Lecture 22 Class and Methods III

1. Card objects
There are fifty-two cards in a deck, each of which belongs to one of four suits and one of thirteen ranks. The suits are Spades, Hearts, Diamonds, and Clubs (in descending order in bridge). The ranks are Ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, Jack, Queen, and King. Depending on the game that you are playing, an Ace may be higher than King or lower than 2.

If we want to define a new object to represent a playing card, it is obvious what the attributes should be: rank and suit. It is not as obvious what type the attributes should be. One possibility is to use strings containing words like 'Spade' for suits and 'Queen' for ranks. One problem with this implementation is that it would not be easy to compare cards to see which had a higher rank or suit.

An alternative is to use integers to encode the ranks and suits. In this context, “encode” means that we are going to define a mapping between numbers and suits, or between numbers and ranks. This kind of encoding is not meant to be a secret (that would be “encryption”).

For example, this table shows the suits and the corresponding integer codes:

This code makes it easy to compare cards; because higher suits map to higher numbers, we can compare suits by comparing their codes. The mapping for ranks is fairly obvious; each of the numerical ranks maps to the corresponding integer, and for face cards:

The Object diagram:

As usual, the init method takes an optional parameter for each attribute. The default card is the 2 of Clubs. To create a Card, you call Card with the suit and rank of the card you want.

In order to print Card objects in a way that people can easily read, we need a mapping from the integer codes to the corresponding ranks and suits. A natural way to do that is with lists of strings. We assign these lists to class attributes:

Or you can do it in this way: Please make sure you understand the differences between the one below and the one above:

If I change the arguments in the 'Card()' class call, I can have different results:

** WHY the 'print(cardie)' function can print out the results in a certain format? The reason is the 'print()' function will call the '__str__()' function automatically behind the scene.

2. Comparing cards
For built-in types, there are relational operators (<, >, ==, etc.) that compare values and determine when one is greater than, less than, or equal to another. For programmer-defined types, we can override the behavior of the built-in operators by providing a method named __lt__, which stands for “less than”. __lt__ takes two parameters, self and other, and returns True if self is strictly less than other.

The correct ordering for cards is not obvious. For example, which is better, the 3 of Clubs or the 2 of Diamonds? One has a higher rank, but the other has a higher suit. In order to compare cards, you have to decide whether rank or suit is more important. The answer might depend on what game you are playing, but to keep things simple, we’ll make the arbitrary choice that suit is more important, so all of the Spades outrank all of the Diamonds, and so on.

3. Decks and printing the deck

We know that there are 4 suits and 13 ranks. To printing out the deck, we need to create a list of 'index pairs' to extract all the combination of Suits&Pairs. Let's start with a small program. Let's create the index list first:
I used a nested 'for loop' to create these combinations.

Now we need these indices to extract all the real card names from the list:

you can use the join method on your delimiter, '\n':
Join many string with a new line between them:

"\n".join(...)

If we comment the '__str__()' function, the printed results will not be aligned in a single column: