From: <umg...@us...> - 2007-07-13 17:56:16
|
Revision: 482 http://svn.sourceforge.net/pybridge/?rev=482&view=rev Author: umgangee Date: 2007-07-13 10:56:13 -0700 (Fri, 13 Jul 2007) Log Message: ----------- Rewrite TrickPlay class, making full use of new-style Python objects and eliminating ugly trick index methods. Modified Paths: -------------- trunk/pybridge/pybridge/games/bridge/game.py trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py trunk/pybridge/pybridge/ui/cardarea.py trunk/pybridge/tests/bridge/test_game.py trunk/pybridge/tests/bridge/test_play.py Added Paths: ----------- trunk/pybridge/pybridge/games/bridge/play.py Removed Paths: ------------- trunk/pybridge/pybridge/games/bridge/playing.py Modified: trunk/pybridge/pybridge/games/bridge/game.py =================================================================== --- trunk/pybridge/pybridge/games/bridge/game.py 2007-07-13 10:29:04 UTC (rev 481) +++ trunk/pybridge/pybridge/games/bridge/game.py 2007-07-13 17:56:13 UTC (rev 482) @@ -25,7 +25,7 @@ from bidding import Bidding from board import Board -from playing import Playing +from play import Trick, TrickPlay from scoring import scoreDuplicate from call import Bid, Pass, Double, Redouble @@ -59,9 +59,11 @@ def __init__(self): self.listeners = [] + # TODO: are these necessary? self.board = None self.bidding = None self.contract = None + self.trumpSuit = None self.play = None self.boardQueue = [] # Boards for successive games. @@ -85,6 +87,7 @@ self.board.nextDeal() self.bidding = Bidding(self.board['dealer']) # Start bidding. self.contract = None + self.trumpSuit = None self.play = None self.visibleHands.clear() @@ -96,7 +99,7 @@ def inProgress(self): - if self.play: + if self.play is not None: return not self.play.isComplete() elif self.bidding: return not self.bidding.isPassedOut() @@ -119,14 +122,8 @@ if self.bidding: state['calls'] = self.bidding.calls - if self.play: - state['played'] = [] - trickcount = max([len(s) for s in self.play.played.values()]) - for index in range(trickcount): - leader, cards = self.play.getTrick(index) - for pos in Direction[leader.index:] + Direction[:leader.index]: - if pos in cards: - state['played'].append(cards[pos]) + if self.play is not None: + state['play'] = [dict(trick) for trick in self.play] return state @@ -139,12 +136,11 @@ turn = self.getTurn() self.makeCall(call, position=turn) - for card in state.get('played', []): - turn = self.getTurn() - # TODO: remove this hack - if turn == self.play.dummy: - turn = self.play.declarer - self.playCard(card, position=turn) + for trick in state.get('play', []): + turn = self.play.whoseTurn() + trickobj = Trick(leader=turn, trumpSuit=self.trumpSuit) + trickobj.update(trick) # Populate with cards. + self.play.append(trickobj) def updateState(self, event, *args, **kwargs): @@ -237,8 +233,8 @@ if self.bidding.isComplete() and not self.bidding.isPassedOut(): self.contract = self.bidding.getContract() # TODO: make a property - trumpSuit = self.trumpMap[self.contract['bid'].strain] - self.play = Playing(self.contract['declarer'], trumpSuit) + self.trumpSuit = self.trumpMap[self.contract['bid'].strain] + self.play = TrickPlay(self.contract['declarer'], self.trumpSuit) self.notify('makeCall', call=call, position=position) @@ -279,7 +275,7 @@ if position not in Direction: raise TypeError, "Expected Direction, got %s" % type(position) - if not self.play or self.play.isComplete(): + if self.play is None or self.play.isComplete(): raise GameError, "No game in progress, or play complete" playfrom = position @@ -294,15 +290,16 @@ if self.getTurn() != playfrom: raise GameError, "Card played out of turn" - hand = self.board['deal'].get(playfrom, []) # Empty if hand unknown. - if not self.play.isValidPlay(card, playfrom, hand): - raise GameError, "Card cannot be played from hand" + # If complete deal known, validate card play. + if len(self.board['deal']) == len(Direction): + if not self.play.isValidCardPlay(card, self.board['deal']): + raise GameError, "Card cannot be played from hand" - self.play.playCard(card) + self.play.playCard(card, playfrom) self.notify('playCard', card=card, position=position) # Dummy's hand is revealed when the first card of first trick is played. - if len(self.play.getTrick(0)[1]) == 1: + if len(self.play[0]) == 1: dummyhand = self.board['deal'].get(self.play.dummy) if dummyhand: # Reveal hand only if known. self.revealHand(dummyhand, self.play.dummy) @@ -380,15 +377,10 @@ else: # East or West vulnerable = (self.board['vuln'] in (Vulnerable.EastWest, Vulnerable.All)) - tricksMade = 0 # Count of tricks won by declarer or dummy. - for index in range(len(self.play.winners)): - trick = self.play.getTrick(index) - winningCard = self.play.winningCard(trick) - winner = self.play.whoPlayed(winningCard) - tricksMade += winner in (declarer, dummy) - result = {'contract' : contract, - 'tricksMade' : tricksMade, - 'vulnerable' : vulnerable, } + declarerWon, defenceWon = self.play.wonTrickCount() + + result = {'contract': contract, 'tricksMade': declarerWon, + 'vulnerable': vulnerable} return scoreDuplicate(result) Copied: trunk/pybridge/pybridge/games/bridge/play.py (from rev 480, trunk/pybridge/pybridge/games/bridge/playing.py) =================================================================== --- trunk/pybridge/pybridge/games/bridge/play.py (rev 0) +++ trunk/pybridge/pybridge/games/bridge/play.py 2007-07-13 17:56:13 UTC (rev 482) @@ -0,0 +1,235 @@ +# PyBridge -- online contract bridge made easy. +# Copyright (C) 2004-2007 PyBridge Project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +from card import Card +from symbols import Direction + + +class Trick(dict): + """A trick is a set of cards, each played from the hand of a player.""" + + + def __init__(self, leader, trumpSuit): + """ + @param leader: the position from which the lead card is played. + @type declarer: Direction + @param trumpSuit: the contract's trump suit: specify None for No Trumps. + @type trumpSuit: Suit or None + """ + self.leader = leader + self.trumpSuit = trumpSuit + + winningCard = property(lambda self: self._getWinningCard()) + winner = property(lambda self: self.whoPlayed(self.winningCard)) + + + def isComplete(self): + """The trick is complete when it contains a card from each position. + + @return: True if trick is complete, False otherwise. + """ + return set(self.keys()) == set(Direction) # A card from each position. + + + def whoseTurn(self): + """Returns the position from which the next card should be played. + + @return: the next position to play a card, or None. + """ + if self.isComplete(): + return + + numCardsPlayed = len(self) + return Direction[(self.leader.index + numCardsPlayed) % 4] + + + def whoPlayed(self, playedcard): + """Returns the position from which the specified card was played. + + @param playedcard: a card played in the trick. + @return: the position of the card. + """ + for position, card in self.iteritems(): + if card == playedcard: + return position + + + def _getWinningCard(self): + """If the trick is complete, returns the winning card. + + - In a trump contract, the highest ranked trump card wins. + - Otherwise, the highest ranked card following the lead suit wins. + + @return: the winning card, or None if trick is not complete. + """ + if not self.isComplete(): + return + + if self.trumpSuit: # Suit contract. + # The highest ranked trump card wins. + trumpcards = [c for c in self.values() if c.suit == self.trumpSuit] + if trumpcards: + return max(trumpcards) + + # No trump cards played, or No Trump contract. + # The highest ranked card in the lead card's suit wins. + leadsuit = self[self.leader].suit + followers = [c for c in self.values() if c.suit == leadsuit] + return max(followers) + + + + +class TrickPlay(list): + """The trick-taking phase of a game of cards. + + This code is generalised, and could easily be adapted to support a + variety of trick-taking card games. + """ + + + def __init__(self, declarer, trumpSuit): + """ + @param declarer: the declarer of the auction contract. + @type declarer: Direction + @param trumpSuit: the trump suit of the auction contract. + @type trumpSuit: Suit or None + """ + self.declarer = declarer + self.trumpSuit = trumpSuit + + # Other positions, respective to declarer. + dummy = property(lambda self: Direction[(self.declarer.index + 2) % 4]) + lho = property(lambda self: Direction[(self.declarer.index + 1) % 4]) + rho = property(lambda self: Direction[(self.declarer.index + 3) % 4]) + + + def isComplete(self): + """Play is complete if there are 13 complete tricks. + + @return: True if play is complete, False otherwise. + """ + return len([trick for trick in self if trick.isComplete()]) == 13 + + + def isValidCardPlay(self, card, deal): + """Card is playable if all of the following are true: + + - The play session is not complete. + - The position is on turn to play. + - The card exists in hand. + - The card has not been previously played in any trick. + + In addition, if the current trick has an established lead, then + card must follow lead suit OR hand must be void in lead suit. + + Assumes that players do not attempt to play cards from other hands. + + @param card: the candidate card. + @type card: Card + @param deal: the original deal of hands. + @type deal: {Direction: [Card]} + @return: True if card is playable, False otherwise. + """ + turn = self.whoseTurn() + played = [trick[turn] for trick in self if trick.get(turn)] + hand = set(deal[turn]) - set(played) # Cards currently in hand. + + # Some sanity checks. + if self.isComplete() or card not in hand: + return False + + if len(self) == 0 or self[-1].isComplete(): + return True # First card in the next (new) trick. + + # Current trick has an established lead: check for revoke. + trick = self[-1] + leadsuit = trick[trick.leader].suit + followers = [c for c in hand if c.suit == leadsuit] + # Hand void in lead suit, or card follows lead suit. + return followers == [] or card in followers + + + def playCard(self, card, position): + """Plays card to current (or new) trick. + + Please note that card validity must be checked with isValidCardPlay() + before calling this method! + + @param card: the card to be played. + @type card: Card + @param position: the position from which the card is to be played. + @type position: Direction + """ + assert not self.isComplete() + assert self.whoseTurn() == position + + # If current trick is complete, instantiate a new trick. + if len(self) == 0 or self[-1].isComplete(): + trick = Trick(leader=self.whoseTurn(), trumpSuit=self.trumpSuit) + self.append(trick) + else: + trick = self[-1] + assert trick.get(position) is None + + trick[position] = card + + + def whoseTurn(self): + """Returns the position from which the next card should be played. + + @return: the next position to play a card, or None. + """ + if self.isComplete(): + return + + try: + currentTrick = self[-1] # Raises IndexError if no tricks. + except IndexError: + return self.lho # Declarer's LHO leads the first trick. + + if currentTrick.isComplete(): + return currentTrick.winner # The winner leads the next trick. + else: + return currentTrick.whoseTurn() + + + def wonTricks(self): + """Returns, for each position a list of tricks won by that position. + + @return: a dict containing, for each position, the list of won tricks. + @rtype: {Direction: [Trick]} + """ + won = dict([(pos, []) for pos in Direction]) + for trick in self: + if trick.isComplete(): # Trick is complete <=> trick has winner. + won[trick.winner].append(trick) + return won + + + def wonTrickCount(self): + """Returns the number of tricks won by declarer/dummy and by defenders. + + @return: a 2-tuple containing the declarer and defender trick counts. + @rtype: (int, int) + """ + tricks = self.wonTricks() + declarerWon = len(tricks[self.declarer]) + len(tricks[self.dummy]) + defenceWon = len(tricks[self.lho]) + len(tricks[self.rho]) + return (declarerWon, defenceWon) + Deleted: trunk/pybridge/pybridge/games/bridge/playing.py =================================================================== --- trunk/pybridge/pybridge/games/bridge/playing.py 2007-07-13 10:29:04 UTC (rev 481) +++ trunk/pybridge/pybridge/games/bridge/playing.py 2007-07-13 17:56:13 UTC (rev 482) @@ -1,227 +0,0 @@ -# PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2007 PyBridge Project. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -from card import Card -from symbols import Direction, Suit - - -class Playing(object): - """This class models the trick-taking phase of a game of bridge. - - This code is generalised, and could easily be adapted to support a - variety of trick-taking card games. - """ - - # TODO: tricks, leader, winner properties? - - - def __init__(self, declarer, trumpSuit): - """ - @param declarer: the declarer from the auction. - @type declarer: Direction - @param trumpSuit: the trump suit from the auction. - @type trumpSuit: Suit or None - """ - if declarer not in Direction: - raise TypeError, "Expected Direction, got %s" % type(declarer) - if trumpSuit not in Suit and trumpSuit is not None: # None => No Trumps - raise TypeError, "Expected Suit, got %s" % type(trumpSuit) - - self.trumps = trumpSuit - self.declarer = declarer - self.dummy = Direction[(declarer.index + 2) % 4] - self.lho = Direction[(declarer.index + 1) % 4] - self.rho = Direction[(declarer.index + 3) % 4] - - # Each trick corresponds to a cross-section of lists. - self.played = {} - for position in Direction: - self.played[position] = [] - self.winners = [] # Winning player of each trick. - - - def isComplete(self): - """Playing is complete if there are 13 complete tricks. - - @return: True if playing is complete, False if not. - """ - return len(self.winners) == 13 - - - def getTrick(self, index): - """A trick is a set of cards, one from each player's hand. - The leader plays the first card, the others play in clockwise order. - - @param: trick index, in range 0 to 12. - @return: a (leader, cards) trick tuple. - """ - assert 0 <= index < 13 - - if index == 0: # First trick. - leader = self.lho # Leader is declarer's left-hand opponent. - else: # Leader is winner of previous trick. - leader = self.winners[index - 1] - cards = {} - for position in Direction: - # If length of list exceeds index value, player's card in trick. - if len(self.played[position]) > index: - cards[position] = self.played[position][index] - return leader, cards - - - def getCurrentTrick(self): - """Returns the getTrick() tuple of the current trick. - - @return: a (leader, cards) trick tuple. - """ - # Index of current trick is length of longest played list minus 1. - index = max(0, max([len(cards) for cards in self.played.values()]) - 1) - return self.getTrick(index) - - - def getTrickCount(self): - """Returns the number of tricks won by declarer/dummy and by defenders. - - @return: the declarer trick count, the defender trick count. - @rtype: tuple - """ - declarerCount, defenderCount = 0, 0 - - for i in range(len(self.winners)): - trick = self.getTrick(i) - winner = self.whoPlayed(self.winningCard(trick)) - if winner in (self.declarer, self.dummy): - declarerCount += 1 - else: # Trick won by defenders. - defenderCount += 1 - - return declarerCount, defenderCount - - - def playCard(self, card, player=None, hand=[]): - """Plays card to current trick. - Card validity should be checked with isValidPlay() beforehand. - - @param card: the Card object to be played from player's hand. - @param player: the player of card, or None. - @param hand: the hand of player, or []. - """ - assert isinstance(card, Card) - player = player or self.whoseTurn() - hand = hand or [card] # Skip hand check. - - valid = self.isValidPlay(card, player, hand) - assert valid - if valid: # In case assert is disabled. - self.played[player].append(card) - - # If trick is complete, determine winner. - trick = self.getCurrentTrick() - leader, cards = trick - if len(cards) == 4: - winner = self.whoPlayed(self.winningCard(trick)) - self.winners.append(winner) - - - def isValidPlay(self, card, player=None, hand=[]): - """Card is playable if and only if: - - - Play session is not complete. - - Direction is on turn to play. - - Card exists in hand. - - Card has not been previously played. - - In addition, if the current trick has an established lead, then - card must follow lead suit OR hand must be void in lead suit. - - Specification of player and hand are required for verification. - """ - assert isinstance(card, Card) - - if self.isComplete(): - return False - elif hand and card not in hand: - return False # Playing a card not in hand. - elif player and player != self.whoseTurn(): - return False # Playing out of turn. - elif self.whoPlayed(card): - return False # Card played previously. - - leader, cards = self.getCurrentTrick() - # 0 if start of playing, 4 if complete trick. - if len(cards) in (0, 4): - return True # Card will be first in next trick. - - else: # Current trick has an established lead: check for revoke. - leadcard = cards[leader] - # Cards in hand that match suit of leadcard. - followers = [c for c in hand if c.suit == leadcard.suit - and not self.whoPlayed(c)] - # Hand void in lead suit or card follows lead suit. - return len(followers) == 0 or card in followers - - - def whoPlayed(self, card): - """Returns the player who played the specified card. - - @param card: a Card. - @return: the player who played card. - """ - assert isinstance(card, Card) - for player, cards in self.played.items(): - if card in cards: - return player - return False - - - def whoseTurn(self): - """If playing is not complete, returns the player who is next to play. - - @return: the player next to play. - """ - if not self.isComplete(): - trick = self.getCurrentTrick() - leader, cards = trick - if len(cards) == 4: # If trick is complete, trick winner's turn. - return self.whoPlayed(self.winningCard(trick)) - else: # Otherwise, turn is next (clockwise) player in trick. - return Direction[(leader.index + len(cards)) % 4] - return False - - - def winningCard(self, trick): - """Determine which card wins the specified trick: - - - In a trump contract, the highest ranked trump card wins. - - Otherwise, the highest ranked card of the lead suit wins. - - @param: a complete (leader, cards) trick tuple. - @return: the Card object which wins the trick. - """ - leader, cards = trick - if len(cards) == 4: # Trick is complete. - if self.trumps: # Suit contract. - trumpcards = [c for c in cards.values() if c.suit==self.trumps] - if len(trumpcards) > 0: - return max(trumpcards) # Highest ranked trump. - # No Trump contract, or no trump cards played. - followers = [c for c in cards.values() - if c.suit==cards[leader].suit] - return max(followers) # Highest ranked card in lead suit. - return False - Modified: trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py =================================================================== --- trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py 2007-07-13 10:29:04 UTC (rev 481) +++ trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py 2007-07-13 17:56:13 UTC (rev 482) @@ -102,7 +102,7 @@ def add_score(self, game): - declarerWon, defenceWon = game.play.getTrickCount() + declarerWon, defenceWon = game.play.wonTrickCount() score = game.getScore() textContract = render_contract(game.contract) @@ -169,15 +169,15 @@ def set_trickcount(self, game): if game.play: - declarer, defence = game.play.getTrickCount() + declarerWon, defenceWon = game.play.wonTrickCount() required = game.contract['bid'].level.index + 7 - declarerNeeds = max(0, required - declarer) - defenceNeeds = max(0, 13 + 1 - required - defence) + declarerNeeds = max(0, required - declarerWon) + defenceNeeds = max(0, 13 + 1 - required - defenceWon) else: - declarer, defence, declarerNeeds, defenceNeeds = 0, 0, 0, 0 + declarerWon, defenceWon, declarerNeeds, defenceNeeds = 0, 0, 0, 0 format = "<span size='x-large'><b>%s</b> (%s)</span>" - self.declarer_tricks.set_markup(format % (declarer, declarerNeeds)) - self.defence_tricks.set_markup(format % (defence, defenceNeeds)) + self.declarer_tricks.set_markup(format % (declarerWon, declarerNeeds)) + self.defence_tricks.set_markup(format % (defenceWon, defenceNeeds)) def set_dealer(self, game): @@ -285,11 +285,10 @@ if self.table.game.inProgress(): # If trick play in progress, redraw trick. - if self.table.game.play: + if self.table.game.play is not None: self.redrawTrick() - index = max([len(cards) for cards in self.table.game.play.played.values()]) - 2 - if index >= 0: - self.trickarea.set_trick(self.table.game.play.getTrick(index)) + if len(self.table.game.play) > 1: + self.trickarea.set_trick(self.table.game.play[-2]) self.setTurnIndicator() @@ -340,7 +339,7 @@ if self.table.game.contract: self.scoreview.add_score(self.table.game) - declarerWon, defenceWon = self.table.game.play.getTrickCount() + declarerWon, defenceWon = self.table.game.play.wonTrickCount() required = self.table.game.contract['bid'].level.index + 7 offset = declarerWon - required score = self.table.game.getScore() @@ -410,7 +409,7 @@ if all is True or self.table.game.play is None: available = hand else: - played = self.table.game.play.played[position] + played = [trick[position] for trick in self.table.game.play if trick.get(position)] if facedown: # Draw cards face down for unknown hand. available = range(13 - len(played)) else: @@ -427,7 +426,7 @@ """ trick = None if self.table.game.play: - trick = self.table.game.play.getCurrentTrick() + trick = self.table.game.play[-1] self.cardarea.set_trick(trick) @@ -439,7 +438,7 @@ try: turn = self.table.game.getTurn() - if self.table.game.play: + if self.table.game.play is not None: declarer, dummy = self.table.game.play.declarer, self.table.game.play.dummy if self.position and self.position == turn != dummy: text = _("Play a card from your hand.") @@ -531,16 +530,14 @@ def event_playCard(self, card, position): # Determine the position of the hand from which card was played. - playfrom = self.table.game.play.whoPlayed(card) + playfrom = self.table.game.play[-1].whoPlayed(card) self.setTurnIndicator() self.dashboard.set_trickcount(self.table.game) self.redrawTrick() self.redrawHand(playfrom) + if len(self.table.game.play) > 1: + self.trickarea.set_trick(self.table.game.play[-2]) - index = max([len(cards) for cards in self.table.game.play.played.values()]) - 2 - if index >= 0: - self.trickarea.set_trick(self.table.game.play.getTrick(index)) - if not self.table.game.inProgress(): self.gameComplete() @@ -567,7 +564,7 @@ def on_card_clicked(self, card, position): if self.player: - if self.table.game.inProgress() and self.table.game.play: + if self.table.game.inProgress() and self.table.game.play is not None: d = self.player.callRemote('playCard', card) d.addErrback(self.errback) Modified: trunk/pybridge/pybridge/ui/cardarea.py =================================================================== --- trunk/pybridge/pybridge/ui/cardarea.py 2007-07-13 10:29:04 UTC (rev 481) +++ trunk/pybridge/pybridge/ui/cardarea.py 2007-07-13 17:56:13 UTC (rev 482) @@ -251,16 +251,15 @@ """Sets the current trick. Draws representation of current trick to context. - @param trick: a (leader, cards_played) pair, or None. + @param trick: a Trick object, or None. """ if trick: - leader, cards = trick # The order of play is the leader, then clockwise around Direction. - order = Direction[leader.index:] + Direction[:leader.index] + order = Direction[trick.leader.index:] + Direction[:trick.leader.index] for i, position in enumerate(order): id = ('trick', position) - old_card = self.trick and self.trick[1].get(position) or None - new_card = cards.get(position) or None + old_card = self.trick and self.trick.get(position) + new_card = trick.get(position) # If old card matches new card, take no action. if old_card is None and new_card is not None: @@ -275,11 +274,14 @@ self.update_item(id, surface, z_index=i+1) elif self.trick: # Remove all cards from previous trick. - for position in self.trick[1]: + for position in self.trick: id = ('trick', position) if id in self.items: self.remove_item(id) + # Copy trick object, to distinguish it from itself in the future. + if trick: + trick = trick.copy() self.trick = trick # Save trick. Modified: trunk/pybridge/tests/bridge/test_game.py =================================================================== --- trunk/pybridge/tests/bridge/test_game.py 2007-07-13 10:29:04 UTC (rev 481) +++ trunk/pybridge/tests/bridge/test_game.py 2007-07-13 17:56:13 UTC (rev 482) @@ -107,7 +107,7 @@ turn = self.game.getTurn() # Find a valid card. for card in board['deal'][turn]: - if self.game.play.isValidPlay(card, turn, hand=board['deal'][turn]): + if self.game.play.isValidCardPlay(card, deal=board['deal']): if turn == self.game.play.dummy: turn = self.game.play.declarer self.players[turn].playCard(card) Modified: trunk/pybridge/tests/bridge/test_play.py =================================================================== --- trunk/pybridge/tests/bridge/test_play.py 2007-07-13 10:29:04 UTC (rev 481) +++ trunk/pybridge/tests/bridge/test_play.py 2007-07-13 17:56:13 UTC (rev 482) @@ -1,28 +1,64 @@ import unittest -import random from pybridge.games.bridge.card import Card from pybridge.games.bridge.deck import Deck -from pybridge.games.bridge.playing import Playing +from pybridge.games.bridge.play import TrickPlay from pybridge.games.bridge.symbols import Direction, Rank, Suit -class TestPlaying(unittest.TestCase): +class TestTrickPlay(unittest.TestCase): - + deal = Deck().indexToDeal(31415926535897932384626433832) # Pi! + declarer = Direction.North + trumpSuit = Suit.Spade + + def setUp(self): - declarer = random.choice(Direction) - trumps = random.choice(list(Suit) + [None]) - self.deal = Deck().randomDeal() - self.playing = Playing(declarer, trumps) + self.trickplay = TrickPlay(self.declarer, self.trumpSuit) def tearDown(self): - self.deal = None - self.playing = None + self.trickplay = None + def stepThroughTrickPlay(self): + for i in range(52): + card, position = self.getValidArgsForPlayCard() + yield card, position + self.trickplay.playCard(card, position) + + + def getValidArgsForPlayCard(self): + # Select the next card to play, deterministically. + assert not self.trickplay.isComplete() + turn = self.trickplay.whoseTurn() + card = self.deal[turn][0] + # Assumes correctness of isValidCardPlay. + while not self.trickplay.isValidCardPlay(card, self.deal): + card = self.deal[turn][self.deal[turn].index(card) + 1] + return card, turn + + + def testIsComplete(self): + s = self.stepThroughTrickPlay() + try: + while s.next(): + self.assertEqual(self.trickplay.isComplete(), False) + except StopIteration: + self.assertEqual(self.trickplay.isComplete(), True) +# for trick in self.trickplay: +# print "leader", trick.leader +# for pos, card in trick.items(): +# print str(pos), card +# print "winner", trick.winner, trick.winningCard + + def testWhoseTurn(self): + s = self.stepThroughTrickPlay() + self.assertEqual(self.trickplay.whoseTurn(), self.trickplay.lho) + +''' + def testWhoseTurn(self): """whoseTurn""" while not self.playing.isComplete(): # Determine whose turn it should be. @@ -42,10 +78,11 @@ if self.playing.isValidPlay(card, turn, hand): break self.playing.playCard(card, turn, hand) +''' def main(): - suite = unittest.makeSuite(TestPlaying) + suite = unittest.makeSuite(TestTrickPlay) unittest.TextTestRunner(verbosity=2).run(suite) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |