diff options
author | cinap_lenrek <cinap_lenrek@localhost> | 2011-05-03 15:16:20 +0000 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@localhost> | 2011-05-03 15:16:20 +0000 |
commit | 5976fdfe42ecdee07df0621d9323c2790b23eb5d (patch) | |
tree | e399aa4b8bb7c6d5d2eb8267cf9a2904370a046a /sys/src/cmd/python/Demo/tkinter/guido/solitaire.py | |
parent | 1665b57e14f8637569e52f8752cc9dd1672a5cfb (diff) |
remove stuff
Diffstat (limited to 'sys/src/cmd/python/Demo/tkinter/guido/solitaire.py')
-rwxr-xr-x | sys/src/cmd/python/Demo/tkinter/guido/solitaire.py | 637 |
1 files changed, 0 insertions, 637 deletions
diff --git a/sys/src/cmd/python/Demo/tkinter/guido/solitaire.py b/sys/src/cmd/python/Demo/tkinter/guido/solitaire.py deleted file mode 100755 index 50a8b2643..000000000 --- a/sys/src/cmd/python/Demo/tkinter/guido/solitaire.py +++ /dev/null @@ -1,637 +0,0 @@ -#! /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 * -from Canvas import Rectangle, CanvasText, Group, Window - - -# Fix a bug in Canvas.Group as distributed in Python 1.4. The -# distributed bind() method is broken. Rather than asking you to fix -# the source, we fix it here by deriving a subclass: - -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 -# 2*MARGIN pixels. OFFSET is the offset used for displaying the -# face down cards in the row stacks. - -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) - - -# Card values are 1-13. We also define symbolic names for the picture -# cards. ALLVALUES is a list of all card values. - -ACE = 1 -JACK = 11 -QUEEN = 12 -KING = 13 -ALLVALUES = range(1, 14) # (one more than the highest value) -NVALUES = len(ALLVALUES) - - -# 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 - - -# The rest of the program consists of class definitions. These are -# further described in their documentation strings. - - -class Card: - - """A playing card. - - 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). - - 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 - - Public read-only instance variables: - - suit, value, color -- the card's suit, value and color - face_shown -- true when the card is shown face up, else false - - Semi-public read-only instance variables (XXX should be made - private): - - 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 - is reversed. The card is created face down.) - - """ - - 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). - - """ - self.suit = suit - self.value = value - self.color = COLOR[suit] - self.face_shown = 0 - - self.x = self.y = 0 - self.group = Group(canvas) - - 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) - - 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) - - def __repr__(self): - """Return a string for debug print statements.""" - return "Card(%r, %r)" % (self.suit, self.value) - - def moveto(self, x, y): - """Move the card to absolute position (x, y).""" - self.moveby(x - self.x, y - self.y) - - def moveby(self, dx, dy): - """Move the card by (dx, dy).""" - self.x = self.x + dx - self.y = self.y + dy - self.group.move(dx, dy) - - def tkraise(self): - """Raise the card above all other objects in its canvas.""" - self.group.tkraise() - - def showface(self): - """Turn the card's face up.""" - self.tkraise() - self.__rect.tkraise() - self.__text.tkraise() - self.face_shown = 1 - - def showback(self): - """Turn the card's face down.""" - self.tkraise() - self.__rect.tkraise() - self.__back.tkraise() - self.face_shown = 0 - - -class Stack: - - """A generic stack of cards. - - This is used as a base class for all other stacks (e.g. the deck, - the suit stacks, and the row stacks). - - Public methods: - - 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 - - Method that subclasses may override: - - position(card) -- move the card to its proper (x, y) position - - The default position() method places all cards at the stack's - own (x, y) position. - - userclickhandler(), userdoubleclickhandler() -- called to do - subclass specific things on single and double clicks - - The default user (single) click handler shows the top card - face up. The default user double click handler calls the user - single click handler. - - usermovehandler(cards) -- called to complete a subpile move - - The default user move handler moves all moved cards back to - their original position (by calling the position() method). - - Private methods: - - clickhandler(event), doubleclickhandler(event), - motionhandler(event), releasehandler(event) -- event handlers - - 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 - self.game = game - self.cards = [] - 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 - - def __repr__(self): - """Return a string for debug print statements.""" - return "%s(%d, %d)" % (self.__class__.__name__, self.x, self.y) - - # Public methods - - def add(self, card): - self.cards.append(card) - card.tkraise() - self.position(card) - self.group.addtag_withtag(card.group) - - def delete(self, card): - self.cards.remove(card) - card.group.dtag(self.group) - - def showtop(self): - if self.cards: - self.cards[-1].showface() - - def deal(self): - if not self.cards: - return None - card = self.cards[-1] - self.delete(card) - return card - - # Subclass overridable methods - - def position(self, card): - card.moveto(self.x, self.y) - - def userclickhandler(self): - self.showtop() - - def userdoubleclickhandler(self): - self.userclickhandler() - - def usermovehandler(self, cards): - for card in cards: - self.position(card) - - # 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) - - def releasehandler(self, event): - self.keepmoving(event) - self.finishmoving() - - def doubleclickhandler(self, event): - self.finishmoving() # In case we lost an event - self.userdoubleclickhandler() - self.startmoving(event) - - # Move internals - - moving = None - - def startmoving(self, event): - self.moving = None - tags = self.game.canvas.gettags('current') - for i in range(len(self.cards)): - card = self.cards[i] - if card.group.tag in tags: - break - else: - return - if not card.face_shown: - return - 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 - dx = event.x - self.lastx - dy = event.y - self.lasty - self.lastx = event.x - self.lasty = event.y - if dx or dy: - for card in self.moving: - card.moveby(dx, dy) - - 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): - - def acceptable(self, cards): - return 0 - - def usermovehandler(self, cards): - card = cards[0] - stack = self.game.closeststack(card) - if not stack or stack is self or not stack.acceptable(cards): - Stack.usermovehandler(self, cards) - else: - for card in cards: - self.delete(card) - stack.add(card) - self.game.wincheck() - - def userdoubleclickhandler(self): - if not self.cards: - return - card = self.cards[-1] - if not card.face_shown: - self.userclickhandler() - return - for s in self.game.suits: - if s.acceptable([card]): - self.delete(card) - s.add(card) - self.game.wincheck() - break - - -class SuitStack(OpenStack): - - def makebottom(self): - bottom = Rectangle(self.game.canvas, - self.x, self.y, - self.x+CARDWIDTH, self.y+CARDHEIGHT, - outline='black', fill='') - - def userclickhandler(self): - pass - - def userdoubleclickhandler(self): - pass - - 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 - - -class RowStack(OpenStack): - - 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 - 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) - - -class Solitaire: - - def __init__(self, master): - self.master = master - - self.canvas = Canvas(self.master, - background=BACKGROUND, - highlightthickness=0, - width=NROWS*XSPACING, - height=3*YSPACING + 20 + MARGIN) - self.canvas.pack(fill=BOTH, expand=TRUE) - - self.dealbutton = Button(self.canvas, - text="Deal", - highlightthickness=0, - background=BACKGROUND, - activebackground="green", - command=self.deal) - Window(self.canvas, MARGIN, 3*YSPACING + 20, - window=self.dealbutton, anchor=SW) - - x = MARGIN - y = MARGIN - - self.deck = Deck(x, y, self) - - x = x + XSPACING - self.opendeck = OpenStack(x, y, self) - - x = x + XSPACING - self.suits = [] - for i in range(NSUITS): - x = x + XSPACING - self.suits.append(SuitStack(x, y, self)) - - x = MARGIN - y = y + YSPACING - - self.rows = [] - for i in range(NROWS): - self.rows.append(RowStack(x, y, self)) - x = x + XSPACING - - self.openstacks = [self.opendeck] + self.suits + self.rows - - self.deck.fill() - self.deal() - - def wincheck(self): - for s in self.suits: - if len(s.cards) != NVALUES: - return - self.win() - self.deal() - - def win(self): - """Stupid animation when you win.""" - cards = [] - for s in self.openstacks: - cards = cards + s.cards - while cards: - card = random.choice(cards) - 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 - 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. - for stack in self.openstacks: - 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() - r.add(card) - for r in self.rows: - r.showtop() - - def reset(self): - for stack in self.openstacks: - while 1: - card = stack.deal() - if not card: - break - self.deck.add(card) - card.showback() - - -# 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() |