| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | #! /usr/bin/env python | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """Solitaire game, much like the one that comes with MS Windows.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Limitations: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | - No cute graphical images for the playing cards faces or backs. | 
					
						
							|  |  |  | - No scoring or timer. | 
					
						
							|  |  |  | - No undo. | 
					
						
							|  |  |  | - No option to turn 3 cards at a time. | 
					
						
							|  |  |  | - No keyboard shortcuts. | 
					
						
							|  |  |  | - Less fancy animation when you win. | 
					
						
							|  |  |  | - The determination of which stack you drag to is more relaxed. | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  | Apology: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | I'm not much of a card player, so my terminology in these comments may | 
					
						
							|  |  |  | at times be a little unusual.  If you have suggestions, please let me | 
					
						
							|  |  |  | know! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Imports | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import math | 
					
						
							|  |  |  | import random | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from Tkinter import * | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | from Canvas import Rectangle, CanvasText, Group, Window | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Fix a bug in Canvas.Group as distributed in Python 1.4.  The | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | # distributed bind() method is broken.  Rather than asking you to fix | 
					
						
							|  |  |  | # the source, we fix it here by deriving a subclass: | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Group(Group): | 
					
						
							|  |  |  |     def bind(self, sequence=None, command=None): | 
					
						
							|  |  |  | 	return self.canvas.tag_bind(self.id, sequence, command) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Constants determining the size and lay-out of cards and stacks.  We | 
					
						
							|  |  |  | # work in a "grid" where each card/stack is surrounded by MARGIN | 
					
						
							|  |  |  | # pixels of space on each side, so adjacent stacks are separated by | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | # 2*MARGIN pixels.  OFFSET is the offset used for displaying the | 
					
						
							|  |  |  | # face down cards in the row stacks. | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | CARDWIDTH = 100 | 
					
						
							|  |  |  | CARDHEIGHT = 150 | 
					
						
							|  |  |  | MARGIN = 10 | 
					
						
							|  |  |  | XSPACING = CARDWIDTH + 2*MARGIN | 
					
						
							|  |  |  | YSPACING = CARDHEIGHT + 4*MARGIN | 
					
						
							|  |  |  | OFFSET = 5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # The background color, green to look like a playing table.  The | 
					
						
							|  |  |  | # standard green is way too bright, and dark green is way to dark, so | 
					
						
							|  |  |  | # we use something in between.  (There are a few more colors that | 
					
						
							|  |  |  | # could be customized, but they are less controversial.) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | BACKGROUND = '#070' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Suits and colors.  The values of the symbolic suit names are the | 
					
						
							|  |  |  | # strings used to display them (you change these and VALNAMES to | 
					
						
							|  |  |  | # internationalize the game).  The COLOR dictionary maps suit names to | 
					
						
							|  |  |  | # colors (red and black) which must be Tk color names.  The keys() of | 
					
						
							|  |  |  | # the COLOR dictionary conveniently provides us with a list of all | 
					
						
							|  |  |  | # suits (in arbitrary order). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | HEARTS = 'Heart' | 
					
						
							|  |  |  | DIAMONDS = 'Diamond' | 
					
						
							|  |  |  | CLUBS = 'Club' | 
					
						
							|  |  |  | SPADES = 'Spade' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | RED = 'red' | 
					
						
							|  |  |  | BLACK = 'black' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | COLOR = {} | 
					
						
							|  |  |  | for s in (HEARTS, DIAMONDS): | 
					
						
							|  |  |  |     COLOR[s] = RED | 
					
						
							|  |  |  | for s in (CLUBS, SPADES): | 
					
						
							|  |  |  |     COLOR[s] = BLACK | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ALLSUITS = COLOR.keys() | 
					
						
							|  |  |  | NSUITS = len(ALLSUITS) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | # Card values are 1-13.  We also define symbolic names for the picture | 
					
						
							|  |  |  | # cards.  ALLVALUES is a list of all card values. | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ACE = 1 | 
					
						
							|  |  |  | JACK = 11 | 
					
						
							|  |  |  | QUEEN = 12 | 
					
						
							|  |  |  | KING = 13 | 
					
						
							|  |  |  | ALLVALUES = range(1, 14) # (one more than the highest value) | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | NVALUES = len(ALLVALUES) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # VALNAMES is a list that maps a card value to string.  It contains a | 
					
						
							|  |  |  | # dummy element at index 0 so it can be indexed directly with the card | 
					
						
							|  |  |  | # value. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | VALNAMES = ["", "A"] + map(str, range(2, 11)) + ["J", "Q", "K"] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Solitaire constants.  The only one I can think of is the number of | 
					
						
							|  |  |  | # row stacks. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | NROWS = 7 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | # The rest of the program consists of class definitions.  These are | 
					
						
							|  |  |  | # further described in their documentation strings. | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Card: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """A playing card.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     A card doesn't record to which stack it belongs; only the stack | 
					
						
							|  |  |  |     records this (it turns out that we always know this from the | 
					
						
							|  |  |  |     context, and this saves a ``double update'' with potential for | 
					
						
							|  |  |  |     inconsistencies). | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  |     Public methods: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     moveto(x, y) -- move the card to an absolute position | 
					
						
							|  |  |  |     moveby(dx, dy) -- move the card by a relative offset | 
					
						
							|  |  |  |     tkraise() -- raise the card to the top of its stack | 
					
						
							|  |  |  |     showface(), showback() -- turn the card face up or down & raise it | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     Public read-only instance variables: | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     suit, value, color -- the card's suit, value and color | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  |     face_shown -- true when the card is shown face up, else false | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     Semi-public read-only instance variables (XXX should be made | 
					
						
							|  |  |  |     private): | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  |      | 
					
						
							|  |  |  |     group -- the Canvas.Group representing the card | 
					
						
							|  |  |  |     x, y -- the position of the card's top left corner | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Private instance variables: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     __back, __rect, __text -- the canvas items making up the card | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     (To show the card face up, the text item is placed in front of | 
					
						
							|  |  |  |     rect and the back is placed behind it.  To show it face down, this | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     is reversed.  The card is created face down.) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def __init__(self, suit, value, canvas): | 
					
						
							|  |  |  | 	"""Card constructor.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Arguments are the card's suit and value, and the canvas widget. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	The card is created at position (0, 0), with its face down | 
					
						
							|  |  |  | 	(adding it to a stack will position it according to that | 
					
						
							|  |  |  | 	stack's rules). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"""
 | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	self.suit = suit | 
					
						
							|  |  |  | 	self.value = value | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	self.color = COLOR[suit] | 
					
						
							|  |  |  | 	self.face_shown = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	self.x = self.y = 0 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	self.group = Group(canvas) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	text = "%s  %s" % (VALNAMES[value], suit) | 
					
						
							|  |  |  | 	self.__text = CanvasText(canvas, CARDWIDTH/2, 0, | 
					
						
							|  |  |  | 			       anchor=N, fill=self.color, text=text) | 
					
						
							|  |  |  | 	self.group.addtag_withtag(self.__text) | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	self.__rect = Rectangle(canvas, 0, 0, CARDWIDTH, CARDHEIGHT, | 
					
						
							|  |  |  | 			      outline='black', fill='white') | 
					
						
							|  |  |  | 	self.group.addtag_withtag(self.__rect) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self.__back = Rectangle(canvas, MARGIN, MARGIN, | 
					
						
							|  |  |  | 			      CARDWIDTH-MARGIN, CARDHEIGHT-MARGIN, | 
					
						
							|  |  |  | 			      outline='black', fill='blue') | 
					
						
							|  |  |  | 	self.group.addtag_withtag(self.__back) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	"""Return a string for debug print statements.""" | 
					
						
							|  |  |  | 	return "Card(%s, %s)" % (`self.suit`, `self.value`) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def moveto(self, x, y): | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	"""Move the card to absolute position (x, y).""" | 
					
						
							|  |  |  | 	self.moveby(x - self.x, y - self.y) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def moveby(self, dx, dy): | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	"""Move the card by (dx, dy).""" | 
					
						
							|  |  |  | 	self.x = self.x + dx | 
					
						
							|  |  |  | 	self.y = self.y + dy | 
					
						
							|  |  |  | 	self.group.move(dx, dy) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def tkraise(self): | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	"""Raise the card above all other objects in its canvas.""" | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	self.group.tkraise() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def showface(self): | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	"""Turn the card's face up.""" | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	self.tkraise() | 
					
						
							|  |  |  | 	self.__rect.tkraise() | 
					
						
							|  |  |  | 	self.__text.tkraise() | 
					
						
							|  |  |  | 	self.face_shown = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def showback(self): | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	"""Turn the card's face down.""" | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	self.tkraise() | 
					
						
							|  |  |  | 	self.__rect.tkraise() | 
					
						
							|  |  |  | 	self.__back.tkraise() | 
					
						
							|  |  |  | 	self.face_shown = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | class Stack: | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     """A generic stack of cards.
 | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     This is used as a base class for all other stacks (e.g. the deck, | 
					
						
							|  |  |  |     the suit stacks, and the row stacks). | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     Public methods: | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     add(card) -- add a card to the stack | 
					
						
							|  |  |  |     delete(card) -- delete a card from the stack | 
					
						
							|  |  |  |     showtop() -- show the top card (if any) face up | 
					
						
							|  |  |  |     deal() -- delete and return the top card, or None if empty | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     Method that subclasses may override: | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     position(card) -- move the card to its proper (x, y) position | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |         The default position() method places all cards at the stack's | 
					
						
							|  |  |  |         own (x, y) position. | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     userclickhandler(), userdoubleclickhandler() -- called to do | 
					
						
							|  |  |  |     subclass specific things on single and double clicks | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |         The default user (single) click handler shows the top card | 
					
						
							|  |  |  |         face up.  The default user double click handler calls the user | 
					
						
							|  |  |  | 	single click handler. | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     usermovehandler(cards) -- called to complete a subpile move | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |         The default user move handler moves all moved cards back to | 
					
						
							|  |  |  |         their original position (by calling the position() method). | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     Private methods: | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     clickhandler(event), doubleclickhandler(event), | 
					
						
							|  |  |  |     motionhandler(event), releasehandler(event) -- event handlers | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |         The default event handlers turn the top card of the stack with | 
					
						
							|  |  |  |         its face up on a (single or double) click, and also support | 
					
						
							|  |  |  |         moving a subpile around. | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     startmoving(event) -- begin a move operation | 
					
						
							|  |  |  |     finishmoving() -- finish a move operation | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, x, y, game=None): | 
					
						
							|  |  |  | 	"""Stack constructor.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Arguments are the stack's nominal x and y position (the top | 
					
						
							|  |  |  | 	left corner of the first card placed in the stack), and the | 
					
						
							|  |  |  | 	game object (which is used to get the canvas; subclasses use | 
					
						
							|  |  |  | 	the game object to find other stacks). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"""
 | 
					
						
							|  |  |  | 	self.x = x | 
					
						
							|  |  |  | 	self.y = y | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	self.game = game | 
					
						
							|  |  |  | 	self.cards = [] | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	self.group = Group(self.game.canvas) | 
					
						
							|  |  |  | 	self.group.bind('<1>', self.clickhandler) | 
					
						
							|  |  |  |  	self.group.bind('<Double-1>', self.doubleclickhandler) | 
					
						
							|  |  |  | 	self.group.bind('<B1-Motion>', self.motionhandler) | 
					
						
							|  |  |  | 	self.group.bind('<ButtonRelease-1>', self.releasehandler) | 
					
						
							|  |  |  | 	self.makebottom() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def makebottom(self): | 
					
						
							|  |  |  | 	pass | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def __repr__(self): | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	"""Return a string for debug print statements.""" | 
					
						
							|  |  |  | 	return "%s(%d, %d)" % (self.__class__.__name__, self.x, self.y) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     # Public methods | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def add(self, card): | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	self.cards.append(card) | 
					
						
							|  |  |  | 	card.tkraise() | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	self.position(card) | 
					
						
							|  |  |  | 	self.group.addtag_withtag(card.group) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def delete(self, card): | 
					
						
							|  |  |  | 	self.cards.remove(card) | 
					
						
							|  |  |  | 	card.group.dtag(self.group) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def showtop(self): | 
					
						
							|  |  |  | 	if self.cards: | 
					
						
							|  |  |  | 	    self.cards[-1].showface() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def deal(self): | 
					
						
							|  |  |  | 	if not self.cards: | 
					
						
							|  |  |  | 	    return None | 
					
						
							|  |  |  | 	card = self.cards[-1] | 
					
						
							|  |  |  | 	self.delete(card) | 
					
						
							|  |  |  | 	return card | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     # Subclass overridable methods | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def position(self, card): | 
					
						
							|  |  |  | 	card.moveto(self.x, self.y) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def userclickhandler(self): | 
					
						
							|  |  |  | 	self.showtop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def userdoubleclickhandler(self): | 
					
						
							|  |  |  | 	self.userclickhandler() | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def usermovehandler(self, cards): | 
					
						
							|  |  |  | 	for card in cards: | 
					
						
							|  |  |  | 	    self.position(card) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     # Event handlers | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def clickhandler(self, event): | 
					
						
							|  |  |  | 	self.finishmoving()		# In case we lost an event | 
					
						
							|  |  |  | 	self.userclickhandler() | 
					
						
							|  |  |  | 	self.startmoving(event) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def motionhandler(self, event): | 
					
						
							|  |  |  | 	self.keepmoving(event) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def releasehandler(self, event): | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	self.keepmoving(event) | 
					
						
							|  |  |  | 	self.finishmoving() | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def doubleclickhandler(self, event): | 
					
						
							|  |  |  | 	self.finishmoving()		# In case we lost an event | 
					
						
							|  |  |  | 	self.userdoubleclickhandler() | 
					
						
							|  |  |  | 	self.startmoving(event) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     # Move internals | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     moving = None | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def startmoving(self, event): | 
					
						
							|  |  |  | 	self.moving = None | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	tags = self.game.canvas.gettags('current') | 
					
						
							|  |  |  | 	for i in range(len(self.cards)): | 
					
						
							|  |  |  | 	    card = self.cards[i] | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	    if card.group.tag in tags: | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 		break | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 	    return | 
					
						
							|  |  |  | 	if not card.face_shown: | 
					
						
							|  |  |  | 	    return | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	self.moving = self.cards[i:] | 
					
						
							|  |  |  | 	self.lastx = event.x | 
					
						
							|  |  |  | 	self.lasty = event.y | 
					
						
							|  |  |  | 	for card in self.moving: | 
					
						
							|  |  |  | 	    card.tkraise() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def keepmoving(self, event): | 
					
						
							|  |  |  | 	if not self.moving: | 
					
						
							|  |  |  | 	    return | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	dx = event.x - self.lastx | 
					
						
							|  |  |  | 	dy = event.y - self.lasty | 
					
						
							|  |  |  | 	self.lastx = event.x | 
					
						
							|  |  |  | 	self.lasty = event.y | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	if dx or dy: | 
					
						
							|  |  |  | 	    for card in self.moving: | 
					
						
							|  |  |  | 		card.moveby(dx, dy) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def finishmoving(self): | 
					
						
							|  |  |  | 	cards = self.moving | 
					
						
							|  |  |  | 	self.moving = None | 
					
						
							|  |  |  | 	if cards: | 
					
						
							|  |  |  | 	    self.usermovehandler(cards) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Deck(Stack): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """The deck is a stack with support for shuffling.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     New methods: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fill() -- create the playing cards | 
					
						
							|  |  |  |     shuffle() -- shuffle the playing cards | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     A single click moves the top card to the game's open deck and | 
					
						
							|  |  |  |     moves it face up; if we're out of cards, it moves the open deck | 
					
						
							|  |  |  |     back to the deck. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def makebottom(self): | 
					
						
							|  |  |  | 	bottom = Rectangle(self.game.canvas, | 
					
						
							|  |  |  | 			   self.x, self.y, | 
					
						
							|  |  |  | 			   self.x+CARDWIDTH, self.y+CARDHEIGHT, | 
					
						
							|  |  |  | 			   outline='black', fill=BACKGROUND) | 
					
						
							|  |  |  |  	self.group.addtag_withtag(bottom) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def fill(self): | 
					
						
							|  |  |  | 	for suit in ALLSUITS: | 
					
						
							|  |  |  | 	    for value in ALLVALUES: | 
					
						
							|  |  |  | 		self.add(Card(suit, value, self.game.canvas)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def shuffle(self): | 
					
						
							|  |  |  | 	n = len(self.cards) | 
					
						
							|  |  |  | 	newcards = [] | 
					
						
							|  |  |  | 	for i in randperm(n): | 
					
						
							|  |  |  | 	    newcards.append(self.cards[i]) | 
					
						
							|  |  |  | 	self.cards = newcards | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def userclickhandler(self): | 
					
						
							|  |  |  | 	opendeck = self.game.opendeck | 
					
						
							|  |  |  | 	card = self.deal() | 
					
						
							|  |  |  | 	if not card: | 
					
						
							|  |  |  | 	    while 1: | 
					
						
							|  |  |  | 		card = opendeck.deal() | 
					
						
							|  |  |  | 		if not card: | 
					
						
							|  |  |  | 		    break | 
					
						
							|  |  |  | 		self.add(card) | 
					
						
							|  |  |  | 		card.showback() | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 	    self.game.opendeck.add(card) | 
					
						
							|  |  |  | 	    card.showface() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def randperm(n): | 
					
						
							|  |  |  |     """Function returning a random permutation of range(n).""" | 
					
						
							|  |  |  |     r = range(n) | 
					
						
							|  |  |  |     x = [] | 
					
						
							|  |  |  |     while r: | 
					
						
							|  |  |  | 	i = random.choice(r) | 
					
						
							|  |  |  | 	x.append(i) | 
					
						
							|  |  |  | 	r.remove(i) | 
					
						
							|  |  |  |     return x | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class OpenStack(Stack): | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:37:07 +00:00
										 |  |  |     def acceptable(self, cards): | 
					
						
							|  |  |  | 	return 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def usermovehandler(self, cards): | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	card = cards[0] | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	stack = self.game.closeststack(card) | 
					
						
							|  |  |  | 	if not stack or stack is self or not stack.acceptable(cards): | 
					
						
							|  |  |  | 	    Stack.usermovehandler(self, cards) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	else: | 
					
						
							|  |  |  | 	    for card in cards: | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 		self.delete(card) | 
					
						
							|  |  |  | 		stack.add(card) | 
					
						
							|  |  |  | 	    self.game.wincheck() | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def userdoubleclickhandler(self): | 
					
						
							|  |  |  | 	if not self.cards: | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	    return | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	card = self.cards[-1] | 
					
						
							|  |  |  | 	if not card.face_shown: | 
					
						
							|  |  |  | 	    self.userclickhandler() | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	    return | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	for s in self.game.suits: | 
					
						
							|  |  |  | 	    if s.acceptable([card]): | 
					
						
							|  |  |  | 		self.delete(card) | 
					
						
							|  |  |  | 		s.add(card) | 
					
						
							|  |  |  | 		self.game.wincheck() | 
					
						
							|  |  |  | 		break | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | class SuitStack(OpenStack): | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def makebottom(self): | 
					
						
							|  |  |  | 	bottom = Rectangle(self.game.canvas, | 
					
						
							|  |  |  | 			   self.x, self.y, | 
					
						
							|  |  |  | 			   self.x+CARDWIDTH, self.y+CARDHEIGHT, | 
					
						
							|  |  |  | 			   outline='black', fill='') | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def userclickhandler(self): | 
					
						
							|  |  |  | 	pass | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  |     def userdoubleclickhandler(self): | 
					
						
							|  |  |  | 	pass | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def acceptable(self, cards): | 
					
						
							|  |  |  | 	if len(cards) != 1: | 
					
						
							|  |  |  | 	    return 0 | 
					
						
							|  |  |  | 	card = cards[0] | 
					
						
							|  |  |  | 	if not self.cards: | 
					
						
							|  |  |  | 	    return card.value == ACE | 
					
						
							|  |  |  | 	topcard = self.cards[-1] | 
					
						
							|  |  |  | 	return card.suit == topcard.suit and card.value == topcard.value + 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | class RowStack(OpenStack): | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def acceptable(self, cards): | 
					
						
							|  |  |  | 	card = cards[0] | 
					
						
							|  |  |  | 	if not self.cards: | 
					
						
							|  |  |  | 	    return card.value == KING | 
					
						
							|  |  |  | 	topcard = self.cards[-1] | 
					
						
							|  |  |  | 	if not topcard.face_shown: | 
					
						
							|  |  |  | 	    return 0 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	return card.color != topcard.color and card.value == topcard.value - 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def position(self, card): | 
					
						
							|  |  |  | 	y = self.y | 
					
						
							|  |  |  | 	for c in self.cards: | 
					
						
							|  |  |  | 	    if c == card: | 
					
						
							|  |  |  | 		break | 
					
						
							|  |  |  | 	    if c.face_shown: | 
					
						
							|  |  |  | 		y = y + 2*MARGIN | 
					
						
							|  |  |  | 	    else: | 
					
						
							|  |  |  | 		y = y + OFFSET | 
					
						
							|  |  |  | 	card.moveto(self.x, y) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class Solitaire: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def __init__(self, master): | 
					
						
							|  |  |  | 	self.master = master | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	self.canvas = Canvas(self.master, | 
					
						
							|  |  |  | 			     background=BACKGROUND, | 
					
						
							|  |  |  | 			     highlightthickness=0, | 
					
						
							|  |  |  | 			     width=NROWS*XSPACING, | 
					
						
							|  |  |  | 			     height=3*YSPACING + 20 + MARGIN) | 
					
						
							|  |  |  | 	self.canvas.pack(fill=BOTH, expand=TRUE) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	self.dealbutton = Button(self.canvas, | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 				 text="Deal", | 
					
						
							|  |  |  | 				 highlightthickness=0, | 
					
						
							|  |  |  | 				 background=BACKGROUND, | 
					
						
							|  |  |  | 				 activebackground="green", | 
					
						
							|  |  |  | 				 command=self.deal) | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	Window(self.canvas, MARGIN, 3*YSPACING + 20, | 
					
						
							|  |  |  | 	       window=self.dealbutton, anchor=SW) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	x = MARGIN | 
					
						
							|  |  |  | 	y = MARGIN | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	self.deck = Deck(x, y, self) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	x = x + XSPACING | 
					
						
							|  |  |  | 	self.opendeck = OpenStack(x, y, self) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	x = x + XSPACING | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	self.suits = [] | 
					
						
							|  |  |  | 	for i in range(NSUITS): | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	    x = x + XSPACING | 
					
						
							|  |  |  | 	    self.suits.append(SuitStack(x, y, self)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	x = MARGIN | 
					
						
							|  |  |  | 	y = y + YSPACING | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	self.rows = [] | 
					
						
							|  |  |  | 	for i in range(NROWS): | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	    self.rows.append(RowStack(x, y, self)) | 
					
						
							|  |  |  | 	    x = x + XSPACING | 
					
						
							| 
									
										
										
										
											1996-12-30 02:37:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	self.openstacks = [self.opendeck] + self.suits + self.rows | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	self.deck.fill() | 
					
						
							|  |  |  | 	self.deal() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def wincheck(self): | 
					
						
							|  |  |  | 	for s in self.suits: | 
					
						
							|  |  |  | 	    if len(s.cards) != NVALUES: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	self.win() | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	self.deal() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def win(self): | 
					
						
							|  |  |  | 	"""Stupid animation when you win.""" | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	cards = [] | 
					
						
							| 
									
										
										
										
											1996-12-30 16:45:14 +00:00
										 |  |  | 	for s in self.openstacks: | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 	    cards = cards + s.cards | 
					
						
							| 
									
										
										
										
											1996-12-30 16:45:14 +00:00
										 |  |  | 	while cards: | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	    card = random.choice(cards) | 
					
						
							| 
									
										
										
										
											1996-12-30 16:45:14 +00:00
										 |  |  | 	    cards.remove(card) | 
					
						
							|  |  |  | 	    self.animatedmoveto(card, self.deck) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def animatedmoveto(self, card, dest): | 
					
						
							|  |  |  | 	for i in range(10, 0, -1): | 
					
						
							|  |  |  | 	    dx, dy = (dest.x-card.x)/i, (dest.y-card.y)/i | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	    card.moveby(dx, dy) | 
					
						
							|  |  |  | 	    self.master.update_idletasks() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def closeststack(self, card): | 
					
						
							|  |  |  | 	closest = None | 
					
						
							|  |  |  | 	cdist = 999999999 | 
					
						
							|  |  |  | 	# Since we only compare distances, | 
					
						
							|  |  |  | 	# we don't bother to take the square root. | 
					
						
							| 
									
										
										
										
											1996-12-30 02:37:07 +00:00
										 |  |  | 	for stack in self.openstacks: | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	    dist = (stack.x - card.x)**2 + (stack.y - card.y)**2 | 
					
						
							|  |  |  | 	    if dist < cdist: | 
					
						
							|  |  |  | 		closest = stack | 
					
						
							|  |  |  | 		cdist = dist | 
					
						
							|  |  |  | 	return closest | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def deal(self): | 
					
						
							|  |  |  | 	self.reset() | 
					
						
							|  |  |  | 	self.deck.shuffle() | 
					
						
							|  |  |  | 	for i in range(NROWS): | 
					
						
							|  |  |  | 	    for r in self.rows[i:]: | 
					
						
							|  |  |  | 		card = self.deck.deal() | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 		r.add(card) | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	for r in self.rows: | 
					
						
							|  |  |  | 	    r.showtop() | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def reset(self): | 
					
						
							| 
									
										
										
										
											1996-12-30 02:37:07 +00:00
										 |  |  | 	for stack in self.openstacks: | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 	    while 1: | 
					
						
							| 
									
										
										
										
											1996-12-30 02:20:29 +00:00
										 |  |  | 		card = stack.deal() | 
					
						
							|  |  |  | 		if not card: | 
					
						
							|  |  |  | 		    break | 
					
						
							|  |  |  | 		self.deck.add(card) | 
					
						
							|  |  |  | 		card.showback() | 
					
						
							| 
									
										
										
										
											1996-12-29 20:15:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Main function, run when invoked as a stand-alone Python program. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def main(): | 
					
						
							|  |  |  |     root = Tk() | 
					
						
							|  |  |  |     game = Solitaire(root) | 
					
						
							|  |  |  |     root.protocol('WM_DELETE_WINDOW', root.quit) | 
					
						
							|  |  |  |     root.mainloop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     main() |