blob: 4c1bb788df85c7db347b0374062fb665cb4e77a8 [file] [log] [blame]
Guido van Rossum8de9f891996-12-29 20:15:32 +00001#! /usr/bin/env python
2
3"""Solitaire game, much like the one that comes with MS Windows.
4
5Limitations:
6
7- No cute graphical images for the playing cards faces or backs.
8- No scoring or timer.
9- No undo.
10- No option to turn 3 cards at a time.
11- No keyboard shortcuts.
12- Less fancy animation when you win.
13- The determination of which stack you drag to is more relaxed.
Guido van Rossum8de9f891996-12-29 20:15:32 +000014
15Apology:
16
17I'm not much of a card player, so my terminology in these comments may
18at times be a little unusual. If you have suggestions, please let me
19know!
20
21"""
22
23# Imports
24
25import math
26import random
27
28from Tkinter import *
Guido van Rossum1b2b53a1996-12-30 02:20:29 +000029from Canvas import Rectangle, CanvasText, Group, Window
Guido van Rossum8de9f891996-12-29 20:15:32 +000030
31
32# Fix a bug in Canvas.Group as distributed in Python 1.4. The
Guido van Rossum1b2b53a1996-12-30 02:20:29 +000033# distributed bind() method is broken. Rather than asking you to fix
34# the source, we fix it here by deriving a subclass:
Guido van Rossum8de9f891996-12-29 20:15:32 +000035
36class Group(Group):
37 def bind(self, sequence=None, command=None):
38 return self.canvas.tag_bind(self.id, sequence, command)
39
40
41# Constants determining the size and lay-out of cards and stacks. We
42# work in a "grid" where each card/stack is surrounded by MARGIN
43# pixels of space on each side, so adjacent stacks are separated by
Guido van Rossum1b2b53a1996-12-30 02:20:29 +000044# 2*MARGIN pixels. OFFSET is the offset used for displaying the
45# face down cards in the row stacks.
Guido van Rossum8de9f891996-12-29 20:15:32 +000046
47CARDWIDTH = 100
48CARDHEIGHT = 150
49MARGIN = 10
50XSPACING = CARDWIDTH + 2*MARGIN
51YSPACING = CARDHEIGHT + 4*MARGIN
52OFFSET = 5
53
54# The background color, green to look like a playing table. The
55# standard green is way too bright, and dark green is way to dark, so
56# we use something in between. (There are a few more colors that
57# could be customized, but they are less controversial.)
58
59BACKGROUND = '#070'
60
61
62# Suits and colors. The values of the symbolic suit names are the
63# strings used to display them (you change these and VALNAMES to
64# internationalize the game). The COLOR dictionary maps suit names to
65# colors (red and black) which must be Tk color names. The keys() of
66# the COLOR dictionary conveniently provides us with a list of all
67# suits (in arbitrary order).
68
69HEARTS = 'Heart'
70DIAMONDS = 'Diamond'
71CLUBS = 'Club'
72SPADES = 'Spade'
73
74RED = 'red'
75BLACK = 'black'
76
77COLOR = {}
78for s in (HEARTS, DIAMONDS):
79 COLOR[s] = RED
80for s in (CLUBS, SPADES):
81 COLOR[s] = BLACK
82
83ALLSUITS = COLOR.keys()
84NSUITS = len(ALLSUITS)
85
86
Guido van Rossum1b2b53a1996-12-30 02:20:29 +000087# Card values are 1-13. We also define symbolic names for the picture
88# cards. ALLVALUES is a list of all card values.
Guido van Rossum8de9f891996-12-29 20:15:32 +000089
90ACE = 1
91JACK = 11
92QUEEN = 12
93KING = 13
94ALLVALUES = range(1, 14) # (one more than the highest value)
Guido van Rossum1b2b53a1996-12-30 02:20:29 +000095NVALUES = len(ALLVALUES)
Guido van Rossum8de9f891996-12-29 20:15:32 +000096
97
98# VALNAMES is a list that maps a card value to string. It contains a
99# dummy element at index 0 so it can be indexed directly with the card
100# value.
101
102VALNAMES = ["", "A"] + map(str, range(2, 11)) + ["J", "Q", "K"]
103
104
105# Solitaire constants. The only one I can think of is the number of
106# row stacks.
107
108NROWS = 7
109
110
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000111# The rest of the program consists of class definitions. These are
112# further described in their documentation strings.
Guido van Rossum8de9f891996-12-29 20:15:32 +0000113
114
115class Card:
116
117 """A playing card.
118
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000119 A card doesn't record to which stack it belongs; only the stack
120 records this (it turns out that we always know this from the
121 context, and this saves a ``double update'' with potential for
122 inconsistencies).
123
Guido van Rossum8de9f891996-12-29 20:15:32 +0000124 Public methods:
125
126 moveto(x, y) -- move the card to an absolute position
127 moveby(dx, dy) -- move the card by a relative offset
128 tkraise() -- raise the card to the top of its stack
129 showface(), showback() -- turn the card face up or down & raise it
Guido van Rossum8de9f891996-12-29 20:15:32 +0000130
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000131 Public read-only instance variables:
Guido van Rossum8de9f891996-12-29 20:15:32 +0000132
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000133 suit, value, color -- the card's suit, value and color
Guido van Rossum8de9f891996-12-29 20:15:32 +0000134 face_shown -- true when the card is shown face up, else false
135
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000136 Semi-public read-only instance variables (XXX should be made
137 private):
Guido van Rossum8de9f891996-12-29 20:15:32 +0000138
139 group -- the Canvas.Group representing the card
140 x, y -- the position of the card's top left corner
141
142 Private instance variables:
143
144 __back, __rect, __text -- the canvas items making up the card
145
146 (To show the card face up, the text item is placed in front of
147 rect and the back is placed behind it. To show it face down, this
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000148 is reversed. The card is created face down.)
Guido van Rossum8de9f891996-12-29 20:15:32 +0000149
150 """
151
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000152 def __init__(self, suit, value, canvas):
153 """Card constructor.
154
155 Arguments are the card's suit and value, and the canvas widget.
156
157 The card is created at position (0, 0), with its face down
158 (adding it to a stack will position it according to that
159 stack's rules).
160
161 """
Guido van Rossum8de9f891996-12-29 20:15:32 +0000162 self.suit = suit
Guido van Rossum8de9f891996-12-29 20:15:32 +0000163 self.value = value
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000164 self.color = COLOR[suit]
165 self.face_shown = 0
166
Guido van Rossum8de9f891996-12-29 20:15:32 +0000167 self.x = self.y = 0
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000168 self.group = Group(canvas)
169
Guido van Rossum8de9f891996-12-29 20:15:32 +0000170 text = "%s %s" % (VALNAMES[value], suit)
171 self.__text = CanvasText(canvas, CARDWIDTH/2, 0,
172 anchor=N, fill=self.color, text=text)
Guido van Rossum8de9f891996-12-29 20:15:32 +0000173 self.group.addtag_withtag(self.__text)
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000174
175 self.__rect = Rectangle(canvas, 0, 0, CARDWIDTH, CARDHEIGHT,
176 outline='black', fill='white')
177 self.group.addtag_withtag(self.__rect)
178
179 self.__back = Rectangle(canvas, MARGIN, MARGIN,
180 CARDWIDTH-MARGIN, CARDHEIGHT-MARGIN,
181 outline='black', fill='blue')
182 self.group.addtag_withtag(self.__back)
Guido van Rossum8de9f891996-12-29 20:15:32 +0000183
184 def __repr__(self):
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000185 """Return a string for debug print statements."""
186 return "Card(%s, %s)" % (`self.suit`, `self.value`)
Guido van Rossum8de9f891996-12-29 20:15:32 +0000187
188 def moveto(self, x, y):
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000189 """Move the card to absolute position (x, y)."""
190 self.moveby(x - self.x, y - self.y)
Guido van Rossum8de9f891996-12-29 20:15:32 +0000191
192 def moveby(self, dx, dy):
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000193 """Move the card by (dx, dy)."""
194 self.x = self.x + dx
195 self.y = self.y + dy
196 self.group.move(dx, dy)
Guido van Rossum8de9f891996-12-29 20:15:32 +0000197
198 def tkraise(self):
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000199 """Raise the card above all other objects in its canvas."""
Guido van Rossum8de9f891996-12-29 20:15:32 +0000200 self.group.tkraise()
201
202 def showface(self):
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000203 """Turn the card's face up."""
Guido van Rossum8de9f891996-12-29 20:15:32 +0000204 self.tkraise()
205 self.__rect.tkraise()
206 self.__text.tkraise()
207 self.face_shown = 1
208
209 def showback(self):
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000210 """Turn the card's face down."""
Guido van Rossum8de9f891996-12-29 20:15:32 +0000211 self.tkraise()
212 self.__rect.tkraise()
213 self.__back.tkraise()
214 self.face_shown = 0
215
Guido van Rossum8de9f891996-12-29 20:15:32 +0000216
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000217class Stack:
Guido van Rossum8de9f891996-12-29 20:15:32 +0000218
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000219 """A generic stack of cards.
Guido van Rossum8de9f891996-12-29 20:15:32 +0000220
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000221 This is used as a base class for all other stacks (e.g. the deck,
222 the suit stacks, and the row stacks).
Guido van Rossum8de9f891996-12-29 20:15:32 +0000223
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000224 Public methods:
Guido van Rossum8de9f891996-12-29 20:15:32 +0000225
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000226 add(card) -- add a card to the stack
227 delete(card) -- delete a card from the stack
228 showtop() -- show the top card (if any) face up
229 deal() -- delete and return the top card, or None if empty
Guido van Rossum8de9f891996-12-29 20:15:32 +0000230
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000231 Method that subclasses may override:
Guido van Rossum8de9f891996-12-29 20:15:32 +0000232
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000233 position(card) -- move the card to its proper (x, y) position
234
235 The default position() method places all cards at the stack's
236 own (x, y) position.
237
238 userclickhandler(), userdoubleclickhandler() -- called to do
239 subclass specific things on single and double clicks
240
241 The default user (single) click handler shows the top card
242 face up. The default user double click handler calls the user
243 single click handler.
244
245 usermovehandler(cards) -- called to complete a subpile move
246
247 The default user move handler moves all moved cards back to
248 their original position (by calling the position() method).
249
250 Private methods:
251
252 clickhandler(event), doubleclickhandler(event),
253 motionhandler(event), releasehandler(event) -- event handlers
254
255 The default event handlers turn the top card of the stack with
256 its face up on a (single or double) click, and also support
257 moving a subpile around.
258
259 startmoving(event) -- begin a move operation
260 finishmoving() -- finish a move operation
261
262 """
263
264 def __init__(self, x, y, game=None):
265 """Stack constructor.
266
267 Arguments are the stack's nominal x and y position (the top
268 left corner of the first card placed in the stack), and the
269 game object (which is used to get the canvas; subclasses use
270 the game object to find other stacks).
271
272 """
273 self.x = x
274 self.y = y
Guido van Rossum8de9f891996-12-29 20:15:32 +0000275 self.game = game
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000276 self.cards = []
277 self.group = Group(self.game.canvas)
278 self.group.bind('<1>', self.clickhandler)
279 self.group.bind('<Double-1>', self.doubleclickhandler)
280 self.group.bind('<B1-Motion>', self.motionhandler)
281 self.group.bind('<ButtonRelease-1>', self.releasehandler)
282 self.makebottom()
283
284 def makebottom(self):
285 pass
286
287 def __repr__(self):
288 """Return a string for debug print statements."""
289 return "%s(%d, %d)" % (self.__class__.__name__, self.x, self.y)
290
291 # Public methods
292
293 def add(self, card):
294 self.cards.append(card)
295 card.tkraise()
296 self.position(card)
297 self.group.addtag_withtag(card.group)
298
299 def delete(self, card):
300 self.cards.remove(card)
301 card.group.dtag(self.group)
302
303 def showtop(self):
304 if self.cards:
305 self.cards[-1].showface()
306
307 def deal(self):
308 if not self.cards:
309 return None
310 card = self.cards[-1]
311 self.delete(card)
312 return card
313
314 # Subclass overridable methods
315
316 def position(self, card):
317 card.moveto(self.x, self.y)
318
319 def userclickhandler(self):
320 self.showtop()
321
322 def userdoubleclickhandler(self):
323 self.userclickhandler()
324
325 def usermovehandler(self, cards):
326 for card in cards:
327 self.position(card)
328
329 # Event handlers
330
331 def clickhandler(self, event):
332 self.finishmoving() # In case we lost an event
333 self.userclickhandler()
334 self.startmoving(event)
335
336 def motionhandler(self, event):
337 self.keepmoving(event)
338
339 def releasehandler(self, event):
340 self.keepmoving(event)
341 self.finishmoving()
342
343 def doubleclickhandler(self, event):
344 self.finishmoving() # In case we lost an event
345 self.userdoubleclickhandler()
346 self.startmoving(event)
347
348 # Move internals
349
350 moving = None
351
352 def startmoving(self, event):
353 self.moving = None
354 tags = self.game.canvas.gettags('current')
355 for i in range(len(self.cards)):
356 card = self.cards[i]
357 if card.group.tag in tags:
358 break
359 else:
360 return
361 if not card.face_shown:
362 return
363 self.moving = self.cards[i:]
364 self.lastx = event.x
365 self.lasty = event.y
366 for card in self.moving:
367 card.tkraise()
368
369 def keepmoving(self, event):
370 if not self.moving:
371 return
372 dx = event.x - self.lastx
373 dy = event.y - self.lasty
374 self.lastx = event.x
375 self.lasty = event.y
376 if dx or dy:
377 for card in self.moving:
378 card.moveby(dx, dy)
379
380 def finishmoving(self):
381 cards = self.moving
382 self.moving = None
383 if cards:
384 self.usermovehandler(cards)
385
386
387class Deck(Stack):
388
389 """The deck is a stack with support for shuffling.
390
391 New methods:
392
393 fill() -- create the playing cards
394 shuffle() -- shuffle the playing cards
395
396 A single click moves the top card to the game's open deck and
397 moves it face up; if we're out of cards, it moves the open deck
398 back to the deck.
399
400 """
401
402 def makebottom(self):
403 bottom = Rectangle(self.game.canvas,
404 self.x, self.y,
405 self.x+CARDWIDTH, self.y+CARDHEIGHT,
406 outline='black', fill=BACKGROUND)
407 self.group.addtag_withtag(bottom)
408
409 def fill(self):
Guido van Rossum8de9f891996-12-29 20:15:32 +0000410 for suit in ALLSUITS:
411 for value in ALLVALUES:
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000412 self.add(Card(suit, value, self.game.canvas))
Guido van Rossum8de9f891996-12-29 20:15:32 +0000413
414 def shuffle(self):
415 n = len(self.cards)
416 newcards = []
417 for i in randperm(n):
418 newcards.append(self.cards[i])
419 self.cards = newcards
420
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000421 def userclickhandler(self):
422 opendeck = self.game.opendeck
423 card = self.deal()
424 if not card:
425 while 1:
426 card = opendeck.deal()
427 if not card:
428 break
429 self.add(card)
430 card.showback()
431 else:
432 self.game.opendeck.add(card)
433 card.showface()
Guido van Rossum8de9f891996-12-29 20:15:32 +0000434
Guido van Rossum8de9f891996-12-29 20:15:32 +0000435
436def randperm(n):
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000437 """Function returning a random permutation of range(n)."""
Guido van Rossum8de9f891996-12-29 20:15:32 +0000438 r = range(n)
439 x = []
440 while r:
441 i = random.choice(r)
442 x.append(i)
443 r.remove(i)
444 return x
445
Guido van Rossum8de9f891996-12-29 20:15:32 +0000446
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000447class OpenStack(Stack):
Guido van Rossum8de9f891996-12-29 20:15:32 +0000448
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000449 def usermovehandler(self, cards):
450 card = cards[0]
451 stack = self.game.closeststack(card)
452 if not stack or stack is self or not stack.acceptable(cards):
453 Stack.usermovehandler(self, cards)
454 else:
455 for card in cards:
456 self.delete(card)
457 stack.add(card)
458 self.game.wincheck()
Guido van Rossum8de9f891996-12-29 20:15:32 +0000459
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000460 def userdoubleclickhandler(self):
Guido van Rossum8de9f891996-12-29 20:15:32 +0000461 if not self.cards:
462 return
463 card = self.cards[-1]
Guido van Rossum8de9f891996-12-29 20:15:32 +0000464 if not card.face_shown:
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000465 self.userclickhandler()
Guido van Rossum8de9f891996-12-29 20:15:32 +0000466 return
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000467 for s in self.game.suits:
468 if s.acceptable([card]):
469 self.delete(card)
470 s.add(card)
471 self.game.wincheck()
Guido van Rossum8de9f891996-12-29 20:15:32 +0000472 break
Guido van Rossum8de9f891996-12-29 20:15:32 +0000473
Guido van Rossum8de9f891996-12-29 20:15:32 +0000474
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000475class SuitStack(OpenStack):
Guido van Rossum8de9f891996-12-29 20:15:32 +0000476
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000477 def makebottom(self):
478 bottom = Rectangle(self.game.canvas,
479 self.x, self.y,
480 self.x+CARDWIDTH, self.y+CARDHEIGHT,
481 outline='black', fill='')
Guido van Rossum8de9f891996-12-29 20:15:32 +0000482
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000483 def userclickhandler(self):
484 pass
Guido van Rossum8de9f891996-12-29 20:15:32 +0000485
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000486 def userdoubleclickhandler(self):
487 pass
Guido van Rossum8de9f891996-12-29 20:15:32 +0000488
489 def acceptable(self, cards):
490 if len(cards) != 1:
491 return 0
492 card = cards[0]
Guido van Rossum8de9f891996-12-29 20:15:32 +0000493 if not self.cards:
494 return card.value == ACE
495 topcard = self.cards[-1]
Guido van Rossum8de9f891996-12-29 20:15:32 +0000496 return card.suit == topcard.suit and card.value == topcard.value + 1
497
Guido van Rossum8de9f891996-12-29 20:15:32 +0000498
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000499class RowStack(OpenStack):
Guido van Rossum8de9f891996-12-29 20:15:32 +0000500
501 def acceptable(self, cards):
502 card = cards[0]
Guido van Rossum8de9f891996-12-29 20:15:32 +0000503 if not self.cards:
504 return card.value == KING
505 topcard = self.cards[-1]
506 if not topcard.face_shown:
507 return 0
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000508 return card.color != topcard.color and card.value == topcard.value - 1
509
510 def position(self, card):
511 y = self.y
512 for c in self.cards:
513 if c == card:
514 break
515 if c.face_shown:
516 y = y + 2*MARGIN
517 else:
518 y = y + OFFSET
519 card.moveto(self.x, y)
520
Guido van Rossum8de9f891996-12-29 20:15:32 +0000521
522class Solitaire:
523
524 def __init__(self, master):
525 self.master = master
526
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000527 self.canvas = Canvas(self.master,
528 background=BACKGROUND,
529 highlightthickness=0,
530 width=NROWS*XSPACING,
531 height=3*YSPACING + 20 + MARGIN)
532 self.canvas.pack(fill=BOTH, expand=TRUE)
Guido van Rossum8de9f891996-12-29 20:15:32 +0000533
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000534 self.dealbutton = Button(self.canvas,
Guido van Rossum8de9f891996-12-29 20:15:32 +0000535 text="Deal",
536 highlightthickness=0,
537 background=BACKGROUND,
538 activebackground="green",
539 command=self.deal)
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000540 Window(self.canvas, MARGIN, 3*YSPACING + 20,
541 window=self.dealbutton, anchor=SW)
Guido van Rossum8de9f891996-12-29 20:15:32 +0000542
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000543 x = MARGIN
544 y = MARGIN
Guido van Rossum8de9f891996-12-29 20:15:32 +0000545
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000546 self.deck = Deck(x, y, self)
547
548 x = x + XSPACING
549 self.opendeck = OpenStack(x, y, self)
Guido van Rossum8de9f891996-12-29 20:15:32 +0000550
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000551 x = x + XSPACING
Guido van Rossum8de9f891996-12-29 20:15:32 +0000552 self.suits = []
553 for i in range(NSUITS):
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000554 x = x + XSPACING
555 self.suits.append(SuitStack(x, y, self))
556
557 x = MARGIN
558 y = y + YSPACING
Guido van Rossum8de9f891996-12-29 20:15:32 +0000559
560 self.rows = []
561 for i in range(NROWS):
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000562 self.rows.append(RowStack(x, y, self))
563 x = x + XSPACING
Guido van Rossum8de9f891996-12-29 20:15:32 +0000564
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000565 self.deck.fill()
566 self.deal()
567
568 def wincheck(self):
569 for s in self.suits:
570 if len(s.cards) != NVALUES:
571 return
572 self.win()
Guido van Rossum8de9f891996-12-29 20:15:32 +0000573 self.deal()
574
575 def win(self):
576 """Stupid animation when you win."""
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000577 cards = []
578 for s in self.suits:
579 cards = cards + s.cards
580 if not cards:
581 return
Guido van Rossum8de9f891996-12-29 20:15:32 +0000582 for i in range(1000):
583 card = random.choice(cards)
584 dx = random.randint(-50, 50)
585 dy = random.randint(-50, 50)
586 card.moveby(dx, dy)
587 self.master.update_idletasks()
588
589 def closeststack(self, card):
590 closest = None
591 cdist = 999999999
592 # Since we only compare distances,
593 # we don't bother to take the square root.
594 for stack in self.rows + self.suits:
595 dist = (stack.x - card.x)**2 + (stack.y - card.y)**2
596 if dist < cdist:
597 closest = stack
598 cdist = dist
599 return closest
600
Guido van Rossum8de9f891996-12-29 20:15:32 +0000601 def deal(self):
602 self.reset()
603 self.deck.shuffle()
604 for i in range(NROWS):
605 for r in self.rows[i:]:
606 card = self.deck.deal()
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000607 r.add(card)
Guido van Rossum8de9f891996-12-29 20:15:32 +0000608 for r in self.rows:
609 r.showtop()
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000610
611 def reset(self):
612 for stack in [self.opendeck] + self.suits + self.rows:
Guido van Rossum8de9f891996-12-29 20:15:32 +0000613 while 1:
Guido van Rossum1b2b53a1996-12-30 02:20:29 +0000614 card = stack.deal()
615 if not card:
616 break
617 self.deck.add(card)
618 card.showback()
Guido van Rossum8de9f891996-12-29 20:15:32 +0000619
620
621# Main function, run when invoked as a stand-alone Python program.
622
623def main():
624 root = Tk()
625 game = Solitaire(root)
626 root.protocol('WM_DELETE_WINDOW', root.quit)
627 root.mainloop()
628
629if __name__ == '__main__':
630 main()