|
From: <umg...@us...> - 2007-07-16 15:28:34
|
Revision: 483
http://svn.sourceforge.net/pybridge/?rev=483&view=rev
Author: umgangee
Date: 2007-07-16 08:28:30 -0700 (Mon, 16 Jul 2007)
Log Message:
-----------
Refactor Auction class (previously Bidding) as a subclass of list.
Modified Paths:
--------------
trunk/pybridge/pybridge/games/bridge/game.py
trunk/pybridge/pybridge/games/bridge/scoring.py
trunk/pybridge/pybridge/games/bridge/ui/window_bidbox.py
trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py
trunk/pybridge/pybridge/ui/vocabulary.py
trunk/pybridge/tests/bridge/test_game.py
trunk/pybridge/tests/monkey.py
Added Paths:
-----------
trunk/pybridge/pybridge/games/bridge/auction.py
trunk/pybridge/tests/bridge/test_auction.py
Removed Paths:
-------------
trunk/pybridge/pybridge/games/bridge/bidding.py
trunk/pybridge/tests/bridge/test_bidding.py
Copied: trunk/pybridge/pybridge/games/bridge/auction.py (from rev 480, trunk/pybridge/pybridge/games/bridge/bidding.py)
===================================================================
--- trunk/pybridge/pybridge/games/bridge/auction.py (rev 0)
+++ trunk/pybridge/pybridge/games/bridge/auction.py 2007-07-16 15:28:30 UTC (rev 483)
@@ -0,0 +1,194 @@
+# 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 call import Bid, Pass, Double, Redouble
+from symbols import Direction
+
+
+class Contract(object):
+ """Represents the result of an auction."""
+
+
+ def __init__(self, auction):
+ """
+ @param auction: a completed, but not passed out, auction.
+ @type auction: Auction
+ """
+ assert auction.isComplete() and not auction.isPassedOut()
+
+ # The contract is the last (and highest) bid.
+ self.bid = auction.currentBid
+
+ # The declarer is the first partner to bid the contract denomination.
+ caller = auction.whoCalled(self.bid)
+ partnership = (caller, Direction[(caller.index + 2) % 4])
+ # Determine which partner is declarer.
+ for call in auction:
+ if isinstance(call, Bid) and call.strain == self.bid.strain:
+ bidder = auction.whoCalled(call)
+ if bidder in partnership:
+ self.declarer = bidder
+ break
+
+ self.doubleBy, self.redoubleBy = None, None
+ if auction.currentDouble:
+ # The opponent who doubled the contract bid.
+ self.doubleBy = auction.whoCalled(auction.currentDouble)
+ if auction.currentRedouble:
+ # The partner who redoubled an opponent's double.
+ self.redoubleBy = auction.whoCalled(auction.currentRedouble)
+
+
+
+
+class Auction(list):
+ """The auction (bidding phase) of a game of bridge."""
+
+
+ def __init__(self, dealer):
+ """
+ @param dealer: who distributes the cards and makes the first call.
+ @type dealer: Direction
+ """
+ self.dealer = dealer
+ self.contract = None
+
+ currentBid = property(lambda self: self._getCurrentCall(Bid))
+ currentDouble = property(lambda self: self._getCurrentCall(Double))
+ currentRedouble = property(lambda self: self._getCurrentCall(Redouble))
+
+
+ def isComplete(self):
+ """Auction is complete if all players have called (ie. 4 or more calls)
+ and the last 3 calls are Pass calls.
+
+ @return: True if bidding is complete, False if not.
+ @rtype: bool
+ """
+ passes = len([c for c in self[-3:] if isinstance(c, Pass)])
+ return len(self) >= 4 and passes == 3
+
+
+ def isPassedOut(self):
+ """Auction is passed out if each player has passed on their first turn.
+ In this case, the bidding is complete, but no contract is established.
+
+ @return: True if bidding is passed out, False if not.
+ @rtype: bool
+ """
+ passes = len([call for call in self if isinstance(call, Pass)])
+ return len(self) == 4 and passes == 4
+
+
+ def makeCall(self, call):
+ """Appends call from position to the calls list.
+
+ Please note that call validity should be checked with isValidCall()
+ before calling this method!
+
+ @param call: a candidate call.
+ """
+ assert call not in self # Calls must be distinct.
+ assert self.isValidCall(call)
+
+ self.append(call)
+ if self.isComplete() and not self.isPassedOut():
+ self.contract = Contract(self)
+
+
+ def isValidCall(self, call, position=None):
+ """Check that call can be made, according to the rules of bidding.
+
+ @param call: the candidate call.
+ @param position: if specified, the position from which the call is made.
+ @return: True if call is available, False if not.
+ """
+ # The bidding must not be complete.
+ if self.isComplete():
+ return False
+
+ # Position's turn to play.
+ if position and position != self.whoseTurn():
+ return False
+
+ # A pass is always available.
+ if isinstance(call, Pass):
+ return True
+
+ # A bid must be greater than the current bid.
+ if isinstance(call, Bid):
+ return not self.currentBid or call > self.currentBid
+
+ # Doubles and redoubles only when a bid has been made.
+ if self.currentBid:
+ bidder = self.whoCalled(self.currentBid)
+
+ # A double must be made on the current bid from opponents,
+ # with has not been already doubled by partnership.
+ if isinstance(call, Double):
+ opposition = (Direction[(self.whoseTurn().index + 1) % 4],
+ Direction[(self.whoseTurn().index + 3) % 4])
+ return bidder in opposition and not self.currentDouble
+
+ # A redouble must be made on the current bid from partnership,
+ # which has been doubled by an opponent.
+ elif isinstance(call, Redouble):
+ partnership = (self.whoseTurn(),
+ Direction[(self.whoseTurn().index + 2) % 4])
+ return bidder in partnership and self.currentDouble \
+ and not self.currentRedouble
+
+ return False # Otherwise unavailable.
+
+
+ def whoCalled(self, call):
+ """Returns the position from which the specified call was made.
+
+ @param call: a call made in the auction.
+ @return: the position of the player who made call, or None.
+ """
+ if call in self:
+ return Direction[(self.dealer.index + self.index(call)) % 4]
+ return None # Call not made by any player.
+
+
+ def whoseTurn(self):
+ """Returns the position from which the next call should be made.
+
+ @return: the next position to make a call, or None.
+ """
+ if self.isComplete():
+ return
+ return Direction[(self.dealer.index + len(self)) % 4]
+
+
+ def _getCurrentCall(self, callclass):
+ """Returns most recent current call of specified class, or None.
+
+ @param callclass: call class, in (Bid, Pass, Double, Redouble).
+ @return: most recent call matching type, or None.
+ """
+ assert callclass in (Bid, Pass, Double, Redouble)
+
+ for call in reversed(self):
+ if isinstance(call, callclass):
+ return call
+ elif isinstance(call, Bid):
+ break # Bids cancel all preceding calls.
+ return None
+
Deleted: trunk/pybridge/pybridge/games/bridge/bidding.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/bidding.py 2007-07-13 17:56:13 UTC (rev 482)
+++ trunk/pybridge/pybridge/games/bridge/bidding.py 2007-07-16 15:28:30 UTC (rev 483)
@@ -1,201 +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 pybridge.network.error import GameError
-
-from call import Bid, Pass, Double, Redouble
-from symbols import Direction, Level, Strain
-
-
-class Bidding(object):
- """This class models the bidding (auction) phase of a game of bridge.
-
- A bidding session is a list of Call objects and the dealer.
- """
-
-
- def __init__(self, dealer):
- if dealer not in Direction:
- raise TypeError, "Expected Direction, got %s" % type(dealer)
- self.calls = []
- self.dealer = dealer
-
-
- def isComplete(self):
- """Bidding is complete if 4 or more calls have been made,
- and the last 3 calls are Pass calls.
-
- @return: True if bidding is complete, False if not.
- @rtype: bool
- """
- passes = len([c for c in self.calls[-3:] if isinstance(c, Pass)])
- return len(self.calls) >= 4 and passes == 3
-
-
- def isPassedOut(self):
- """Bidding is passed out if each player has passed on their first turn.
- In this case, the bidding is complete, but no contract is established.
-
- @return: True if bidding is passed out, False if not.
- @rtype: bool
- """
- passes = len([call for call in self.calls if isinstance(call, Pass)])
- return len(self.calls) == 4 and passes == 4
-
-
- def getContract(self):
- """When the bidding is complete, the contract is the last and highest
- bid, which may be doubled or redoubled.
-
- Hence, the contract represents the "final state" of the bidding.
-
- @return: a dict containing the keywords:
- @keyword bid: the last and highest bid.
- @keyword declarer: the partner who first bid the contract strain.
- @keyword doubleBy: the opponent who doubled the contract, or None.
- @keyword redoubleBy: the partner who redoubled an opponent's double
- on the contract, or None.
- """
- if self.isComplete() and not self.isPassedOut():
- bid = self.getCurrentCall(Bid)
- double = self.getCurrentCall(Double)
- redouble = self.getCurrentCall(Redouble)
- # Determine partnership.
- caller = self.whoCalled(bid)
- partnership = (caller, Direction[(caller.index + 2) % 4])
- # Determine declarer.
- for call in self.calls:
- if isinstance(call, Bid) and call.strain == bid.strain \
- and self.whoCalled(call) in partnership:
- declarerBid = call
- break
-
- return {'bid' : bid,
- 'declarer' : self.whoCalled(declarerBid),
- 'doubleBy' : double and self.whoCalled(double),
- 'redoubleBy' : redouble and self.whoCalled(redouble) }
- return None # Bidding passed out or not complete, no contract.
-
-
- def getCurrentCall(self, calltype):
- """Returns most recent current call of specified type, or None.
-
- @param calltype: call type, in (Bid, Pass, Double, Redouble).
- @return: most recent call matching type, or None.
- """
- if calltype not in (Bid, Pass, Double, Redouble):
- raise GameError, "Expected call type, got %s" % type(calltype)
-
- for call in self.calls[::-1]:
- if isinstance(call, calltype):
- return call
- elif isinstance(call, Bid):
- break
- return None
-
-
- def makeCall(self, call, player=None):
- """Appends call from player to the calls list.
-
- @param call: the Call object representing player's call.
- @param player: the player making call, or None.
- """
- if not isinstance(call, (Bid, Pass, Double, Redouble)):
- raise GameError, "Expected call type, got %s" % type(call)
- if not self.isValidCall(call, player):
- raise GameError, "Invalid call"
-
- self.calls.append(call)
-
-
- def isValidCall(self, call, player=None):
- """Check that specified call is available to player, with respect to
- current state of bidding. If specified, player's turn will be checked.
-
- @param call: the Call object to be tested for validity.
- @param player: the player attempting to call, or None.
- @return: True if call is available, False if not.
- """
- if not isinstance(call, (Bid, Pass, Double, Redouble)):
- raise GameError, "Expected call type, got %s" % type(call)
- assert player in Direction or player is None
-
- # The bidding must not be complete.
- if self.isComplete():
- return False
-
- # It must be player's turn to call.
- if player and player != self.whoseTurn():
- return False
-
- # Bidding is not complete; a pass is always available.
- elif isinstance(call, Pass):
- return True
-
- currentBid = self.getCurrentCall(Bid)
-
- # A bid must be greater than the current bid.
- if isinstance(call, Bid):
- return not currentBid or call > currentBid
-
- # Doubles and redoubles only when a bid has been made.
- if currentBid:
- bidder = self.whoCalled(currentBid)
-
- # A double must be made on the current bid from opponents,
- # with has not been already doubled by partnership.
- if isinstance(call, Double):
- opposition = (Direction[(self.whoseTurn().index + 1) % 4],
- Direction[(self.whoseTurn().index + 3) % 4])
- return bidder in opposition and not self.getCurrentCall(Double)
-
- # A redouble must be made on the current bid from partnership,
- # which has been doubled by an opponent.
- elif isinstance(call, Redouble):
- partnership = (self.whoseTurn(),
- Direction[(self.whoseTurn().index + 2) % 4])
- return bidder in partnership and self.getCurrentCall(Double) \
- and not self.getCurrentCall(Redouble)
-
- return False # Otherwise unavailable.
-
-
- def whoCalled(self, call):
- """Returns the player who made the specified call.
-
- @param call: a Call.
- @return: the player who made call, or False.
- """
- if not isinstance(call, (Bid, Pass, Double, Redouble)):
- raise GameError, "Expected call type, got %s" % type(call)
-
- if call in self.calls:
- return Direction[(self.calls.index(call) + self.dealer.index) % 4]
- return False # Call not made by any player.
-
-
- def whoseTurn(self):
- """Returns position of player who is next to make a call.
-
- @return: the current turn.
- @rtype: Direction
- """
- if self.isComplete():
- raise GameError, "Bidding complete"
- return Direction[(len(self.calls) + self.dealer.index) % 4]
-
Modified: trunk/pybridge/pybridge/games/bridge/game.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/game.py 2007-07-13 17:56:13 UTC (rev 482)
+++ trunk/pybridge/pybridge/games/bridge/game.py 2007-07-16 15:28:30 UTC (rev 483)
@@ -23,7 +23,7 @@
from pybridge.interfaces.observer import ISubject
from pybridge.network.error import GameError
-from bidding import Bidding
+from auction import Auction
from board import Board
from play import Trick, TrickPlay
from scoring import scoreDuplicate
@@ -34,7 +34,7 @@
class Bridge(object):
- """A bridge game models the bidding and play sequence.
+ """A bridge game sequences the auction and trick play.
The methods of this class comprise the interface of a state machine.
Clients should only use the class methods to interact with the game state.
@@ -59,18 +59,18 @@
def __init__(self):
self.listeners = []
- # TODO: are these necessary?
self.board = None
- self.bidding = None
- self.contract = None
- self.trumpSuit = None
+ self.auction = None
self.play = None
self.boardQueue = [] # Boards for successive games.
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)
+
# Implementation of ICardGame.
@@ -85,9 +85,7 @@
else: # Create a board.
self.board = Board()
self.board.nextDeal()
- self.bidding = Bidding(self.board['dealer']) # Start bidding.
- self.contract = None
- self.trumpSuit = None
+ self.auction = Auction(self.board['dealer']) # Start auction.
self.play = None
self.visibleHands.clear()
@@ -101,8 +99,8 @@
def inProgress(self):
if self.play is not None:
return not self.play.isComplete()
- elif self.bidding:
- return not self.bidding.isPassedOut()
+ elif self.auction is not None:
+ return not self.auction.isPassedOut()
else:
return False
@@ -120,8 +118,8 @@
visibleBoard['deal'] = self.visibleHands
state['board'] = visibleBoard
- if self.bidding:
- state['calls'] = self.bidding.calls
+ if self.auction:
+ state['auction'] = list(self.auction)
if self.play is not None:
state['play'] = [dict(trick) for trick in self.play]
@@ -132,15 +130,23 @@
if state.get('board'):
self.start(state['board'])
- for call in state.get('calls', []):
+ # Perform validation on game provided by server.
+ # Better to encounter errors earlier than later.
+
+ for call in state.get('auction', []):
turn = self.getTurn()
self.makeCall(call, 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)
+ # TODO: clean this up.
+ leader = self.getTurn()
+ for turn in Direction[leader.index:] + Direction[:leader.index]:
+ if turn in trick:
+ card = trick[turn]
+ if turn == self.play.dummy:
+ self.playCard(card, position=self.play.declarer)
+ else:
+ self.playCard(card, position=turn)
def updateState(self, event, *args, **kwargs):
@@ -200,7 +206,7 @@
def makeCall(self, call, player=None, position=None):
- """Make a call in the current bidding session.
+ """Make a call in the current auction.
This method expects to receive either a player argument or a position.
If both are given, the position argument is disregarded.
@@ -222,19 +228,19 @@
raise TypeError, "Expected Direction, got %s" % type(position)
# Validate call according to game state.
- if not self.bidding or self.bidding.isComplete():
- raise GameError, "No game in progress, or bidding complete"
+ if self.auction is None or self.auction.isComplete():
+ raise GameError, "No game in progress, or auction complete"
if self.getTurn() != position:
raise GameError, "Call made out of turn"
- if not self.bidding.isValidCall(call, position):
+ if not self.auction.isValidCall(call, position):
raise GameError, "Call cannot be made"
- self.bidding.makeCall(call, position)
+ self.auction.makeCall(call)
- if self.bidding.isComplete() and not self.bidding.isPassedOut():
- self.contract = self.bidding.getContract() # TODO: make a property
- self.trumpSuit = self.trumpMap[self.contract['bid'].strain]
- self.play = TrickPlay(self.contract['declarer'], self.trumpSuit)
+ if self.auction.isComplete() and not self.auction.isPassedOut():
+ declarer = self.auction.contract.declarer
+ trumpSuit = self.trumpMap[self.contract.bid.strain]
+ self.play = TrickPlay(declarer, trumpSuit)
self.notify('makeCall', call=call, position=position)
@@ -349,10 +355,10 @@
def getTurn(self):
if self.inProgress():
- if self.bidding.isComplete(): # In trick play.
+ if self.auction.isComplete(): # In trick play.
return self.play.whoseTurn()
- else: # Currently in the bidding.
- return self.bidding.whoseTurn()
+ else: # Currently in the auction.
+ return self.auction.whoseTurn()
else: # Not in game.
raise GameError, "No game in progress"
@@ -360,16 +366,15 @@
def getScore(self):
"""Returns the integer score value for declarer/dummy if:
- - bidding stage has been passed out, with no bids made.
- - play stage is complete.
+ - auction has been passed out, with no bids made.
+ - trick play is complete.
"""
- if self.inProgress() or self.bidding is None:
+ if self.inProgress() or self.auction is None:
raise GameError, "Game not complete"
- if self.bidding.isPassedOut():
+ if self.auction.isPassedOut():
return 0 # A passed out deal does not score.
- contract = self.bidding.getContract()
- declarer = contract['declarer']
+ declarer = self.contract.declarer
dummy = Direction[(declarer.index + 2) % 4]
if declarer in (Direction.North, Direction.South):
@@ -379,7 +384,7 @@
declarerWon, defenceWon = self.play.wonTrickCount()
- result = {'contract': contract, 'tricksMade': declarerWon,
+ result = {'contract': self.contract, 'tricksMade': declarerWon,
'vulnerable': vulnerable}
return scoreDuplicate(result)
Modified: trunk/pybridge/pybridge/games/bridge/scoring.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/scoring.py 2007-07-13 17:56:13 UTC (rev 482)
+++ trunk/pybridge/pybridge/games/bridge/scoring.py 2007-07-16 15:28:30 UTC (rev 483)
@@ -31,13 +31,13 @@
"""
score = 0
- isDoubled = result['contract']['doubleBy']
- isRedoubled = result['contract']['redoubleBy']
+ isDoubled = bool(result['contract'].doubleBy)
+ isRedoubled = bool(result['contract'].redoubleBy)
isVulnerable = result['vulnerable']
- contractLevel = result['contract']['bid'].level.index + 1
+ contractLevel = result['contract'].bid.level.index + 1
tricksMade = result['tricksMade']
- tricksRequired = result['contract']['bid'].level.index + 7
- trumpSuit = result['contract']['bid'].strain
+ tricksRequired = result['contract'].bid.level.index + 7
+ trumpSuit = result['contract'].bid.strain
if tricksMade >= tricksRequired:
# Contract fulfilled.
Modified: trunk/pybridge/pybridge/games/bridge/ui/window_bidbox.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/ui/window_bidbox.py 2007-07-13 17:56:13 UTC (rev 482)
+++ trunk/pybridge/pybridge/games/bridge/ui/window_bidbox.py 2007-07-16 15:28:30 UTC (rev 483)
@@ -26,7 +26,7 @@
class WindowBidbox(object):
- """The bidding box is presented to a player, during bidding.
+ """The bidding box is presented to the playing user, during an auction.
Each call (bid, pass, double or redouble) is displayed as a button.
When it is the player's turn to bid, a call is made by clicking the
@@ -104,9 +104,9 @@
def setTable(self, table, position):
- """Monitor the state of bidding in game at specified table.
+ """Monitor the state of auction in game at specified table.
- @param table: the BridgeGame for which to observe bidding session.
+ @param table: the BridgeGame for which to observe auction session.
@param:
"""
if self.table:
@@ -134,7 +134,7 @@
if self.position == self.table.game.getTurn():
self.window.set_property('sensitive', True)
for call, button in self.callButtons.items():
- isvalid = self.table.game.bidding.isValidCall(call)
+ isvalid = self.table.game.auction.isValidCall(call)
button.set_property('sensitive', isvalid)
else:
self.window.set_property('sensitive', False)
Modified: trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py 2007-07-13 17:56:13 UTC (rev 482)
+++ trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py 2007-07-16 15:28:30 UTC (rev 483)
@@ -107,8 +107,8 @@
textContract = render_contract(game.contract)
textMade = str(declarerWon)
- if game.contract['declarer'] in (Direction.North, Direction.South) and score > 0 \
- or game.contract['declarer'] in (Direction.East, Direction.West) and score < 0:
+ if game.contract.declarer in (Direction.North, Direction.South) and score > 0 \
+ or game.contract.declarer in (Direction.East, Direction.West) and score < 0:
textNS, textEW = str(abs(score)), ''
else:
textNS, textEW = '', str(abs(score))
@@ -170,7 +170,7 @@
def set_trickcount(self, game):
if game.play:
declarerWon, defenceWon = game.play.wonTrickCount()
- required = game.contract['bid'].level.index + 7
+ required = game.contract.bid.level.index + 7
declarerNeeds = max(0, required - declarerWon)
defenceNeeds = max(0, 13 + 1 - required - defenceWon)
else:
@@ -292,12 +292,12 @@
self.setTurnIndicator()
- for call in self.table.game.bidding.calls:
- position = self.table.game.bidding.whoCalled(call)
+ for call in self.table.game.auction:
+ position = self.table.game.auction.whoCalled(call)
self.biddingview.add_call(call, position)
- # If user is a player and bidding in progress, open bidding box.
- if self.player and not self.table.game.bidding.isComplete():
+ # If user is a player and auction in progress, open bidding box.
+ if self.player and not self.table.game.auction.isComplete():
bidbox = self.children.open(WindowBidbox, parent=self)
bidbox.setCallSelectHandler(self.on_call_selected)
bidbox.setTable(self.table, self.position)
@@ -340,7 +340,7 @@
self.scoreview.add_score(self.table.game)
declarerWon, defenceWon = self.table.game.play.wonTrickCount()
- required = self.table.game.contract['bid'].level.index + 7
+ required = self.table.game.contract.bid.level.index + 7
offset = declarerWon - required
score = self.table.game.getScore()
@@ -519,7 +519,7 @@
self.biddingview.add_call(call, position)
self.setTurnIndicator()
- if self.table.game.bidding.isComplete():
+ if self.table.game.auction.isComplete():
self.dashboard.set_contract(self.table.game)
if self.children.get(WindowBidbox): # If a player.
self.children.close(self.children[WindowBidbox])
@@ -578,8 +578,8 @@
d = self.player.callRemote('getHand')
d.addCallbacks(self.table.game.revealHand, self.errback,
callbackKeywords={'position' : self.position})
- # If game is running and bidding is active, open bidding box.
- if not self.table.game.bidding.isComplete():
+ # If game is running and auction is active, open bidding box.
+ if not self.table.game.auction.isComplete():
bidbox = self.children.open(WindowBidbox, parent=self)
bidbox.setCallSelectHandler(self.on_call_selected)
bidbox.setTable(self.table, self.position)
Modified: trunk/pybridge/pybridge/ui/vocabulary.py
===================================================================
--- trunk/pybridge/pybridge/ui/vocabulary.py 2007-07-13 17:56:13 UTC (rev 482)
+++ trunk/pybridge/pybridge/ui/vocabulary.py 2007-07-16 15:28:30 UTC (rev 483)
@@ -191,11 +191,11 @@
@return: a format string representing the contract.
@rtype: str
"""
- doubled = contract['redoubleBy'] and CALLTYPE_SYMBOLS[Call.Redouble] \
- or contract['doubleBy'] and CALLTYPE_SYMBOLS[Call.Double] or ''
+ doubled = contract.redoubleBy and CALLTYPE_SYMBOLS[Call.Redouble] \
+ or contract.doubleBy and CALLTYPE_SYMBOLS[Call.Double] or ''
- fields = {'bid': render_call(contract['bid']), 'doubled': doubled,
- 'declarer': DIRECTION_NAMES[contract['declarer']]}
+ fields = {'bid': render_call(contract.bid), 'doubled': doubled,
+ 'declarer': DIRECTION_NAMES[contract.declarer]}
if doubled:
return _('%(bid)s %(doubled)s by %(declarer)s') % fields
Copied: trunk/pybridge/tests/bridge/test_auction.py (from rev 480, trunk/pybridge/tests/bridge/test_bidding.py)
===================================================================
--- trunk/pybridge/tests/bridge/test_auction.py (rev 0)
+++ trunk/pybridge/tests/bridge/test_auction.py 2007-07-16 15:28:30 UTC (rev 483)
@@ -0,0 +1,113 @@
+import unittest
+
+from pybridge.games.bridge.auction import Auction
+from pybridge.games.bridge.call import Bid, Pass, Double, Redouble
+from pybridge.games.bridge.symbols import Direction, Level, Strain
+
+
+class TestAuction(unittest.TestCase):
+
+# bids = [Bid(l, s) for l in Level for s in Strain]
+
+ dealer = Direction.North
+ calls = [Pass(), Pass(), Bid(Level.One, Strain.Club), Double(),
+ Redouble(), Pass(), Pass(), Bid(Level.One, Strain.NoTrump),
+ Pass(), Bid(Level.Three, Strain.NoTrump), Pass(), Pass(),
+ Pass()]
+
+
+ def setUp(self):
+ self.auction = Auction(dealer=self.dealer)
+
+
+ def tearDown(self):
+ self.auction = None
+
+
+ def stepThroughAuction(self):
+ for call in self.calls:
+ yield call
+ self.auction.makeCall(call)
+
+
+ def testIsComplete(self):
+ """Checking isComplete() only when auction completed"""
+ s = self.stepThroughAuction()
+ self.assertEqual(self.auction.isComplete(), False)
+ try:
+ while s.next():
+ self.assertEqual(self.auction.isComplete(), False)
+ except StopIteration:
+ self.assertEqual(self.auction.isComplete(), True)
+
+
+ def testIsPassedOut(self):
+ """Checking isPassedOut() when all players pass"""
+ for call in [Pass(), Pass(), Pass(), Pass()]:
+ self.assertEqual(self.auction.isPassedOut(), False)
+ self.auction.makeCall(call)
+ self.assertEqual(self.auction.isPassedOut(), True)
+
+
+ def testCurrentCalls(self):
+ """Checking currentBid/currentDouble/currentRedouble values"""
+
+ def testCurrent(bid, double, redouble):
+ self.assertEqual(self.auction.currentBid, bid)
+ self.assertEqual(self.auction.currentDouble, double)
+ self.assertEqual(self.auction.currentRedouble, redouble)
+
+ testCurrent(None, None, None)
+
+ bid = Bid(Level.One, Strain.Diamond)
+ self.auction.makeCall(bid)
+ testCurrent(bid, None, None) # Ensure that currentBid is set.
+
+ double = Double()
+ self.auction.makeCall(double)
+ testCurrent(bid, double, None) # Ensure currentBid/Double set.
+
+ redouble = Redouble()
+ self.auction.makeCall(redouble)
+ testCurrent(bid, double, redouble) # Ensure currentBid/Double/Redouble set.
+
+ bid = Bid(Level.One, Strain.Spade)
+ self.auction.makeCall(bid)
+ testCurrent(bid, None, None) # Ensure currentBid set, Double/Redouble reset.
+
+
+ def testWhoseTurn(self):
+ """Checking whoseTurn() returns position on turn"""
+ s = self.stepThroughAuction()
+ try:
+ turn = self.dealer
+ while s.next():
+ self.assertEqual(self.auction.whoseTurn(), turn)
+ turn = Direction[(turn.index + 1) % 4] # Turn moves clockwise.
+ except StopIteration:
+ self.assertEqual(self.auction.whoseTurn(), None)
+
+
+ def testIsValidCall(self):
+ """Checking isValidCall() identifies valid and invalid calls."""
+ s = self.stepThroughAuction()
+ try:
+ while True:
+ candidate = s.next()
+ self.assert_(self.auction.isValidCall(candidate))
+ if self.auction.currentBid:
+ pass
+ #self.assert_(self.auction.isValidCall
+ except StopIteration:
+ pass
+
+
+
+def main():
+ suite = unittest.makeSuite(TestAuction)
+ unittest.TextTestRunner(verbosity=2).run(suite)
+
+
+if __name__ == '__main__':
+ main()
+
Deleted: trunk/pybridge/tests/bridge/test_bidding.py
===================================================================
--- trunk/pybridge/tests/bridge/test_bidding.py 2007-07-13 17:56:13 UTC (rev 482)
+++ trunk/pybridge/tests/bridge/test_bidding.py 2007-07-16 15:28:30 UTC (rev 483)
@@ -1,67 +0,0 @@
-import unittest
-import random
-
-from pybridge.games.bridge.bidding import Bidding
-from pybridge.games.bridge.call import Bid, Pass, Double, Redouble
-from pybridge.games.bridge.symbols import Direction, Level, Strain
-
-
-class TestBidding(unittest.TestCase):
-
-
- # Generate some bids.
- bids = [Bid(l, s) for l in Level for s in Strain]
-
-
- def setUp(self):
- dealer = random.choice(Direction)
- self.bidding = Bidding(dealer)
-
-
- def tearDown(self):
- self.bidding = None
-
-
- def testGetCurrentCall(self):
- """getCurrentCall"""
- for calltype in [Bid, Pass, Double, Redouble]:
- self.assertEqual(self.bidding.getCurrentCall(calltype), None)
-
- for call, calltype in [(Pass(), Pass), (Bid(Level.One, Strain.Club), Bid),
- (Double(), Double), (Redouble(), Redouble)]:
- self.assertEqual(self.bidding.getCurrentCall(calltype), None)
- self.bidding.makeCall(call)
- self.assertEqual(self.bidding.getCurrentCall(calltype), call)
-
- # A bid should clear types Pass, Double, Redouble.
- bid = Bid(Level.One, Strain.Diamond)
- self.bidding.makeCall(bid)
- self.assertEqual(self.bidding.getCurrentCall(Bid), bid)
- for calltype in [Pass, Double, Redouble]:
- self.assertEqual(self.bidding.getCurrentCall(calltype), None)
-
-
- def testWhoseTurn(self):
- """whoseTurn"""
- # Tests whoseTurn() before and after making calls.
- turn = Direction[self.bidding.dealer.index]
- for call in self.bids:
- self.assertEqual(self.bidding.whoseTurn(), turn)
- self.bidding.makeCall(call)
- turn = Direction[(turn.index + 1) % 4]
- self.assertEqual(self.bidding.whoseTurn(), turn)
-
-
- def testIsValidCall(self):
- """isValidCall"""
- pass
-
-
-def main():
- suite = unittest.makeSuite(TestBidding)
- unittest.TextTestRunner(verbosity=2).run(suite)
-
-
-if __name__ == '__main__':
- main()
-
Modified: trunk/pybridge/tests/bridge/test_game.py
===================================================================
--- trunk/pybridge/tests/bridge/test_game.py 2007-07-13 17:56:13 UTC (rev 482)
+++ trunk/pybridge/tests/bridge/test_game.py 2007-07-16 15:28:30 UTC (rev 483)
@@ -96,7 +96,7 @@
This does not attempt to test the integrity of Bidding and Play.
"""
- calls = [Bid(l, s) for l in Level for s in Strain] + [Pass()]*3
+ calls = [Bid(l, s) for l in Level for s in Strain] + [Pass(), Pass(), Pass()]
self.game.start(board)
for call in calls:
Modified: trunk/pybridge/tests/monkey.py
===================================================================
--- trunk/pybridge/tests/monkey.py 2007-07-13 17:56:13 UTC (rev 482)
+++ trunk/pybridge/tests/monkey.py 2007-07-16 15:28:30 UTC (rev 483)
@@ -221,7 +221,7 @@
def loop():
if self.table.game.inProgress():
- if not self.table.game.bidding.isComplete():
+ if not self.table.game.auction.isComplete():
self.chooseCall()
else:
self.chooseCard()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|