I'm becoming more enamored of the idea of using playing cards as a standard feature in my Python pedagogy and andragogy (means teaching adults). Not only do we have the standard deck, but also Tarot which could get us more into text files, string substitution (string.Template) and so forth.
Cards have all the elements Mathematically, a Deck suggests the difference between Cardinality (yes, a silly pun) and Ordinality. You might imagine a deck in which you can't decipher the cards, don't know their "face value", and so have no clear idea of their ranking (ordinality). On the other hand, you know which cards are the same and which are different across multiple decks (le'ts just say), which is the meaning of "cardinality" (difference without any implied ordering). Midhat Gazele dwells on this difference some in his book 'Number'. You might have a set of objects, say stones or wasp specimens, and a way of cataloging them that doesn't implement > or < or even ==. There is only the Python "is" and "is not" for determining of two objects have the same identity or not. License plates on cars, proper names, have this purpose of distinguishing. However, very quickly just about any set beyond a certain size needs an ordering, perhaps simply alphabetical, so that one might flip through a lookup table in a hurry and get to the desired object. People used to use ledgers, thick books, for such cataloging. This is the beginning of data structuring or data structures. The idea of "ordering" (ordinality) is very closely associated with that of cardinality. Anyway, over on Pyfora I was noticing a member suggesting reversing a string might be best accomplished by thestring[::-1], i.e. extended slicing with from the end to the beginning step with a step of -1. However PEP 322 suggests this will be inefficient compared a a built in function introduced in 2.4: reversed. According to the PEP, all reversed needs is for the consumed object to support __getitem__ and __len__. If those two are present, the function will do the rest, and return an iterator object in which the contents of a sequence are iterated over in reverse order. >>> a = 'the rain in spain stays mainly in the plain' >>> ''.join(reversed(a)) 'nialp eht ni ylniam syats niaps ni niar eht' So for our Deck to be reversible by means of this built in function, the only methods we need to implement are these two, __getitem__ and __len__. I do this below, plus make shuffling the deck upon instantiation an option, not de rigueur (not mandatory). This makes it easier to see what reverse order is like. Note that the returned iterable is not itself a Deck, nor is it subscriptable, as the whole point of an iterable is it returns its contents "just in time" as you iterate over it. The cards are not "already present" in reversed order, are simply returned in reverse order. Of course you can force the iterable to dump all its contents by coercing it into a list. I do this as a part of the clone_deck method. Playing Game of War with clone decks, one the reverse of the other, results in a draw if always dealing from the top (now the default, yet still optional). The code below is just my Game of War again, with a few wrinkles. I've upgraded all string printing to use the print(thestring.format(args)) approach, versus the old percent sign string substitution codes. Other small improvements. >>> from sillygame import Deck >>> d = Deck(10) >>> newd = d.clone_deck() >>> newd[0] is d[0] True >>> id(newd[0]) 22884944 >>> id(d[0]) 22884944 >>> d.shuffle() >>> str(d) "['7 of Diamonds', 'Jack of Spades', 'Queen of Clubs', 'King of Spades', '5 of Clubs', '3 of Spades', '6 of Hearts', 'Ace of Clubs', '2 of Hearts', '9 of Spades']" >>> str(newd) "['2 of Hearts', 'Queen of Clubs', '6 of Hearts', '9 of Spades', '5 of Clubs', '7 of Diamonds', 'Ace of Clubs', '3 of Spades', 'Jack of Spades', 'King of Spades']" >>> d[0] Card(Diamonds, ('7', 7)) >>> newd[5] Card(Diamonds, ('7', 7)) >>> d[0] == newd[5] True >>> d[0] is newd[5] True Kirby For further reading: http://www.python.org/dev/peps/pep-0322/ from random import shuffle, randint thesuits = ['Hearts','Diamonds','Clubs','Spades'] theranks = ['Ace'] + [str(v) for v in range(2,11)] + ['Jack','Queen','King'] rank_values = list(zip(theranks, range(1,14))) class Card: def __init__(self, suit, rank_value ): self.suit = suit self.rank = rank_value[0] self.value = rank_value[1] def __lt__(self, other): if self.value < other.value: return True else: return False def __gt__(self, other): if self.value > other.value: return True else: return False def __eq__(self, other): if self.value == other.value: return True else: return False def __repr__(self): return "Card({0}, {1})".format(self.suit, (self.rank, self.value)) def __str__(self): return "{0} of {1}".format(self.rank, self.suit) class Deck: def __init__(self, numcards = 52, shuffle = True): # build a complete deck then slice try: assert 0 < numcards <= 52 except AssertionError: print("Defaulting to 52 cards") numcards = 52 self.numcards = numcards self.cards = [Card(suit, rank_value) for suit in thesuits for rank_value in rank_values ] if shuffle: self.shuffle() self.cards = self.cards[ : self.numcards] def __getitem__(self, index): return self.cards[index] def shuffle(self): shuffle(self.cards) def spit_card(self, top=True): try: assert self.numcards > 0 except AssertionError: raise Exception("Out of cards!") if top: some_card = self.cards.pop(0) else: some_card = self.cards.pop( randint( 0, self.numcards - 1 )) self.numcards = len(self.cards) return some_card def clone_deck(self, reverse=False): newdeck = Deck(numcards=1) newdeck.numcards = self.numcards if reverse: newdeck.cards = list(reversed(self.cards)) else: newdeck.cards = self.cards[:] return newdeck def __repr__(self): return "Deck({0})".format(self.numcards) def __str__(self): return str([str(card) for card in self.cards]) def __len__(self): return len(self.cards) def test(): thedeck = Deck() print (str(thedeck)) def game_of_war(): deckA = Deck(10) # deckB = Deck(10) deckB = deckA.clone_deck(reverse=True) # play a reversed clone PlayerA_score = 0 PlayerB_score = 0 try: assert deckA.numcards == deckB.numcards except AssertionError: raise Exception("Decks don't have same number of cards") for i in range(deckA.numcards): playerA_card = deckA.spit_card(top=False) # deal from anywhere playerB_card = deckB.spit_card(top=False) if playerA_card > playerB_card: PlayerA_score += 1 print("A's {0} beats B's {1}".format(playerA_card, playerB_card)) if playerA_card < playerB_card: PlayerB_score += 1 print("B's {0} beats A's {1}".format(playerB_card, playerA_card)) if playerA_card == playerB_card: print("B's {0} matches A's {1}".format(playerB_card, playerA_card)) if PlayerA_score > PlayerB_score: print("Game Over: A wins") if PlayerA_score < PlayerB_score: print("Game Over: B wins") if PlayerA_score == PlayerB_score: print("Game Over: it's a draw!") if __name__ == '__main__': # test() game_of_war() _______________________________________________ Edu-sig mailing list Edu-sig@python.org http://mail.python.org/mailman/listinfo/edu-sig