From: <umg...@us...> - 2007-07-26 19:35:35
|
Revision: 496 http://pybridge.svn.sourceforge.net/pybridge/?rev=496&view=rev Author: umgangee Date: 2007-07-26 12:03:38 -0700 (Thu, 26 Jul 2007) Log Message: ----------- Incorporate support for Result objects in board, make appropriate tweaks to dependencies. Modified Paths: -------------- trunk/pybridge/pybridge/games/bridge/board.py trunk/pybridge/pybridge/games/bridge/game.py trunk/pybridge/pybridge/games/bridge/result.py trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py Modified: trunk/pybridge/pybridge/games/bridge/board.py =================================================================== --- trunk/pybridge/pybridge/games/bridge/board.py 2007-07-25 21:04:25 UTC (rev 495) +++ trunk/pybridge/pybridge/games/bridge/board.py 2007-07-26 19:03:38 UTC (rev 496) @@ -18,7 +18,9 @@ import random import time + from deal import Deal +from result import DuplicateResult, RubberResult from symbols import Direction, Vulnerable @@ -43,32 +45,68 @@ @type vuln: Vulnerable """ + __directionToVuln = {Direction.North: Vulnerable.NorthSouth, + Direction.East: Vulnerable.EastWest, + Direction.South: Vulnerable.NorthSouth, + Direction.West: Vulnerable.EastWest} - def nextDeal(self, result=None): - """Generates and stores a random deal for the board. + + @classmethod + def first(cls, deal=None): + """Build an initial board. - If result of a previous game is provided, the dealer and vulnerability - are rotated according to the rules of bridge. + @deal: if provided, the deal to be wrapped by board. + Otherwise, a randomly-generated deal is wrapped. + """ + board = cls() + board['deal'] = deal or Deal.fromRandom() + board['num'] = 1 + board['time'] = tuple(time.localtime()) + + board['dealer'] = Direction.North # Arbitary. + board['vuln'] = Vulnerable.None + + return board + + + def next(self, result, deal=None): + """Given the result for this board, builds the next board. - @param result: - @type result: + The dealer and vulnerability of the next board are calculated + from the result provided. + + @param result: the result of the this board. + @param deal: if provided, the deal to be wrapped by next board. + Otherwise, a randomly-generated deal is wrapped. """ - self['deal'] = Deal.fromRandom() + assert result.board == self - self['num'] = self.get('num', 0) + 1 - self['time'] = tuple(time.localtime()) + board = Board(self.copy()) # copy() returns a dict. + board['deal'] = deal or Deal.fromRandom() + board['num'] = board.get('num', 0) + 1 + board['time'] = tuple(time.localtime()) - if self.get('dealer'): # Rotate dealer. - self['dealer'] = Direction[(self['dealer'].index + 1) % 4] - else: # Select any player as the dealer. - self['dealer'] = random.choice(Direction) + # Dealer rotates clockwise. + board['dealer'] = Direction[(board['dealer'].index + 1) % 4] - if result: - # TODO: proper GameResult object. - # TODO: consider vulnerability rules for duplicate, rubber bridge. - #if result.bidding.isPassedOut(): - # self['vuln'] = result.board['vuln'] - #elif result.getScore() >= 0 - self['vuln'] = Vulnerable[(result.board['vuln'].index + 1) % 4] - else: - self['vuln'] = Vulnerable.None # The default value. + if isinstance(result, DuplicateResult): + # See http://www.d21acbl.com/References/Laws/node5.html#law2 + i = (board['num'] - 1) % 16 + # Map from duplicate board index range 1..16 to vulnerability. + board['vuln'] = Vulnerable[(i%4 + i/4)%4] + + elif isinstance(result, RubberResult): + # Determine vulnerability of board from result of previous board. + above, below = result.score + if below >= 100: # Game contract successful. + pair = __directionToVuln[result.contract.declarer] + # Vulnerability transitions. + if board['vuln'] == Vulnerable.None: + board['vuln'] = pair + elif board['vuln'] in (pair, Vulnerable.All): # Rubber won. + board['vuln'] = Vulnerable.None + else: # Pair not vulnerable, other pair are vulnerable. + board['vuln'] = Vulnerable.All + + return board + Modified: trunk/pybridge/pybridge/games/bridge/game.py =================================================================== --- trunk/pybridge/pybridge/games/bridge/game.py 2007-07-25 21:04:25 UTC (rev 495) +++ trunk/pybridge/pybridge/games/bridge/game.py 2007-07-26 19:03:38 UTC (rev 496) @@ -63,12 +63,14 @@ self.auction = None self.play = None - self.boardQueue = [] # Boards for successive games. + self.boardQueue = [] # Boards for successive rounds. + self.results = [] # Results of previous rounds. self.visibleHands = {} # A subset of deal, containing revealed hands. self.players = {} # One-to-one mapping from BridgePlayer to Direction. contract = property(lambda self: self.auction and self.auction.contract or None) trumpSuit = property(lambda self: self.play and self.play.trumpSuit or None) + result = property(lambda self: not self.inProgress() and self.results[-1]) # Implementation of ICardGame. @@ -81,10 +83,12 @@ if board: # Use specified board. self.board = board elif self.board: # Advance to next deal. - self.board.nextDeal(result=self) # TODO: proper GameResult object. + tricksMade, _ = self.play.wonTrickCount() + result = DuplicateResult(self.board, self.contract, tricksMade) + self.board = self.board.next(result) else: # Create a board. - self.board = Board() - self.board.nextDeal() + self.board = Board.first() + self.auction = Auction(self.board['dealer']) # Start auction. self.play = None self.visibleHands.clear() @@ -242,10 +246,14 @@ trumpSuit = self.__trumpMap[self.contract.bid.strain] self.play = TrickPlay(declarer, trumpSuit) + # If bidding is passed out, game is complete. + if not self.inProgress() and self.board['deal']: + self.results.append(DuplicateResult(self.board, contract=None)) + self.notify('makeCall', call=call, position=position) - # If bidding is passed out, reveal all hands. if not self.inProgress() and self.board['deal']: + # Reveal all unrevealed hands. for position in Direction: hand = self.board['deal'].get(position) if hand and position not in self.visibleHands: @@ -302,7 +310,6 @@ raise GameError, "Card cannot be played from hand" 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[0]) == 1: @@ -310,12 +317,21 @@ if dummyhand: # Reveal hand only if known. self.revealHand(dummyhand, self.play.dummy) - # If play is complete, reveal all hands. + # If play is complete, game is complete. if not self.inProgress() and self.board['deal']: + tricksMade, _ = self.play.wonTrickCount() + result = DuplicateResult(self.board, self.contract, tricksMade) + self.results.append(result) + + self.notify('playCard', card=card, position=position) + + if not self.inProgress() and self.board['deal']: + # Reveal all unrevealed hands. for position in Direction: hand = self.board['deal'].get(position) if hand and position not in self.visibleHands: self.revealHand(hand, position) + def revealHand(self, hand, position): @@ -363,24 +379,8 @@ raise GameError, "No game in progress" - def getScore(self): - """Returns the integer score value for declarer/dummy if: - - auction has been passed out, with no bids made. - - trick play is complete. - """ - if self.inProgress() or self.auction is None: - raise GameError, "Game not complete" - if self.auction.isPassedOut(): - return 0 # A passed out deal does not score. - tricksMade, _ = self.play.wonTrickCount() - result = DuplicateResult(self.contract, self.board['vuln'], tricksMade) - return result.score - - - - class BridgePlayer(pb.Referenceable): """Actor representing a player's view of a BridgeGame object.""" Modified: trunk/pybridge/pybridge/games/bridge/result.py =================================================================== --- trunk/pybridge/pybridge/games/bridge/result.py 2007-07-25 21:04:25 UTC (rev 495) +++ trunk/pybridge/pybridge/games/bridge/result.py 2007-07-26 19:03:38 UTC (rev 496) @@ -30,14 +30,17 @@ Vulnerable.All: tuple(Direction)} - def __init__(self, contract, vuln, tricksMade=None): + def __init__(self, board, contract, tricksMade=None): """ + @type board: Board @type contract: Contract - @type vuln: Vulnerable @type tricksMade: int or None """ + self.board = board self.contract = contract self.tricksMade = tricksMade + + vuln = self.board.get('vuln', Vulnerable.None) self.isVulnerable = self.contract.declarer in self.__vulnMapping[vuln] self.score = self._getScore() Modified: trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py =================================================================== --- trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py 2007-07-25 21:04:25 UTC (rev 495) +++ trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py 2007-07-26 19:03:38 UTC (rev 496) @@ -103,7 +103,7 @@ def add_score(self, game): declarerWon, defenceWon = game.play.wonTrickCount() - score = game.getScore() + score = game.result.score textContract = render_contract(game.contract) textMade = str(declarerWon) @@ -339,13 +339,13 @@ if self.table.game.contract: self.scoreview.add_score(self.table.game) - declarerWon, defenceWon = self.table.game.play.wonTrickCount() - required = self.table.game.contract.bid.level.index + 7 - offset = declarerWon - required - score = self.table.game.getScore() + tricksMade = self.table.game.result.tricksMade + tricksRequired = self.table.game.contract.bid.level.index + 7 + offset = tricksMade - tricksRequired + score = self.table.game.result.score fields = {'contract': render_contract(self.table.game.contract), - 'offset': abs(offset) } + 'offset': abs(offset)} if offset > 0: if offset == 1: resultText = _('Contract %(contract)s made by 1 trick.') % fields This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |