From: <umg...@us...> - 2006-08-16 13:06:53
|
Revision: 341 Author: umgangee Date: 2006-08-16 06:06:42 -0700 (Wed, 16 Aug 2006) ViewCVS: http://svn.sourceforge.net/pybridge/?rev=341&view=rev Log Message: ----------- Update doc files. Bump version number to 0.2.1. Modified Paths: -------------- trunk/pybridge/INSTALL trunk/pybridge/NEWS trunk/pybridge/README trunk/pybridge/pybridge/__init__.py Modified: trunk/pybridge/INSTALL =================================================================== --- trunk/pybridge/INSTALL 2006-08-16 12:45:36 UTC (rev 340) +++ trunk/pybridge/INSTALL 2006-08-16 13:06:42 UTC (rev 341) @@ -18,12 +18,9 @@ - Python (>= 2.3) - http://www.python.org/ - Twisted Core (>= 1.3) - http://twistedmatrix.com/trac/wiki/TwistedCore -- Zope Interface (>= 3.0) http://www.zope.org/Products/ZopeInterface -- GTK+ (>= 2.6) - http://www.gtk.org/ -- PyGTK (>= 2.6) - http://www.pygtk.org/ +- Zope Interface (>= 3.0) - http://www.zope.org/Products/ZopeInterface +- GTK+ (>= 2.6, >= 2.8 recommended) - http://www.gtk.org/ +- PyGTK (>= 2.6, >= 2.8 recommended) - http://www.pygtk.org/ (The GTK+ and PyGTK libraries are not necessary to run the standalone server.) - -Michael Banks (mi...@ba...), 14 August 2006 - Modified: trunk/pybridge/NEWS =================================================================== --- trunk/pybridge/NEWS 2006-08-16 12:45:36 UTC (rev 340) +++ trunk/pybridge/NEWS 2006-08-16 13:06:42 UTC (rev 341) @@ -1,7 +1,23 @@ +====================== +0.2.1 (16 August 2006) +====================== + +Bug fixes +========= + +- Fixed setup.py script to install source package and supporting files in the + standard /usr/ directories. + +- Updated pybridge.environment and bin/* scripts to work with both the source + and installation directory layouts. + + +====================== 0.2.0 (14 August 2006) ====================== -Features: +New Features +============ - Substantial rewrite of network code. Focus on splitting discrete services into separate components and making full use of Twisted's pb.Cacheable. @@ -19,6 +35,7 @@ - Initial support for internationalization and localization via gettext. +==================== 0.1.0 (19 July 2006) ==================== Modified: trunk/pybridge/README =================================================================== --- trunk/pybridge/README 2006-08-16 12:45:36 UTC (rev 340) +++ trunk/pybridge/README 2006-08-16 13:06:42 UTC (rev 341) @@ -1,4 +1,4 @@ -PyBridge 0.2.0 - a free online bridge game +PyBridge 0.2.1 - a free online bridge game http://pybridge.sourceforge.net/ http://sourceforge.net/projects/pybridge/ @@ -42,6 +42,3 @@ PyBridge is released under the GNU General Public License, version 2 or later. A copy of the license is provided in the COPYING file. - -Michael Banks (mi...@ba...), 14 August 2006 - Modified: trunk/pybridge/pybridge/__init__.py =================================================================== --- trunk/pybridge/pybridge/__init__.py 2006-08-16 12:45:36 UTC (rev 340) +++ trunk/pybridge/pybridge/__init__.py 2006-08-16 13:06:42 UTC (rev 341) @@ -1 +1 @@ -__version__ = '0.2.0' +__version__ = '0.2.1' This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-03-01 17:29:43
|
Revision: 360 http://svn.sourceforge.net/pybridge/?rev=360&view=rev Author: umgangee Date: 2007-03-01 09:29:38 -0800 (Thu, 01 Mar 2007) Log Message: ----------- Relocate symbol types to pybridge.bridge.symbols. Renamed "Seat" type to the more intuitive "Player". Modified Paths: -------------- trunk/pybridge/pybridge/bridge/bidding.py trunk/pybridge/pybridge/bridge/call.py trunk/pybridge/pybridge/bridge/card.py trunk/pybridge/pybridge/bridge/deck.py trunk/pybridge/pybridge/bridge/game.py trunk/pybridge/pybridge/bridge/playing.py trunk/pybridge/pybridge/bridge/scoring.py trunk/pybridge/pybridge/network/localbridge.py trunk/pybridge/pybridge/network/localtable.py trunk/pybridge/pybridge/network/remotebridge.py trunk/pybridge/pybridge/network/remotetable.py trunk/pybridge/pybridge/server/database.py trunk/pybridge/pybridge/ui/cardarea.py trunk/pybridge/pybridge/ui/window_bridgetable.py trunk/pybridge/tests/gumby.py trunk/pybridge/tests/test_bidding.py trunk/pybridge/tests/test_playing.py Modified: trunk/pybridge/pybridge/bridge/bidding.py =================================================================== --- trunk/pybridge/pybridge/bridge/bidding.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/bridge/bidding.py 2007-03-01 17:29:38 UTC (rev 360) @@ -1,5 +1,5 @@ # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# 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 @@ -10,19 +10,16 @@ # 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 Call, Bid, Pass, Double, Redouble +from symbols import Level, Player, Strain -from call import Level, Strain -from deck import Seat - - class Bidding: """This class models the bidding (auction) phase of a game of bridge. @@ -31,7 +28,7 @@ def __init__(self, dealer): - assert dealer in Seat + assert dealer in Player self.calls = [] self.dealer = dealer @@ -75,7 +72,7 @@ redouble = self.getCurrentCall(Redouble) # Determine declarer. partnership = (self.whoCalled(bid), \ - Seat[(self.whoCalled(bid).index + 2) % 4]) + Player[(self.whoCalled(bid).index + 2) % 4]) for call in self.calls: if isinstance(call, Bid) and call.strain == bid.strain \ and self.whoCalled(call) in partnership: @@ -125,8 +122,8 @@ @param player: the player attempting to call, or None. @return: True if call is available, False if not. """ - assert(isinstance(call, Call)) - assert(player in Seat or player is None) + assert isinstance(call, Call) + assert player in Player or player is None # The bidding must not be complete. if self.isComplete(): @@ -153,15 +150,15 @@ # A double must be made on the current bid from opponents, # with has not been already doubled by partnership. if isinstance(call, Double): - opposition = (Seat[(self.whoseTurn().index + 1) % 4], - Seat[(self.whoseTurn().index + 3) % 4]) + opposition = (Player[(self.whoseTurn().index + 1) % 4], + Player[(self.whoseTurn().index + 3) % 4]) return not self.getCurrentCall(Double) and bidder in opposition # 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(), - Seat[(self.whoseTurn().index + 2) % 4]) + Player[(self.whoseTurn().index + 2) % 4]) return self.getCurrentCall(Double) and bidder in partnership return False # Otherwise unavailable. @@ -175,7 +172,7 @@ """ assert isinstance(call, Call) if call in self.calls: - return Seat[(self.calls.index(call) + self.dealer.index) % 4] + return Player[(self.calls.index(call) + self.dealer.index) % 4] return False # Call not made by any player. @@ -184,6 +181,6 @@ @return: the player next to call. """ - player = Seat[(len(self.calls) + self.dealer.index) % 4] - return not(self.isComplete()) and player + player = Player[(len(self.calls) + self.dealer.index) % 4] + return not self.isComplete() and player Modified: trunk/pybridge/pybridge/bridge/call.py =================================================================== --- trunk/pybridge/pybridge/bridge/call.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/bridge/call.py 2007-03-01 17:29:38 UTC (rev 360) @@ -1,5 +1,5 @@ # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# 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 @@ -10,7 +10,7 @@ # 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. @@ -18,18 +18,11 @@ from twisted.spread import pb -from pybridge.enum import Enum +from symbols import Level, Strain -# Bid levels. -Level = Enum('One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven') - -# Bid strains, or denominations. -Strain = Enum('Club', 'Diamond', 'Heart', 'Spade', 'NoTrump') - - class Call(pb.Copyable, pb.RemoteCopy): - """Superclass for bids, passes, doubles and redoubles.""" + """Abstract class, inherited by Bid, Pass, Double and Redouble.""" class Bid(Call): @@ -44,12 +37,13 @@ def __cmp__(self, other): - assert issubclass(other.__class__, Call) + if not issubclass(other.__class__, Call): + raise TypeError, "Expected Call, got %s" % type(other) if isinstance(other, Bid): # Compare two bids. - selfVal = self.level.index*len(Strain) + self.strain.index - otherVal = other.level.index*len(Strain) + other.strain.index - return cmp(selfVal, otherVal) + selfIndex = self.level.index*len(Strain) + self.strain.index + otherIndex = other.level.index*len(Strain) + other.strain.index + return cmp(selfIndex, otherIndex) else: # Comparing non-bid calls returns true. return 1 Modified: trunk/pybridge/pybridge/bridge/card.py =================================================================== --- trunk/pybridge/pybridge/bridge/card.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/bridge/card.py 2007-03-01 17:29:38 UTC (rev 360) @@ -1,5 +1,5 @@ # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# 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 @@ -10,7 +10,7 @@ # 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. @@ -18,23 +18,15 @@ from twisted.spread import pb -from pybridge.enum import Enum +from symbols import Rank, Suit -# Card ranks. -Rank = Enum('Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', - 'Ten', 'Jack', 'Queen', 'King', 'Ace') - -# Card suits. -Suit = Enum('Club', 'Diamond', 'Heart', 'Spade') - - class Card(pb.Copyable, pb.RemoteCopy): """A card has a rank and a suit.""" + def __init__(self, rank, suit): - assert(rank in Rank) - assert(suit in Suit) + assert rank in Rank and suit in Suit self.rank = rank self.suit = suit @@ -51,7 +43,9 @@ Care must be taken when comparing cards of different suits. """ - assert isinstance(other, Card) + if not isinstance(other, Card): + raise TypeError, "Expected Card, got %s" % type(other) + selfIndex = self.suit.index*13 + self.rank.index otherIndex = other.suit.index*13 + other.rank.index return cmp(selfIndex, otherIndex) Modified: trunk/pybridge/pybridge/bridge/deck.py =================================================================== --- trunk/pybridge/pybridge/bridge/deck.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/bridge/deck.py 2007-03-01 17:29:38 UTC (rev 360) @@ -20,13 +20,10 @@ from operator import mul from random import shuffle -from card import Card, Rank, Suit +from card import Card +from symbols import Player, Rank, Suit -from pybridge.enum import Enum -Seat = Enum('North', 'East', 'South', 'West') # Clockwise. - - # See http://mail.python.org/pipermail/edu-sig/2001-May/001288.html for details. comb = lambda n, k: reduce(mul, range(n, n-k, -1)) / reduce(mul, range(1, k+1)) @@ -39,7 +36,7 @@ A hand is a collection of 13 cards from the deck. A deal is a distribution of all 52 cards to four hands. - A deal is represented as a dictionary, mapping Seat labels to lists (hands) + A deal is represented as a dictionary, mapping Player labels to lists (hands) of Card objects. There are exactly 52! / (13!)**4 (comb(52,13) * comb(39,13) * comb(26,13)) @@ -59,7 +56,7 @@ def isValidDeal(self, deal): """Checks that structure of deal conforms to requirements: - * 4-element dict, mapping Seat objects to hand lists. + * 4-element dict, mapping Player objects to hand lists. * Hand lists contain exactly 13 Card objects. * No card may be repeated in the same hand, or between hands. * The cards in hands may be in any order. @@ -70,17 +67,17 @@ return True # TODO - def dealRandom(self): # randomDeal + def randomDeal(self): """Shuffles the deck and generates a random deal of hands. @return: a deal dictionary. """ shuffle(self.cards) hands = {} - for seat in Seat: - hands[seat] = [] + for player in Player: + hands[player] = [] for index, card in enumerate(self.cards): - hands[Seat[index % len(Seat)]].append(card) + hands[Player[index % len(Player)]].append(card) for hand in hands.values(): hand.sort() return hands @@ -101,20 +98,20 @@ indexes = {} # For each hand, compute indexes of cards in cardSeq. - for seat in (Seat.North, Seat.East, Seat.South): - indexes[seat] = 0 - deal[seat].sort(reverse=False) + for player in (Player.North, Player.East, Player.South): + indexes[player] = 0 + deal[player].sort(reverse=False) # It is desirable to remove cards from cardSeq when adding their # indexes, instead of doing so in an extra step. # Removing cards backwards preserves the indexes of later cards. - for i, card in enumerate(deal[seat]): - indexes[seat] += comb(cardSeq.index(card), 13-i) + for i, card in enumerate(deal[player]): + indexes[player] += comb(cardSeq.index(card), 13-i) cardSeq.remove(card) # Deal index = (Nindex * Emax * Smax) + (Eindex * Smax) + Sindex - indexes[Seat.North] *= self.Emax * self.Smax - indexes[Seat.East] *= self.Smax - return sum(indexes.values()) + indexes[Player.North] *= self.Emax * self.Smax + indexes[Player.East] *= self.Smax + return long(sum(indexes.values())) def indexToDeal(self, num): @@ -133,28 +130,28 @@ deal = {} # Split index into hand indexes. - indexes = {Seat.North : (num / self.Smax) / self.Emax, - Seat.East : (num / self.Smax) % self.Emax, - Seat.South : (num % self.Smax) } + indexes = {Player.North : (num / self.Smax) / self.Emax, + Player.East : (num / self.Smax) % self.Emax, + Player.South : (num % self.Smax) } - for seat in (Seat.North, Seat.East, Seat.South): - deal[seat] = [] + for player in (Player.North, Player.East, Player.South): + deal[player] = [] for k in range(13, 0, -1): - # Find the largest n such that comb(n, k) <= indexes[seat]. + # Find the largest n such that comb(n, k) <= indexes[player]. n = k-1 # n < k implies comb(n, k) = 0 # comb(n+1, k) = # n-k = -1 => comb(n, k) * (n+1) # otherwise => (comb(n, k) * (n+1)) / (n+1 - k) - while comb(n+1, k) <= indexes[seat]: + while comb(n+1, k) <= indexes[player]: n += 1 # Remove card index from indices, add card to hand. - indexes[seat] -= comb(n, k) + indexes[player] -= comb(n, k) card = cardSeq[n] - deal[seat].append(card) + deal[player].append(card) cardSeq.remove(card) - - deal[Seat.West] = cardSeq # South has the remaining cards. + + deal[Player.West] = cardSeq # West has the remaining cards. return deal Modified: trunk/pybridge/pybridge/bridge/game.py =================================================================== --- trunk/pybridge/pybridge/bridge/game.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/bridge/game.py 2007-03-01 17:29:38 UTC (rev 360) @@ -1,5 +1,5 @@ # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# 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 @@ -10,7 +10,7 @@ # 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. @@ -18,19 +18,15 @@ from bidding import Bidding from playing import Playing +from symbols import Player, Suit -# Enumerations. -from card import Suit -from deck import Seat +class GameError(Exception): + pass -class GameError(Exception): pass - class Game: - """A bridge game models the bidding, playing, scoring sequence. - - """ + """A bridge game models the bidding, playing, scoring sequence.""" def __init__(self, dealer, deal, scoring, vulnNS, vulnEW): @@ -55,7 +51,7 @@ return self.bidding.isPassedOut() - def isHandVisible(self, seat, viewer): + def isHandVisible(self, player, viewer): """A hand is visible if one of the following conditions is met: 1. The hand is the viewer's own hand. @@ -63,23 +59,23 @@ 3. Bidding complete and hand is dummy's, and first card of first trick has been played. """ - return seat == viewer \ + return player == viewer \ or self.isComplete() \ - or (self.bidding.isComplete() and seat == self.playing.dummy and \ + or (self.bidding.isComplete() and player == self.playing.dummy and \ len(self.playing.getTrick(0)[1]) >= 1) - def makeCall(self, seat, call): - """Makes call from seat.""" + def makeCall(self, player, call): + """Makes call from player.""" if self.bidding.isComplete(): raise GameError('not in bidding') - if self.bidding.whoseTurn() is not seat: + if self.bidding.whoseTurn() is not player: raise GameError('out of turn') - elif not self.bidding.isValidCall(call, seat): + elif not self.bidding.isValidCall(call, player): raise GameError('invalid call') - self.bidding.makeCall(call, seat) + self.bidding.makeCall(call, player) # If bidding is complete, start playing. if self.bidding.isComplete() and not self.bidding.isPassedOut(): @@ -90,31 +86,31 @@ self.playing = Playing(contract['declarer'], trumpSuit) - def playCard(self, seat, card): - """Plays card from seat.""" + def playCard(self, player, card): + """Plays card from player.""" if not self.bidding.isComplete() or self.bidding.isPassedOut(): raise GameError('not in play') elif self.playing.isComplete(): raise GameError('not in play') - hand = self.deal[seat] - if self.playing.whoseTurn() is not seat: + hand = self.deal[player] + if self.playing.whoseTurn() is not player: raise GameError('out of turn') - elif not self.playing.isValidPlay(card, seat, hand): + elif not self.playing.isValidPlay(card, player, hand): raise GameError('invalid card') self.playing.playCard(card) - def getHand(self, seat, viewer=None): - """Returns the hand of player specified by seat. + def getHand(self, player, viewer=None): + """Returns the hand of specified player. If viewer player is specified, then the ability of viewer to "see" the hand will be examined. """ - if viewer and not self.isHandVisible(seat, viewer): + if viewer and not self.isHandVisible(player, viewer): raise GameError('hand not visible') - return self.deal[seat] + return self.deal[player] def getTrickCount(self): @@ -165,9 +161,9 @@ else: contract = self.bidding.getContract() declarer = contract['declarer'] - dummy = Seat[(declarer.index + 2) % 4] - vulnerable = (self.vulnNS and declarer in (Seat.North, Seat.South)) + \ - (self.vulnEW and declarer in (Seat.West, Seat.East)) + dummy = Player[(declarer.index + 2) % 4] + vulnerable = (self.vulnNS and declarer in (Player.North, Player.South)) + \ + (self.vulnEW and declarer in (Player.West, Player.East)) tricksMade = 0 # Count of tricks won by declarer or dummy. for index in range(len(self.playing.winners)): @@ -183,7 +179,7 @@ def whoseTurn(self): - """Returns the seat that is next to call or play card.""" + """Returns the player that is next to call or play card.""" if not self.isComplete(): if self.bidding.isComplete(): return self.playing.whoseTurn() Modified: trunk/pybridge/pybridge/bridge/playing.py =================================================================== --- trunk/pybridge/pybridge/bridge/playing.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/bridge/playing.py 2007-03-01 17:29:38 UTC (rev 360) @@ -1,5 +1,5 @@ # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# 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 @@ -10,19 +10,16 @@ # 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 Player, Suit -# Enumerations. -from card import Suit -from deck import Seat - class Playing: """This class models the trick-taking phase of a game of bridge. @@ -32,19 +29,19 @@ def __init__(self, declarer, trumps): - assert declarer in Seat + assert declarer in Player assert trumps in Suit or trumps is None # (None = No Trumps) self.trumps = trumps self.declarer = declarer - self.dummy = Seat[(declarer.index + 2) % 4] - self.lho = Seat[(declarer.index + 1) % 4] - self.rho = Seat[(declarer.index + 3) % 4] + self.dummy = Player[(declarer.index + 2) % 4] + self.lho = Player[(declarer.index + 1) % 4] + self.rho = Player[(declarer.index + 3) % 4] # Each trick corresponds to a cross-section of lists. self.played = {} - for seat in Seat: - self.played[seat] = [] + for player in Player: + self.played[player] = [] self.winners = [] # Winning player of each trick. @@ -63,17 +60,17 @@ @param: trick index, in range 0 to 12. @return: a (leader, cards) trick tuple. """ - assert(index in range(13)) + 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 seat in Seat: + for player in Player: # If length of list exceeds index value, player's card in trick. - if len(self.played[seat]) > index: - cards[seat] = self.played[seat][index] + if len(self.played[player]) > index: + cards[player] = self.played[player][index] return leader, cards @@ -116,7 +113,7 @@ """Card is playable if and only if: - Play session is not complete. - - Seat is on turn to play. + - Player is on turn to play. - Card exists in hand. - Card has not been previously played. @@ -174,7 +171,7 @@ 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 Seat[(leader.index + len(cards)) % 4] + return Player[(leader.index + len(cards)) % 4] return False Modified: trunk/pybridge/pybridge/bridge/scoring.py =================================================================== --- trunk/pybridge/pybridge/bridge/scoring.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/bridge/scoring.py 2007-03-01 17:29:38 UTC (rev 360) @@ -1,5 +1,5 @@ # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# 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 @@ -10,13 +10,13 @@ # 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 Strain +from symbols import Strain # There are undoubtedly many minor variations of the score values. @@ -24,7 +24,11 @@ def scoreDuplicate(result): - """Scoring algorithm for duplicate bridge.""" + """Scoring algorithm for duplicate bridge. + + This code includes the scoring values from: + http://www.ebu.co.uk/lawsandethics/the_laws/chapter8.asp + """ score = 0 isDoubled = result['contract']['doubleBy'] Modified: trunk/pybridge/pybridge/network/localbridge.py =================================================================== --- trunk/pybridge/pybridge/network/localbridge.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/network/localbridge.py 2007-03-01 17:29:38 UTC (rev 360) @@ -1,5 +1,5 @@ # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# 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 @@ -10,7 +10,7 @@ # 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. @@ -37,11 +37,9 @@ from pybridge.bridge.deck import Deck from pybridge.bridge.game import Game, GameError from pybridge.bridge.scoring import scoreDuplicate +from pybridge.bridge.symbols import Player -# Enumerations. -from pybridge.bridge.deck import Seat - class LocalBridgeTable(LocalTable): """A bridge table, implementing the IBridgeTable interface. @@ -57,12 +55,12 @@ self.dealer = None self.deck = Deck() self.game = None - self.players = dict.fromkeys(Seat, None) + self.players = dict.fromkeys(Player, None) self.scoring = scoreDuplicate self.handsSeen = {} - for seat in Seat: - self.handsSeen[seat] = [] + for player in Player: + self.handsSeen[player] = [] self.pendingDeals = [] # Queue of deals for successive games. @@ -83,13 +81,13 @@ if self.game.playing: state['game']['declarer'] = self.game.playing.declarer.key state['game']['played'] = {} - for seat, played in self.game.playing.played.items(): - state['game']['played'][seat.key] = played + for player, played in self.game.playing.played.items(): + state['game']['played'][player.key] = played # Add visible hands. state['game']['deal'] = {} - for seat, hand in self.game.deal.items(): - if self.game.isHandVisible(seat, viewer=None): - state['game']['deal'][seat.key] = hand + for player, hand in self.game.deal.items(): + if self.game.isHandVisible(player, viewer=None): + state['game']['deal'][player.key] = hand else: state['game'] = None @@ -118,7 +116,7 @@ raise DeniedRequest, 'Not a player' try: - self.game.makeCall(call=call, seat=position) + self.game.makeCall(call=call, player=position) except GameError, error: raise DeniedRequest, error @@ -142,7 +140,7 @@ raise DeniedRequest, 'Dummy cannot play cards' try: - self.game.playCard(card=card, seat=position) + self.game.playCard(card=card, player=position) except GameError, error: raise DeniedRequest, error @@ -164,9 +162,9 @@ if (self.game is None or self.game.isComplete()) \ and len([p for p in self.players.values() if p is None]) == 0: - deal = deal or self.deck.dealRandom() + deal = deal or self.deck.randomDeal() vulnNS, vulnEW = False, False - self.dealer = dealer or (self.dealer and Seat[(self.dealer.index + 1) % 4]) or Seat.North + self.dealer = dealer or (self.dealer and Player[(self.dealer.index + 1) % 4]) or Player.North self.game = Game(self.dealer, deal, self.scoring, vulnNS, vulnEW) self.updateObservers('gameStarted', dealer=self.dealer.key, vulnNS=vulnNS, vulnEW=vulnEW) @@ -198,7 +196,7 @@ """ # TODO: what about observers? for viewer, player in self.players.items(): - for seat in Seat: + for seat in Player: if seat not in self.handsSeen[viewer] and self.game.isHandVisible(seat, viewer): self.handsSeen[viewer].append(seat) hand = self.game.deal[seat] Modified: trunk/pybridge/pybridge/network/localtable.py =================================================================== --- trunk/pybridge/pybridge/network/localtable.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/network/localtable.py 2007-03-01 17:29:38 UTC (rev 360) @@ -1,5 +1,5 @@ # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# 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 @@ -10,7 +10,7 @@ # 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. @@ -23,10 +23,9 @@ from pybridge.interfaces.table import ITable from pybridge.network.error import DeniedRequest, IllegalRequest +from pybridge.bridge.symbols import Player # XX TODO: Try to avoid this. -from pybridge.bridge.deck import Seat # XX TODO: Try to avoid this. - class LocalTable(pb.Cacheable): """""" @@ -168,7 +167,7 @@ def view_addPlayer(self, user, position, player=None): - position = getattr(Seat, position) # XX + position = getattr(Player, position) # XX self.table.addPlayer(position, user) Modified: trunk/pybridge/pybridge/network/remotebridge.py =================================================================== --- trunk/pybridge/pybridge/network/remotebridge.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/network/remotebridge.py 2007-03-01 17:29:38 UTC (rev 360) @@ -1,5 +1,5 @@ # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# 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 @@ -10,7 +10,7 @@ # 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. @@ -35,11 +35,9 @@ # Bridge game. from pybridge.bridge.game import Game, GameError from pybridge.bridge.scoring import scoreDuplicate +from pybridge.bridge.symbols import Player -# Enumerations. -from pybridge.bridge.deck import Seat - class RemoteBridgeTable(RemoteTable): """A bridge table, implementing the IBridgeTable interface. @@ -54,36 +52,36 @@ self.dealer = None self.game = None - self.players = dict.fromkeys(Seat, None) + self.players = dict.fromkeys(Player, None) self.scoring = scoreDuplicate def setCopyableState(self, state): RemoteTable.setCopyableState(self, state) - # Convert seat strings to Seat enumeration values. + # Convert seat strings to Player enumeration values. players = {} for seat, player in self.players.items(): - players[getattr(Seat, seat)] = player + players[getattr(Player, seat)] = player self.players = players if state.get('game'): - self.dealer = getattr(Seat, state['game']['dealer']) # XX + self.dealer = getattr(Player, state['game']['dealer']) # XX deal = {} - for seat in Seat: - deal[seat] = state['game']['deal'].get(seat, []) + for player in Player: + deal[player] = state['game']['deal'].get(player, []) vulnNS, vulnEW = state['game']['vulnNS'], state['game']['vulnEW'] self.game = Game(self.dealer, deal, self.scoring, vulnNS, vulnEW) if state['game'].get('calls'): for call in state['game']['calls']: - seat = self.game.whoseTurn() - self.game.makeCall(call=call, seat=seat) + player = self.game.whoseTurn() + self.game.makeCall(call=call, player=player) if state['game'].get('played'): played = state['game']['played'] while sum([len(cards) for cards in played.values()]) > 0: - seat = self.game.whoseTurn() - card = played[seat.key].pop(0) - self.game.playCard(card=card, seat=seat) + player = self.game.whoseTurn() + card = played[player.key].pop(0) + self.game.playCard(card=card, player=player) def gameMakeCall(self, call, position=None): @@ -101,22 +99,6 @@ def gamePlayCard(self, card, position): d = self.master.callRemote('gamePlayCard', card) return d -# # Check that game is running, we are playing, -# # the position specified is on turn to play, -# # and the card specified is in player's hand. -# if self.game and self.position \ -# and self.game.whoseTurn() == position \ -# and self.game.playing.isValidPlay(card, position, self.game.deal[position]): -# d = self.master.callRemote('gamePlayCard', card) -# return d -# declarer = self.game.playing.declarer -# dummy = self.game.playing.dummy -# # Can play card from own hand, or from dummy's hand as declarer. -# seat = -# if self.game.whoseTurn() == self.position \ -# or (self.game.whoseTurn() == dummy and self.position == declarer): -# d = self.master.callRemote('gamePlayCard', card) -# return d def requestNextGame(self, ready=True, player=None): @@ -128,9 +110,9 @@ def observe_gameStarted(self, dealer, vulnNS, vulnEW): - dealer = getattr(Seat, dealer) # XX + dealer = getattr(Player, dealer) # XX self.dealer = dealer - deal = dict.fromkeys(Seat, []) # Unknown hands. + deal = dict.fromkeys(Player, []) # Unknown hands. self.game = Game(dealer, deal, self.scoring, vulnNS, vulnEW) self.eventHandler.gameStarted(self, dealer, vulnNS, vulnEW) @@ -140,19 +122,19 @@ def observe_gameCallMade(self, call, position): - position = getattr(Seat, position) # XX - self.game.makeCall(call=call, seat=position) + position = getattr(Player, position) # XX + self.game.makeCall(call=call, player=position) self.eventHandler.gameCallMade(self, call, position) def observe_gameCardPlayed(self, card, position): - position = getattr(Seat, position) # XX - self.game.playCard(card=card, seat=position) + position = getattr(Player, position) # XX + self.game.playCard(card=card, player=position) self.eventHandler.gameCardPlayed(self, card, position) def observe_gameHandRevealed(self, hand, position): - position = getattr(Seat, position) # XX + position = getattr(Player, position) # XX self.game.deal[position] = hand self.eventHandler.gameHandRevealed(self, hand, position) Modified: trunk/pybridge/pybridge/network/remotetable.py =================================================================== --- trunk/pybridge/pybridge/network/remotetable.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/network/remotetable.py 2007-03-01 17:29:38 UTC (rev 360) @@ -1,5 +1,5 @@ # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# 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 @@ -10,7 +10,7 @@ # 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. @@ -21,10 +21,9 @@ from pybridge.interfaces.table import ITable from pybridge.network.error import DeniedRequest, IllegalRequest +from pybridge.bridge.symbols import Player # XX TODO: Try to avoid this. -from pybridge.bridge.deck import Seat # XX TODO: Try to avoid this. - class RemoteTable(pb.RemoteCache): """ @@ -87,13 +86,13 @@ def observe_playerAdded(self, player, position): - position = getattr(Seat, position) # XX + position = getattr(Player, position) # XX self.players[position] = player self.eventHandler.playerAdded(self, player, position) def observe_playerRemoved(self, player, position): - position = getattr(Seat, position) # XX + position = getattr(Player, position) # XX self.players[position] = None self.eventHandler.playerRemoved(self, player, position) Modified: trunk/pybridge/pybridge/server/database.py =================================================================== --- trunk/pybridge/pybridge/server/database.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/server/database.py 2007-03-01 17:29:38 UTC (rev 360) @@ -22,7 +22,7 @@ from sqlobject.inheritance import InheritableSQLObject import pybridge.environment as env -from pybridge.bridge.deck import Seat +from pybridge.bridge.symbols import Player backend = "sqlite" @@ -119,10 +119,9 @@ """Captures game attributes specific to bridge games. """ - board = ForeignKey('BridgeBoard') - declarer = EnumCol(enumValues=list(Seat)) + declarer = EnumCol(enumValues=list(Player)) # contract = trickCount = IntCol() # Number of tricks won by score = IntCol() @@ -145,6 +144,6 @@ """ deal = IntCol() - dealer = EnumCol(enumValues=list(Seat)) + dealer = EnumCol(enumValues=list(Player)) vuln = EnumCol(enumValues=['none', 'ns', 'ew', 'all']) Modified: trunk/pybridge/pybridge/ui/cardarea.py =================================================================== --- trunk/pybridge/pybridge/ui/cardarea.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/ui/cardarea.py 2007-03-01 17:29:38 UTC (rev 360) @@ -24,8 +24,8 @@ import pybridge.environment as env from canvas import CairoCanvas -from pybridge.bridge.card import Card, Rank, Suit -from pybridge.bridge.deck import Seat +from pybridge.bridge.card import Card +from pybridge.bridge.symbols import Player, Rank, Suit # The order in which card graphics are expected in card mask. CARD_MASK_RANKS = [Rank.Ace, Rank.Two, Rank.Three, Rank.Four, Rank.Five, @@ -60,11 +60,11 @@ super(CardArea, self).__init__() # Initialise parent. # To receive card clicked events, override this with external method. - self.on_card_clicked = lambda card, seat: True + self.on_card_clicked = lambda card, player: True self.hands = {} self.trick = None - self.set_seat_mapping(Seat.South) + self.set_player_mapping(Player.South) self.connect('button_press_event', self.button_press) self.add_events(gtk.gdk.BUTTON_PRESS_MASK) @@ -91,15 +91,14 @@ context.reset_clip() - def set_hand(self, hand, seat, facedown=False, omit=[]): - """Sets the hand of player at seat. - Draws representation of cards in hand to context. + def set_hand(self, hand, player, facedown=False, omit=[]): + """Sets the hand of player. Draws cards in hand to context. The hand is buffered into an ImageSurface, since hands change infrequently and multiple calls to draw_card() are expensive. @param hand: a list of Card objects. - @param seat: a member of Seat. + @param player: a member of Player. @param facedown: if True, cards are drawn face-down. @param omit: a list of elements of hand not to draw. """ @@ -107,7 +106,7 @@ # TODO: coords should be dict (card : (pos_x, pos_y)), but this breaks when hashing. def get_coords_for_hand(): coords = [] - if seat in (self.TOP, self.BOTTOM): + if player in (self.TOP, self.BOTTOM): pos_y = 0 if facedown is True: # Draw cards in one continuous row. for index, card in enumerate(hand): @@ -124,14 +123,14 @@ else: # LEFT or RIGHT. if facedown is True: # Wrap cards to a 4x4 grid. for index, card in enumerate(hand): - adjust = seat is self.RIGHT and index == 12 and 3 + adjust = player is self.RIGHT and index == 12 and 3 pos_x = ((index % 4) + adjust) * self.spacing_x pos_y = (index / 4) * self.spacing_y coords.append((card, pos_x, pos_y)) else: longest = max([len(cards) for cards in suits.values()]) for index, card in enumerate(hand): - adjust = seat is self.RIGHT and longest - len(suits[card.suit]) + adjust = player is self.RIGHT and longest - len(suits[card.suit]) pos_x = (suits[card.suit].index(card) + adjust) * self.spacing_x pos_y = RED_BLACK.index(card.suit) * self.spacing_y coords.append((card, pos_x, pos_y)) @@ -150,7 +149,7 @@ for suit in RED_BLACK: hand.extend(suits[suit]) - saved = self.hands.get(seat) + saved = self.hands.get(player) if saved and saved['hand'] == hand: # If hand has been set previously, do not recalculate coords. coords = saved['coords'] @@ -169,24 +168,24 @@ self.draw_card(context, pos_x, pos_y, card) # Save - self.hands[seat] = {'hand' : hand, 'visible' : visible, - 'surface' : surface, 'coords' : coords, } + self.hands[player] = {'hand' : hand, 'visible' : visible, + 'surface' : surface, 'coords' : coords, } - id = 'hand-%s' % seat # Identifier for this item. + id = 'hand-%s' % player # Identifier for this item. if id in self.items: self.update_item(id, source=surface) else: xy = {self.TOP : (0.5, 0.15), self.BOTTOM : (0.5, 0.85), self.LEFT : (0.15, 0.5), self.RIGHT : (0.85, 0.5), } - self.add_item(id, surface, xy[seat], 0) + self.add_item(id, surface, xy[player], 0) - def set_player_name(self, seat, name=None): + def set_player_name(self, player, name=None): """ @param name: the name of the player, or None. """ - id = 'player-%s' % seat + id = 'player-%s' % player if name is None or id in self.items: self.remove_item(id) return @@ -216,19 +215,19 @@ else: xy = {self.TOP : (0.5, 0.15), self.BOTTOM : (0.5, 0.85), self.LEFT : (0.15, 0.6), self.RIGHT : (0.85, 0.6), } - self.add_item(id, surface, xy[seat], 2) + self.add_item(id, surface, xy[player], 2) - def set_seat_mapping(self, focus=Seat.South): - """Sets the mapping between seats at table and positions of hands. + def set_player_mapping(self, focus=Player.South): + """Sets the mapping between players at table and positions of hands. - @param focus: the Seat to be drawn "closest" to the observer. + @param focus: the Player to be drawn "closest" to the observer. """ - # Assumes Seat elements are ordered clockwise from North. - order = Seat[focus.index:] + Seat[:focus.index] - for seat, attr in zip(order, ('BOTTOM', 'LEFT', 'TOP', 'RIGHT')): - setattr(self, attr, seat) - # TODO: set seat labels. + # Assumes Player elements are ordered clockwise from North. + order = Player[focus.index:] + Player[:focus.index] + for player, attr in zip(order, ('BOTTOM', 'LEFT', 'TOP', 'RIGHT')): + setattr(self, attr, player) + # TODO: set player labels. def set_trick(self, trick): @@ -241,18 +240,18 @@ self.LEFT : (0.425, 0.5), self.RIGHT : (0.575, 0.5), } if trick: - # The order of play is the leader, then clockwise around Seat. + # The order of play is the leader, then clockwise around Player. leader = trick[0] - order = Seat[leader.index:] + Seat[:leader.index] - for i, seat in enumerate(order): - id = 'trick-%s' % seat - old_card = self.trick and self.trick[1].get(seat) or None - new_card = trick[1].get(seat) + order = Player[leader.index:] + Player[:leader.index] + for i, player in enumerate(order): + id = 'trick-%s' % player + old_card = self.trick and self.trick[1].get(player) or None + new_card = trick[1].get(player) # If old card matches new card, take no action. if old_card is None and new_card is not None: surface, context = self.new_surface(self.card_width, self.card_height) self.draw_card(context, 0, 0, new_card) - self.add_item(id, surface, xy[seat], z_index=i+1) + self.add_item(id, surface, xy[player], z_index=i+1) elif new_card is None and old_card is not None: self.remove_item(id) elif old_card != new_card: @@ -261,8 +260,8 @@ self.update_item(id, surface, z_index=i+1) elif self.trick: # Remove all cards from previous trick. - for seat in self.trick[1]: - self.remove_item('trick-%s' % seat) + for player in self.trick[1]: + self.remove_item('trick-%s' % player) self.trick = trick # Save trick and return. @@ -273,14 +272,14 @@ The hand of the player on turn is drawn opaque; the other hands are drawn translucent. - @param turn: a member of Seat, or None. + @param turn: a member of Player, or None. """ if turn is None: return - for seat in Seat: - opacity = (seat is turn) and 1 or 0.5 - self.update_item('hand-%s' % seat, opacity=opacity) + for player in Player: + opacity = (player is turn) and 1 or 0.5 + self.update_item('hand-%s' % player, opacity=opacity) def button_press(self, widget, event): @@ -289,10 +288,10 @@ found_hand = False # Determine the hand which was clicked. - for seat in self.hands: - card_coords = self.hands[seat]['coords'] - surface = self.hands[seat]['surface'] - hand_x, hand_y = self.items['hand-%s' % seat]['area'][0:2] + for player in self.hands: + card_coords = self.hands[player]['coords'] + surface = self.hands[player]['surface'] + hand_x, hand_y = self.items['hand-%s' % player]['area'][0:2] if (hand_x <= event.x <= hand_x + surface.get_width()) and \ (hand_y <= event.y <= hand_y + surface.get_height()): found_hand = True @@ -302,11 +301,11 @@ # Determine the card in hand which was clicked. pos_x, pos_y = event.x - hand_x, event.y - hand_y # Iterate through visible cards backwards. - for i, card in self.hands[seat]['visible'][::-1]: + for i, card in self.hands[player]['visible'][::-1]: x, y = card_coords[i][1:] if (x <= pos_x <= x + self.card_width) and \ (y <= pos_y <= y + self.card_height): - self.on_card_clicked(card, seat) + self.on_card_clicked(card, player) break return True # Expected to return True. Modified: trunk/pybridge/pybridge/ui/window_bridgetable.py =================================================================== --- trunk/pybridge/pybridge/ui/window_bridgetable.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/pybridge/ui/window_bridgetable.py 2007-03-01 17:29:38 UTC (rev 360) @@ -1,5 +1,5 @@ # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# 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 @@ -10,7 +10,7 @@ # 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. @@ -24,13 +24,9 @@ import utils from pybridge.bridge.call import Bid, Pass, Double, Redouble +from pybridge.bridge.symbols import Level, Strain, Player, Rank -# Enumerations. -from pybridge.bridge.call import Level, Strain -from pybridge.bridge.card import Rank -from pybridge.bridge.deck import Seat - # Translatable symbols for elements of bridge. CALLTYPE_SYMBOLS = {Pass : _('pass'), Double : _('dbl'), Redouble : _('rdbl') } @@ -51,8 +47,8 @@ Strain.Spade : u'\N{BLACK SPADE SUIT}', Strain.NoTrump : u'NT', } -SEAT_SYMBOLS = {Seat.North : _('North'), Seat.East : _('East'), - Seat.South : _('South'), Seat.West : _('West') } +SEAT_SYMBOLS = {Player.North : _('North'), Player.East : _('East'), + Player.South : _('South'), Player.West : _('West') } class WindowBridgetable(GladeWrapper): @@ -72,11 +68,11 @@ # Set up "Take Seat" menu. items = {} menu = gtk.Menu() - for seat in Seat: - items[seat] = gtk.MenuItem(SEAT_SYMBOLS[seat], True) - items[seat].connect('activate', self.on_seat_activated, seat) - items[seat].show() - menu.append(items[seat]) + for player in Player: + items[player] = gtk.MenuItem(SEAT_SYMBOLS[player], True) + items[player].connect('activate', self.on_seat_activated, player) + items[player].show() + menu.append(items[player]) self.takeseat.set_menu(menu) self.takeseat_items = items @@ -92,8 +88,8 @@ # Set up bidding history and column display. self.call_store = gtk.ListStore(str, str, str, str) self.biddingview.set_model(self.call_store) - for index, seat in enumerate(Seat): - title = SEAT_SYMBOLS[seat] + for index, player in enumerate(Player): + title = SEAT_SYMBOLS[player] column = gtk.TreeViewColumn(str(title), renderer, text=index) column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) column.set_fixed_width(50) @@ -102,8 +98,8 @@ # Set up trick history and column display. self.trick_store = gtk.ListStore(str, str, str, str) self.trickview.set_model(self.trick_store) - for index, seat in enumerate(Seat): - title = SEAT_SYMBOLS[seat] + for index, player in enumerate(Player): + title = SEAT_SYMBOLS[player] column = gtk.TreeViewColumn(str(title), renderer, text=index) column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) column.set_fixed_width(50) @@ -152,8 +148,8 @@ self.setTurnIndicator() for call in table.game.bidding.calls: - seat = table.game.bidding.whoCalled(call) - self.addCall(call, seat) + player = table.game.bidding.whoCalled(call) + self.addCall(call, player) self.setDealer(table.dealer) self.setVuln(table.game.vulnNS, table.game.vulnEW) @@ -165,9 +161,9 @@ # If playing, set trick counts. if table.game.playing: - for seat, cards in table.game.playing.played.items(): + for player, cards in table.game.playing.played.items(): for card in cards: - self.addCard(card, seat) + self.addCard(card, player) self.setTrickCount(table.game.getTrickCount()) # If user is a player and bidding in progress, open bidding box. @@ -180,7 +176,7 @@ self.takeseat_items[seat].set_property('sensitive', available) if player: self.event_playerAdded(table, player, seat) - else: # Seat vacant. + else: # Player vacant. self.event_playerRemoved(table, None, seat) # Initialise observer listing. @@ -238,8 +234,8 @@ def addScore(self, contract, made, score): textContract = self.getContractFormat(contract) textMade = '%s' % made - if contract['declarer'] in (Seat.North, Seat.South) and score > 0 \ - or contract['declarer'] in (Seat.East, Seat.West) and score < 0: + if contract['declarer'] in (Player.North, Player.South) and score > 0 \ + or contract['declarer'] in (Player.East, Player.West) and score < 0: textNS, textEW = '%s' % abs(score), '' else: textNS, textEW = '', '%s' % abs(score) @@ -374,7 +370,7 @@ widget.set_property('sensitive', True) # Reset player label. label = getattr(self, 'label_%s' % position.key.lower()) - label.set_markup('<i>%s</i>' % _('Seat vacant')) + label.set_markup('<i>%s</i>' % _('Player vacant')) # If we are not seated, ensure Take Seat is enabled. if not table.seated: Modified: trunk/pybridge/tests/gumby.py =================================================================== --- trunk/pybridge/tests/gumby.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/tests/gumby.py 2007-03-01 17:29:38 UTC (rev 360) @@ -1,7 +1,7 @@ #!/usr/bin/env python # PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 PyBridge Project. +# 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 @@ -12,7 +12,7 @@ # 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. @@ -47,8 +47,7 @@ from pybridge.network.client import client from pybridge.bridge.call import Bid, Double, Redouble, Pass -from pybridge.bridge.call import Level, Strain -from pybridge.bridge.deck import Seat +from pybridge.bridge.symbols import Level, Strain # Give the bot some "personality". Modified: trunk/pybridge/tests/test_bidding.py =================================================================== --- trunk/pybridge/tests/test_bidding.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/tests/test_bidding.py 2007-03-01 17:29:38 UTC (rev 360) @@ -3,12 +3,9 @@ from pybridge.bridge.bidding import Bidding from pybridge.bridge.call import Bid, Pass, Double, Redouble +from pybridge.bridge.symbols import Level, Player, Strain -# Enumerations. -from pybridge.bridge.call import Level, Strain -from pybridge.bridge.deck import Seat - class TestBidding(unittest.TestCase): @@ -16,9 +13,8 @@ bids = [Bid(l, s) for l in Level for s in Strain] - def setUp(self): - dealer = random.choice(Seat) + dealer = random.choice(Player) self.bidding = Bidding(dealer) @@ -30,13 +26,13 @@ """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) @@ -48,11 +44,11 @@ def testWhoseTurn(self): """whoseTurn""" # Tests whoseTurn() before and after making calls. - turn = Seat[self.bidding.dealer.index] + turn = Player[self.bidding.dealer.index] for call in self.bids: self.assertEqual(self.bidding.whoseTurn(), turn) self.bidding.makeCall(call) - turn = Seat[(turn.index + 1) % 4] + turn = Player[(turn.index + 1) % 4] self.assertEqual(self.bidding.whoseTurn(), turn) @@ -61,8 +57,6 @@ pass - - def main(): suite = unittest.makeSuite(TestBidding) unittest.TextTestRunner(verbosity=2).run(suite) Modified: trunk/pybridge/tests/test_playing.py =================================================================== --- trunk/pybridge/tests/test_playing.py 2007-03-01 17:22:17 UTC (rev 359) +++ trunk/pybridge/tests/test_playing.py 2007-03-01 17:29:38 UTC (rev 360) @@ -4,19 +4,16 @@ from pybridge.bridge.card import Card from pybridge.bridge.deck import Deck from pybridge.bridge.playing import Playing +from pybridge.bridge.symbols import Player, Rank, Suit -# Enumerations. -from pybridge.bridge.card import Suit -from pybridge.bridge.deck import Seat - class TestPlaying(unittest.TestCase): def setUp(self): - decl... [truncated message content] |
From: <umg...@us...> - 2007-04-06 18:02:34
|
Revision: 403 http://svn.sourceforge.net/pybridge/?rev=403&view=rev Author: umgangee Date: 2007-04-06 11:02:26 -0700 (Fri, 06 Apr 2007) Log Message: ----------- Tweaks to window_main Glade file, remove unused dialog_gameresult. Modified Paths: -------------- trunk/pybridge/glade/pybridge.glade Removed Paths: ------------- trunk/pybridge/pybridge/ui/dialog_gameresult.py Modified: trunk/pybridge/glade/pybridge.glade =================================================================== --- trunk/pybridge/glade/pybridge.glade 2007-04-06 17:58:59 UTC (rev 402) +++ trunk/pybridge/glade/pybridge.glade 2007-04-06 18:02:26 UTC (rev 403) @@ -15,13 +15,49 @@ <child> <widget class="GtkMenuItem" id="menu_server"> <property name="visible">True</property> - <property name="label" translatable="yes">_File</property> + <property name="label" translatable="yes">_Server</property> <property name="use_underline">True</property> <child> <widget class="GtkMenu" id="menu_server_menu"> <child> + <widget class="GtkImageMenuItem" id="menu_connect"> + <property name="visible">True</property> + <property name="label" translatable="yes">_Connect to Server...</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_connect_activate"/> + <child internal-child="image"> + <widget class="GtkImage" id="image342"> + <property name="visible">True</property> + <property name="stock">gtk-connect</property> + <property name="icon_size">1</property> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkImageMenuItem" id="menu_disconnect"> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">_Disconnect</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_disconnect_activate"/> + <child internal-child="image"> + <widget class="GtkImage" id="menu-item-image6"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="stock">gtk-disconnect</property> + </widget> + </child> + </widget> + </child> + <child> + <widget class="GtkSeparatorMenuItem" id="menu_separator"> + <property name="visible">True</property> + </widget> + </child> + <child> <widget class="GtkImageMenuItem" id="menu_newtable"> <property name="visible">True</property> + <property name="sensitive">False</property> <property name="label" translatable="yes">_New Table...</property> <property name="use_underline">True</property> <signal name="activate" handler="on_newtable_clicked"/> @@ -56,21 +92,6 @@ </widget> </child> <child> - <widget class="GtkImageMenuItem" id="menu_disconnect"> - <property name="visible">True</property> - <property name="label" translatable="yes">_Disconnect</property> - <property name="use_underline">True</property> - <signal name="activate" handler="on_disconnect_activate"/> - <child internal-child="image"> - <widget class="GtkImage" id="image342"> - <property name="visible">True</property> - <property name="stock">gtk-disconnect</property> - <property name="icon_size">1</property> - </widget> - </child> - </widget> - </child> - <child> <widget class="GtkImageMenuItem" id="menu_quit"> <property name="visible">True</property> <property name="label">gtk-quit</property> @@ -159,6 +180,7 @@ <child> <widget class="GtkNotebook" id="notebook"> <property name="visible">True</property> + <property name="sensitive">False</property> <property name="can_focus">True</property> <signal name="switch_page" handler="on_notebook_switch_page"/> <child> @@ -193,6 +215,7 @@ <child> <widget class="GtkButton" id="newtable"> <property name="visible">True</property> + <property name="sensitive">False</property> <property name="can_focus">True</property> <signal name="clicked" handler="on_newtable_clicked"/> <child> @@ -1418,10 +1441,10 @@ <property name="visible">True</property> <property name="can_focus">True</property> <property name="can_default">True</property> - <property name="label">gtk-quit</property> + <property name="label">gtk-cancel</property> <property name="use_stock">True</property> <property name="response_id">-6</property> - <signal name="clicked" handler="on_quit_clicked"/> + <signal name="clicked" handler="on_cancel_clicked"/> </widget> </child> <child> @@ -1545,148 +1568,6 @@ </widget> </child> </widget> - <widget class="GtkDialog" id="dialog_gameresult"> - <property name="visible">True</property> - <property name="title" translatable="yes">Game Result</property> - <property name="resizable">False</property> - <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> - <property name="skip_taskbar_hint">True</property> - <signal name="delete_event" handler="on_dialog_gameresult_delete_event"/> - <child internal-child="vbox"> - <widget class="GtkVBox" id="dialog-vbox4"> - <property name="visible">True</property> - <child> - <widget class="GtkHBox" id="hbox16"> - <property name="visible">True</property> - <child> - <widget class="GtkImage" id="image_information"> - <property name="visible">True</property> - <property name="stock">gtk-dialog-info</property> - <property name="icon_size">6</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="padding">12</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_result"> - <property name="visible">True</property> - </widget> - <packing> - <property name="position">1</property> - </packing> - </child> - </widget> - <packing> - <property name="padding">12</property> - <property name="pack_type">GTK_PACK_END</property> - <property name="position">2</property> - </packing> - </child> - <child internal-child="action_area"> - <widget class="GtkHButtonBox" id="dialog-action_area4"> - <property name="visible">True</property> - <property name="layout_style">GTK_BUTTONBOX_END</property> - <child> - <widget class="GtkButton" id="button_leavetable"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <signal name="clicked" handler="on_leavetable_clicked"/> - <child> - <widget class="GtkAlignment" id="alignment17"> - <property name="visible">True</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <child> - <widget class="GtkHBox" id="hbox14"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <widget class="GtkImage" id="image166"> - <property name="visible">True</property> - <property name="stock">gtk-quit</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label21"> - <property name="visible">True</property> - <property name="label" translatable="yes">Leave Table</property> - <property name="use_underline">True</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </widget> - </child> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkButton" id="button_nextdeal"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="can_default">True</property> - <signal name="clicked" handler="on_nextdeal_clicked"/> - <child> - <widget class="GtkAlignment" id="alignment18"> - <property name="visible">True</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <child> - <widget class="GtkHBox" id="hbox15"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <widget class="GtkImage" id="image167"> - <property name="visible">True</property> - <property name="stock">gtk-ok</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label22"> - <property name="visible">True</property> - <property name="label" translatable="yes">Next Deal</property> - <property name="use_underline">True</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </widget> - </child> - </widget> - </child> - </widget> - <packing> - <property name="position">1</property> - </packing> - </child> - </widget> - <packing> - <property name="expand">False</property> - <property name="pack_type">GTK_PACK_END</property> - </packing> - </child> - </widget> - </child> - </widget> <widget class="GtkWindow" id="window_bridgetable"> <property name="visible">True</property> <property name="title" translatable="yes">Table</property> @@ -1706,6 +1587,10 @@ <property name="stock_id">gtk-media-play</property> <signal name="clicked" handler="on_takeseat_clicked"/> </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> </child> <child> <widget class="GtkToolButton" id="leaveseat"> @@ -1716,11 +1601,18 @@ <property name="stock_id">gtk-media-stop</property> <signal name="clicked" handler="on_leaveseat_clicked"/> </widget> + <packing> + <property name="expand">False</property> + </packing> </child> <child> <widget class="GtkSeparatorToolItem" id="separatortoolitem2"> <property name="visible">True</property> </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> </child> <child> <widget class="GtkToggleToolButton" id="toggle_gameinfo"> @@ -1731,6 +1623,9 @@ <property name="active">True</property> <signal name="clicked" handler="on_toggle_gameinfo_clicked"/> </widget> + <packing> + <property name="expand">False</property> + </packing> </child> <child> <widget class="GtkToggleToolButton" id="toggle_chat"> @@ -1741,6 +1636,9 @@ <property name="active">True</property> <signal name="clicked" handler="on_toggle_chat_clicked"/> </widget> + <packing> + <property name="expand">False</property> + </packing> </child> <child> <widget class="GtkToggleToolButton" id="toggle_fullscreen"> @@ -1748,11 +1646,18 @@ <property name="stock_id">gtk-fullscreen</property> <signal name="clicked" handler="on_toggle_fullscreen_clicked"/> </widget> + <packing> + <property name="expand">False</property> + </packing> </child> <child> <widget class="GtkSeparatorToolItem" id="separatortoolitem1"> <property name="visible">True</property> </widget> + <packing> + <property name="expand">False</property> + <property name="homogeneous">False</property> + </packing> </child> <child> <widget class="GtkToolButton" id="leavetable"> @@ -1762,6 +1667,9 @@ <property name="stock_id">gtk-quit</property> <signal name="clicked" handler="on_leavetable_clicked"/> </widget> + <packing> + <property name="expand">False</property> + </packing> </child> </widget> <packing> Deleted: trunk/pybridge/pybridge/ui/dialog_gameresult.py =================================================================== --- trunk/pybridge/pybridge/ui/dialog_gameresult.py 2007-04-06 17:58:59 UTC (rev 402) +++ trunk/pybridge/pybridge/ui/dialog_gameresult.py 2007-04-06 18:02:26 UTC (rev 403) @@ -1,49 +0,0 @@ -# PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 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. - - -import gtk -from wrapper import GladeWrapper - - -class DialogGameresult(GladeWrapper): - - glade_name = 'dialog_gameresult' - - - def new(self): - pass - - - def setup(self, message): - self.label_result.set_text(message) - - -# Signal handlers. - - - def on_leavetable_clicked(self, widget, *args): - self.parent.on_leavetable_clicked(widget, *args) - - - def on_nextdeal_clicked(self, widget, *args): - self.parent.children.close(self.glade_name) - - - def on_dialog_gameresult_delete_event(self, widget, *args): - return True # Stops window deletion taking place. - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-04-08 20:17:04
|
Revision: 408 http://svn.sourceforge.net/pybridge/?rev=408&view=rev Author: umgangee Date: 2007-04-08 13:17:02 -0700 (Sun, 08 Apr 2007) Log Message: ----------- Remove unused IBridgeTable and IServerState interfaces. Modified Paths: -------------- trunk/pybridge/tests/monkey.py Removed Paths: ------------- trunk/pybridge/pybridge/interfaces/bridgetable.py trunk/pybridge/pybridge/interfaces/serverstate.py Deleted: trunk/pybridge/pybridge/interfaces/bridgetable.py =================================================================== --- trunk/pybridge/pybridge/interfaces/bridgetable.py 2007-04-07 20:56:08 UTC (rev 407) +++ trunk/pybridge/pybridge/interfaces/bridgetable.py 2007-04-08 20:17:02 UTC (rev 408) @@ -1,91 +0,0 @@ -# PyBridge -- online contract bridge made easy. -# Copyright (C) 2004-2006 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 zope.interface import Interface - - -class IBridgeTable(Interface): - """IBridgeTable defines methods specific to bridge tables.""" - - - def gameMakeCall(self, call, position): - """Add call from player (at position) to bidding.""" - - - def gamePlayCard(self, card, position): - """Add card from player (at position) to current trick.""" - - - def requestNextGame(self, ready, player): - """Indicates that player is ready (or not ready) to commence next game.""" - - - - -class IBridgeTableEvents(Interface): - """IBridgeTableEvents defines the events which may be generated by IBridgeTable. - - """ - - - def gameStarted(self, table, dealer, vulnNS, vulnEW): - """Called when a game is started. - - @param table: reference to table. - @param dealer: - @param vulnNS: - @param vulnEW: - """ - - - def gameFinished(self, table): - """Called when a game is finished. - - A game is finished if trick play is complete, or bidding is passed out, - or it has been aborted. - - @param table: reference to table. - """ - - - def gameCallMade(self, table, call, position): - """Called when a player (at position) makes a call. - - @param table: reference to table. - @param call: - @param position: - """ - - - def gameCardPlayed(self, table, card, position): - """Called when a player (at position) plays a card. - - @param table: reference to table. - @param card: - @param position: - """ - - - def gameHandRevealed(self, table, hand, position): - """Called when a player's hand becomes visible. - - @param table: reference to table. - @param hand: - @param position: - """ - Deleted: trunk/pybridge/pybridge/interfaces/serverstate.py =================================================================== --- trunk/pybridge/pybridge/interfaces/serverstate.py 2007-04-07 20:56:08 UTC (rev 407) +++ trunk/pybridge/pybridge/interfaces/serverstate.py 2007-04-08 20:17:02 UTC (rev 408) @@ -1,28 +0,0 @@ - - -from zope.interface import Interface - - -class IServerEvents(Interface): - """IServerEvents defines methods to track the state of a server.""" - - - def connectionLost(self, connector, reason): - """Called when connection to a server is lost.""" - - - def tableOpened(self, table): - """Called when a new table is opened.""" - - - def tableClosed(self, table): - """Called when an existing table is closed.""" - - - def userLoggedIn(self, user): - """Called when a user has connected and logged in.""" - - - def userLoggedOut(self, user): - """Called when a user has logged out.""" - Modified: trunk/pybridge/tests/monkey.py =================================================================== --- trunk/pybridge/tests/monkey.py 2007-04-07 20:56:08 UTC (rev 407) +++ trunk/pybridge/tests/monkey.py 2007-04-08 20:17:02 UTC (rev 408) @@ -41,7 +41,6 @@ from zope.interface import implements from pybridge.interfaces.observer import IListener -from pybridge.interfaces.serverstate import IServerEvents from pybridge.network.client import NetworkClient from pybridge.network.error import GameError @@ -86,9 +85,7 @@ http://folklore.org/StoryView.py?project=Macintosh&story=Monkey_Lives.txt """ - implements(IServerEvents) - def __init__(self, client): self.client = client self.table = None # RemoteTable. @@ -115,7 +112,7 @@ def joinTable(self): print "Looking for a table to join..." - if self.client.tablesAvailable.get('Monkey'): + if self.client.tableRoster.get('Monkey'): d = self.client.joinTable('Monkey') else: d = self.client.joinTable('Monkey', host=True) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-06-16 13:21:42
|
Revision: 421 http://svn.sourceforge.net/pybridge/?rev=421&view=rev Author: umgangee Date: 2007-06-16 06:21:39 -0700 (Sat, 16 Jun 2007) Log Message: ----------- Preliminary work on the Preferences dialog. Modified Paths: -------------- trunk/pybridge/glade/pybridge.glade trunk/pybridge/pybridge/ui/dialog_preferences.py Modified: trunk/pybridge/glade/pybridge.glade =================================================================== --- trunk/pybridge/glade/pybridge.glade 2007-06-14 16:22:05 UTC (rev 420) +++ trunk/pybridge/glade/pybridge.glade 2007-06-16 13:21:39 UTC (rev 421) @@ -1411,7 +1411,7 @@ </widget> </child> <child> - <widget class="GtkLabel" id="label62"> + <widget class="GtkLabel" id="label_useraccount"> <property name="visible">True</property> <property name="label" translatable="yes"><b>User Account</b></property> <property name="use_markup">True</property> @@ -1948,200 +1948,6 @@ </packing> </child> <child> - <widget class="GtkExpander" id="expander_players"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <child> - <widget class="GtkTable" id="table5"> - <property name="visible">True</property> - <property name="n_rows">4</property> - <property name="n_columns">3</property> - <property name="column_spacing">4</property> - <property name="row_spacing">2</property> - <child> - <widget class="GtkLabel" id="label_west"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">4</property> - <property name="label" translatable="yes"><i>Vacant</i></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_south"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">4</property> - <property name="label" translatable="yes"><i>Vacant</i></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_north"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">4</property> - <property name="label" translatable="yes"><i>Vacant</i></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_east"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="xpad">4</property> - <property name="label" translatable="yes"><i>Vacant</i></property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkImage" id="image321"> - <property name="visible">True</property> - <property name="stock">gtk-go-back</property> - </widget> - <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkImage" id="image320"> - <property name="visible">True</property> - <property name="stock">gtk-go-down</property> - </widget> - <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkImage" id="image319"> - <property name="visible">True</property> - <property name="stock">gtk-go-forward</property> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkImage" id="image318"> - <property name="visible">True</property> - <property name="stock">gtk-go-up</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options">GTK_FILL</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label49"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">West:</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label48"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">South:</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label47"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">East:</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label46"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">North:</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - </widget> - </child> - <child> - <widget class="GtkLabel" id="label45"> - <property name="visible">True</property> - <property name="label" translatable="yes">Players</property> - </widget> - <packing> - <property name="type">label_item</property> - </packing> - </child> - </widget> - <packing> - <property name="expand">False</property> - <property name="position">4</property> - </packing> - </child> - <child> <widget class="GtkExpander" id="expander_observers"> <property name="visible">True</property> <property name="can_focus">True</property> @@ -2174,7 +1980,7 @@ </widget> <packing> <property name="expand">False</property> - <property name="position">5</property> + <property name="position">4</property> </packing> </child> </widget> @@ -2278,7 +2084,7 @@ <widget class="GtkDialog" id="dialog_preferences"> <property name="visible">True</property> <property name="border_width">5</property> - <property name="title" translatable="yes">Preferences</property> + <property name="title" translatable="yes">PyBridge Preferences</property> <property name="resizable">False</property> <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> <property name="has_separator">False</property> @@ -2296,92 +2102,166 @@ <property name="border_width">4</property> <property name="spacing">8</property> <child> - <widget class="GtkFrame" id="frame3"> + <widget class="GtkTable" id="table3"> <property name="visible">True</property> - <property name="label_xalign">0</property> - <property name="shadow_type">GTK_SHADOW_NONE</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="n_rows">2</property> + <property name="n_columns">2</property> + <property name="column_spacing">8</property> + <property name="row_spacing">4</property> <child> - <widget class="GtkAlignment" id="alignment1"> + <widget class="GtkLabel" id="label_cardstyle"> <property name="visible">True</property> - <property name="left_padding">12</property> - <child> - <widget class="GtkComboBox" id="carddeck"> - <property name="visible">True</property> - <signal name="changed" handler="on_carddeck_changed"/> - </widget> - </child> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Card Style:</property> </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> </child> <child> - <widget class="GtkLabel" id="label1"> + <widget class="GtkLabel" id="label_background"> <property name="visible">True</property> - <property name="label" translatable="yes"><b>Card Deck</b></property> - <property name="use_markup">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Background:</property> </widget> <packing> - <property name="type">label_item</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> </packing> </child> + <child> + <widget class="GtkComboBox" id="cardstyle"> + <property name="width_request">160</property> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="changed" handler="on_cardstyle_changed"/> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <widget class="GtkFileChooserButton" id="background"> + <property name="width_request">160</property> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="selection_changed" handler="on_background_changed"/> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> </widget> + <packing> + <property name="expand">False</property> + </packing> </child> <child> - <widget class="GtkFrame" id="frame4"> + <widget class="GtkFrame" id="frame5"> <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="label_xalign">0</property> <property name="shadow_type">GTK_SHADOW_NONE</property> <child> - <widget class="GtkAlignment" id="alignment2"> + <widget class="GtkAlignment" id="alignment3"> <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="left_padding">12</property> <child> - <widget class="GtkTable" id="table3"> + <widget class="GtkHBox" id="hbox1"> <property name="visible">True</property> - <property name="n_rows">2</property> - <property name="n_columns">2</property> - <property name="column_spacing">9</property> - <property name="row_spacing">4</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="spacing">4</property> + <property name="homogeneous">True</property> <child> - <widget class="GtkFileChooserButton" id="filechooserbutton1"> + <widget class="GtkButton" id="button_clubcolour"> <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="clicked" handler="on_suitcolour_clicked"/> + <child> + <widget class="GtkLabel" id="label_clubcolour"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes"><span color='#000000' size='xx-large'>♣</span></property> + <property name="use_markup">True</property> + </widget> + </child> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> + <property name="expand">False</property> </packing> </child> <child> - <widget class="GtkColorButton" id="colorbutton1"> + <widget class="GtkButton" id="button_diamondcolour"> <property name="visible">True</property> - <property name="color">#000000000000</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="clicked" handler="on_suitcolour_clicked"/> + <child> + <widget class="GtkLabel" id="label_diamondcolour"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes"><span color='#ff0000' size='xx-large'>♦</span></property> + <property name="use_markup">True</property> + </widget> + </child> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> + <property name="expand">False</property> + <property name="position">1</property> </packing> </child> <child> - <widget class="GtkRadioButton" id="radio_image"> + <widget class="GtkButton" id="button_heartcolour"> <property name="visible">True</property> - <property name="label" translatable="yes">Image</property> - <property name="draw_indicator">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="clicked" handler="on_suitcolour_clicked"/> + <child> + <widget class="GtkLabel" id="label_heartcolour"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes"><span color='#ff0000' size='xx-large'>♥</span></property> + <property name="use_markup">True</property> + </widget> + </child> </widget> <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> + <property name="expand">False</property> + <property name="position">2</property> </packing> </child> <child> - <widget class="GtkRadioButton" id="radio_colour"> + <widget class="GtkButton" id="button_spadecolour"> <property name="visible">True</property> - <property name="label" translatable="yes">Colour</property> - <property name="draw_indicator">True</property> - <property name="group">radio_image</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="clicked" handler="on_suitcolour_clicked"/> + <child> + <widget class="GtkLabel" id="label_spadecolour"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes"><span color='#000000' size='xx-large'>♠</span></property> + <property name="use_markup">True</property> + </widget> + </child> </widget> <packing> - <property name="x_options">GTK_FILL</property> + <property name="expand">False</property> + <property name="position">3</property> </packing> </child> </widget> @@ -2389,9 +2269,10 @@ </widget> </child> <child> - <widget class="GtkLabel" id="label2"> + <widget class="GtkLabel" id="label_suitcolours"> <property name="visible">True</property> - <property name="label" translatable="yes"><b>Background</b></property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Colours for Suits</property> <property name="use_markup">True</property> </widget> <packing> @@ -2400,6 +2281,7 @@ </child> </widget> <packing> + <property name="expand">False</property> <property name="position">1</property> </packing> </child> @@ -2409,9 +2291,9 @@ </packing> </child> <child> - <widget class="GtkLabel" id="label_style"> + <widget class="GtkLabel" id="label_gamedisplay"> <property name="visible">True</property> - <property name="label" translatable="yes">Style</property> + <property name="label" translatable="yes">Game Display</property> </widget> <packing> <property name="type">tab</property> Modified: trunk/pybridge/pybridge/ui/dialog_preferences.py =================================================================== --- trunk/pybridge/pybridge/ui/dialog_preferences.py 2007-06-14 16:22:05 UTC (rev 420) +++ trunk/pybridge/pybridge/ui/dialog_preferences.py 2007-06-16 13:21:39 UTC (rev 421) @@ -22,41 +22,95 @@ import pybridge.environment as env from manager import wm +from pybridge.ui import settings +from pybridge.bridge.symbols import Suit +SUIT_NAMES = {Suit.Club: _("Club"), Suit.Diamond: _("Diamond"), + Suit.Heart: _("Heart"), Suit.Spade: _("Spade") } + +SUIT_SYMBOLS = {Suit.Club: u'\N{BLACK CLUB SUIT}', + Suit.Diamond: u'\N{BLACK DIAMOND SUIT}', + Suit.Heart: u'\N{BLACK HEART SUIT}', + Suit.Spade: u'\N{BLACK SPADE SUIT}' } + +SUIT_LABEL_TEMPLATE = "<span color=\'%s\' size=\'xx-large\'>%s</span>" + + class DialogPreferences(GladeWrapper): glade_name = 'dialog_preferences' - def new(self): + def setUp(self): + # Allow user to select only image files for background. + filter_pixbufs = gtk.FileFilter() + filter_pixbufs.add_pixbuf_formats() + filter_pixbufs.set_name(_("Image files")) + self.background.add_filter(filter_pixbufs) + + # Build a list of card decks from which the user may choose. + # (The user is prevented from selecting an arbitary image.) model = gtk.ListStore(str) - self.carddeck.set_model(model) + self.cardstyle.set_model(model) cell = gtk.CellRendererText() - self.carddeck.pack_start(cell, True) - self.carddeck.add_attribute(cell, 'text', 0) + self.cardstyle.pack_start(cell, True) + self.cardstyle.add_attribute(cell, 'text', 0) + + activedeck = settings.appearance.get('deck', 'bonded.png') # Populate list of card decks. path = env.find_pixmap('') for filename in os.listdir(path): if filename.endswith('.png'): iter = model.append((filename,)) - if filename == 'bonded.png': - self.carddeck.set_active_iter(iter) + if filename == activedeck: + self.cardstyle.set_active_iter(iter) # Signal handlers. - def on_carddeck_changed(self, widget, *args): - print "changed" + def on_cardstyle_changed(self, widget, *args): + print "cardstyle changed" + def on_background_changed(self, widget, *args): + print "background changed" + + + def on_suitcolour_clicked(self, widget, *args): + # Get symbol in Suit corresponding to button clicked. + suit_buttons = {self.button_clubcolour: Suit.Club, + self.button_diamondcolour: Suit.Diamond, + self.button_heartcolour: Suit.Heart, + self.button_spadecolour: Suit.Spade } + suit = suit_buttons[widget] + + title = _("Select colour for %s symbol" % SUIT_NAMES[suit]) + dialog = gtk.ColorSelectionDialog(title) + dialog.colorsel.set_current_color(gtk.gdk.color_parse('#888888')) + + def dialog_response_cb(dialog, response_id): + if response_id == gtk.RESPONSE_OK: + colour = dialog.colorsel.get_current_color() + + # Set button label to colour selected by user. + label = widget.get_children()[0] + hexrep = gtk.color_selection_palette_to_string([colour]) + label.set_markup(SUIT_LABEL_TEMPLATE % (hexrep, SUIT_SYMBOLS[suit])) + + dialog.destroy() + + dialog.connect('response', dialog_response_cb) + #dialog.show() + dialog.run() + + def on_cancelbutton_clicked(self, widget, *args): - print "cancel" wm.close(self) def on_okbutton_clicked(self, widget, *args): - print "ok" + print "SAVE SETTINGS" wm.close(self) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-06-22 15:50:40
|
Revision: 445 http://svn.sourceforge.net/pybridge/?rev=445&view=rev Author: umgangee Date: 2007-06-22 08:50:38 -0700 (Fri, 22 Jun 2007) Log Message: ----------- Enhance documentation for 0.3.0. Modified Paths: -------------- trunk/pybridge/INSTALL trunk/pybridge/README Modified: trunk/pybridge/INSTALL =================================================================== --- trunk/pybridge/INSTALL 2007-06-22 15:42:48 UTC (rev 444) +++ trunk/pybridge/INSTALL 2007-06-22 15:50:38 UTC (rev 445) @@ -2,25 +2,52 @@ =================== If you want to install PyBridge, change to the directory where you unpacked the -tarball, then type (as root): +source tarball, then type (as root): python setup.py install -Alternatively, you can run PyBridge from the extracted tarball. Change to the -PyBridge "bin/" directory, then type "./pybridge" to run the client, or -"./pybridge-server" to run the game server. +We recommend that, if your distribution provides PyBridge packages, you should +install from packages. Packages are available for Debian GNU/Linux and its +derivatives (including Ubuntu) thanks to David Watson <dw...@de...>. +Alternatively, you can run PyBridge from the extracted tarball archive. Change +to the PyBridge "bin/" directory, then type "./pybridge" to run the graphical +client, or "./pybridge-server" to run the standalone server. + Requirements ============ -You'll need the following software installed to run PyBridge: +You will need the following software installed to run PyBridge: -- Python (>= 2.3) - http://www.python.org/ -- Twisted Core (>= 1.3) - http://twistedmatrix.com/trac/wiki/TwistedCore -- Zope Interface (>= 3.0) - http://www.zope.org/Products/ZopeInterface -- GTK+ (>= 2.6, >= 2.8 recommended) - http://www.gtk.org/ -- PyGTK (>= 2.6, >= 2.8 recommended) - http://www.pygtk.org/ + - Python (>= 2.4) - http://www.python.org/ + - Twisted Core (>= 2.0) - http://twistedmatrix.com/trac/wiki/TwistedCore + - Zope Interface (>= 3.0) - http://www.zope.org/Products/ZopeInterface -(The GTK+ and PyGTK libraries are not necessary to run the standalone server.) +To run the PyBridge client, the following software is also required: + + - GTK+ (>= 2.8) - http://www.gtk.org/ + - PyGTK (>= 2.8) - http://www.pygtk.org/ + - Cairo (>= 1.0) - http://cairographics.org/ + - PyCairo (>= 1.0) - http://cairographics.org/pycairo/ + - ConfigObj (>= 4.0) -http://www.voidspace.org.uk/python/configobj.html + + +To run the standalone PyBridge server, the following software is also required: + + - SQLObject (>= 0.7) - http://www.sqlobject.org/ + - A database server compatible with SQLObject: see "Configuring the Server". + + +Configuring the Server +====================== + +By default, the standalone server creates and uses a SQLite database in the +~/.pybridge/ directory. This is suitable for hosting LAN games, but if you wish +to operate a high-load PyBridge server on the Internet, it may be necessary +to switch to an external RDBMS, such as MySQL or PostgreSQL. + +To change the database settings, edit the ~/.pybridge/server.cfg file. The +fields to change are documented in the pybridge/server/config.py module. + Modified: trunk/pybridge/README =================================================================== --- trunk/pybridge/README 2007-06-22 15:42:48 UTC (rev 444) +++ trunk/pybridge/README 2007-06-22 15:50:38 UTC (rev 445) @@ -1,13 +1,16 @@ -PyBridge 0.2.1 - a free online bridge game +PyBridge 0.3.0 - a free online bridge game http://pybridge.sourceforge.net/ http://sourceforge.net/projects/pybridge/ +About PyBridge +============== + PyBridge allows you to play the card game of (contract) bridge, with human players, over the Internet or a local network. There are many Web resources for learning to play bridge. A good starting point -is the Wikipedia: see http://en.wikipedia.org/wiki/Contract_bridge . +is the Wikipedia: see http://en.wikipedia.org/wiki/Contract_bridge. Release Notes @@ -15,10 +18,10 @@ To use PyBridge, you need to connect to a game server. You have two options: -- Connect to a public server. A list of known public servers can be found on - the project website. + - Connect to a public server. A list of known public servers can be found on + the project website. -- Run a game server yourself, with the pybridge-server script. + - Run a game server yourself, using the pybridge-server script. When connecting to a server for the first time, you need to ensure that the "Register as New User" checkbox is ticked. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-06-23 15:41:25
|
Revision: 448 http://svn.sourceforge.net/pybridge/?rev=448&view=rev Author: umgangee Date: 2007-06-23 08:41:22 -0700 (Sat, 23 Jun 2007) Log Message: ----------- Build bidding box with PyGTK code, instead of Glade, to facilitate colourised bid buttons and straightforward mapping between Call objects and their button representations. Modified Paths: -------------- trunk/pybridge/glade/pybridge.glade trunk/pybridge/pybridge/ui/window_bidbox.py trunk/pybridge/pybridge/ui/window_bridgetable.py Modified: trunk/pybridge/glade/pybridge.glade =================================================================== --- trunk/pybridge/glade/pybridge.glade 2007-06-23 14:47:07 UTC (rev 447) +++ trunk/pybridge/glade/pybridge.glade 2007-06-23 15:41:22 UTC (rev 448) @@ -326,51 +326,51 @@ <property name="column_spacing">8</property> <property name="row_spacing">2</property> <child> - <widget class="GtkLabel" id="label63"> + <widget class="GtkLabel" id="label_tabletype"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">ID:</property> </widget> <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label_tableid"> + <widget class="GtkLabel" id="label65"> <property name="visible">True</property> <property name="xalign">0</property> + <property name="label" translatable="yes">Type:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label65"> + <widget class="GtkLabel" id="label_tableid"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Type:</property> </widget> <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label_tabletype"> + <widget class="GtkLabel" id="label63"> <property name="visible">True</property> <property name="xalign">0</property> + <property name="label" translatable="yes">ID:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> @@ -464,24 +464,24 @@ <property name="column_spacing">8</property> <property name="row_spacing">2</property> <child> - <widget class="GtkLabel" id="label67"> + <widget class="GtkLabel" id="label_personname"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Name:</property> </widget> <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label_personname"> + <widget class="GtkLabel" id="label67"> <property name="visible">True</property> <property name="xalign">0</property> + <property name="label" translatable="yes">Name:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> @@ -534,665 +534,6 @@ </widget> </child> </widget> - <widget class="GtkWindow" id="window_bidbox"> - <property name="visible">True</property> - <property name="title" translatable="yes">Bidding Box</property> - <property name="resizable">False</property> - <property name="skip_taskbar_hint">True</property> - <property name="focus_on_map">False</property> - <property name="gravity">GDK_GRAVITY_NORTH_EAST</property> - <signal name="delete_event" handler="on_window_bidbox_delete_event"/> - <child> - <widget class="GtkVBox" id="calls"> - <property name="visible">True</property> - <child> - <widget class="GtkButton" id="button_pass"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Pass</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <widget class="GtkHSeparator" id="hseparator2"> - <property name="visible">True</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="position">1</property> - </packing> - </child> - <child> - <widget class="GtkTable" id="table_bids"> - <property name="visible">True</property> - <property name="n_rows">7</property> - <property name="n_columns">5</property> - <child> - <widget class="GtkButton" id="button_bid_1_nt"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">1NT</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">4</property> - <property name="right_attach">5</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_1_spade"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">1♠</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">3</property> - <property name="right_attach">4</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_1_heart"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">1♥</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_1_diamond"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">1♦</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_1_club"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">1♣</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_3_diamond"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">3♦</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_2_diamond"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">2♦</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_2_club"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">2♣</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_2_nt"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">2NT</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">4</property> - <property name="right_attach">5</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_3_nt"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">3NT</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">4</property> - <property name="right_attach">5</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_4_nt"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">4NT</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">4</property> - <property name="right_attach">5</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_5_nt"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">5NT</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">4</property> - <property name="right_attach">5</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_6_nt"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">6NT</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">4</property> - <property name="right_attach">5</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_7_nt"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">7NT</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">4</property> - <property name="right_attach">5</property> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_7_spade"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">7♠</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">3</property> - <property name="right_attach">4</property> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_7_heart"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">7♥</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_7_diamond"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">7♦</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_7_club"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">7♣</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="top_attach">6</property> - <property name="bottom_attach">7</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_6_club"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">6♣</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_6_diamond"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">6♦</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_6_heart"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">6♥</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_6_spade"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">6♠</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">3</property> - <property name="right_attach">4</property> - <property name="top_attach">5</property> - <property name="bottom_attach">6</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_5_heart"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">5♥</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_5_diamond"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">5♦</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_5_club"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">5♣</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_4_club"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">4♣</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_4_diamond"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">4♦</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_4_heart"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">4♥</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_4_spade"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">4♠</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">3</property> - <property name="right_attach">4</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_3_heart"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">3♥</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_3_club"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">3♣</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_2_heart"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">2♥</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">2</property> - <property name="right_attach">3</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_2_spade"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">2♠</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">3</property> - <property name="right_attach">4</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_3_spade"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">3♠</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">3</property> - <property name="right_attach">4</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkButton" id="button_bid_5_spade"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">5♠</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="left_attach">3</property> - <property name="right_attach">4</property> - <property name="top_attach">4</property> - <property name="bottom_attach">5</property> - <property name="y_options"></property> - </packing> - </child> - </widget> - <packing> - <property name="position">2</property> - </packing> - </child> - <child> - <widget class="GtkHSeparator" id="hseparator1"> - <property name="visible">True</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="position">3</property> - </packing> - </child> - <child> - <widget class="GtkHBox" id="doubles"> - <property name="visible">True</property> - <child> - <widget class="GtkButton" id="button_double"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Double</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - </child> - <child> - <widget class="GtkButton" id="button_redouble"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Redouble</property> - <property name="relief">GTK_RELIEF_NONE</property> - <property name="use_underline">True</property> - <signal name="clicked" handler="on_call_clicked"/> - </widget> - <packing> - <property name="position">1</property> - </packing> - </child> - </widget> - <packing> - <property name="position">4</property> - </packing> - </child> - </widget> - </child> - </widget> <widget class="GtkDialog" id="dialog_connection"> <property name="visible">True</property> <property name="title" translatable="yes">Connect to Server</property> @@ -1227,30 +568,23 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> - <widget class="GtkLabel" id="label_portnum"> + <widget class="GtkEntry" id="entry_portnum"> + <property name="width_request">80</property> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Port:</property> + <property name="can_focus">True</property> + <property name="max_length">5</property> + <property name="invisible_char">*</property> + <signal name="changed" handler="on_field_changed"/> </widget> <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label_hostname"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Host Name:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> <widget class="GtkEntry" id="entry_hostname"> <property name="width_request">140</property> <property name="visible">True</property> @@ -1265,19 +599,26 @@ </packing> </child> <child> - <widget class="GtkEntry" id="entry_portnum"> - <property name="width_request">80</property> + <widget class="GtkLabel" id="label_hostname"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="max_length">5</property> - <property name="invisible_char">*</property> - <signal name="changed" handler="on_field_changed"/> + <property name="xalign">0</property> + <property name="label" translatable="yes">Host Name:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_portnum"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Port:</property> + </widget> + <packing> <property name="top_attach">1</property> <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> @@ -1320,26 +661,20 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> - <widget class="GtkLabel" id="label_username"> + <widget class="GtkEntry" id="entry_password"> + <property name="width_request">120</property> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">User Name:</property> + <property name="can_focus">True</property> + <property name="max_length">40</property> + <property name="visibility">False</property> + <property name="invisible_char">*</property> + <signal name="changed" handler="on_field_changed"/> </widget> <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_password"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Password:</property> - </widget> - <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> @@ -1359,23 +694,29 @@ </packing> </child> <child> - <widget class="GtkEntry" id="entry_password"> - <property name="width_request">120</property> + <widget class="GtkLabel" id="label_password"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="max_length">40</property> - <property name="visibility">False</property> - <property name="invisible_char">*</property> - <signal name="changed" handler="on_field_changed"/> + <property name="xalign">0</property> + <property name="label" translatable="yes">Password:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> + <child> + <widget class="GtkLabel" id="label_username"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">User Name:</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> </widget> </child> <child> @@ -1498,6 +839,16 @@ <property name="column_spacing">4</property> <property name="row_spacing">2</property> <child> + <widget class="GtkLabel" id="label_tablename"> + <property name="visible">True</property> + <property name="label" translatable="yes">Table Name:</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> <widget class="GtkEntry" id="entry_tablename"> <property name="width_request">140</property> <property name="visible">True</property> @@ -1511,16 +862,6 @@ <property name="y_options"></property> </packing> </child> - <child> - <widget class="GtkLabel" id="label_tablename"> - <property name="visible">True</property> - <property name="label" translatable="yes">Table Name:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> </widget> </child> </widget> @@ -1790,23 +1131,14 @@ <property name="column_spacing">8</property> <property name="row_spacing">2</property> <child> - <widget class="GtkLabel" id="label59"> + <widget class="GtkLabel" id="label_vuln"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Dealer:</property> + <property name="use_markup">True</property> </widget> <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label60"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Vulnerability:</property> - </widget> - <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> <property name="x_options">GTK_FILL</property> @@ -1826,20 +1158,29 @@ </packing> </child> <child> - <widget class="GtkLabel" id="label_vuln"> + <widget class="GtkLabel" id="label60"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="use_markup">True</property> + <property name="label" translatable="yes">Vulnerability:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> + <child> + <widget class="GtkLabel" id="label59"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Dealer:</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> </widget> <packing> <property name="expand">False</property> @@ -2113,72 +1454,6 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> - <widget class="GtkFileChooserButton" id="background"> - <property name="width_request">160</property> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <signal name="selection_changed" handler="on_background_changed"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - </packing> - </child> - <child> - <widget class="GtkComboBox" id="cardstyle"> - <property name="width_request">160</property> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <signal name="changed" handler="on_cardstyle_changed"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_background"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Background:</property> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_cardstyle"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Card Style:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_suitcolours"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Suit Colours:</property> - </widget> - <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> <widget class="GtkHBox" id="hbox2"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> @@ -2275,6 +1550,72 @@ <property name="bottom_attach">3</property> </packing> </child> + <child> + <widget class="GtkLabel" id="label_suitcolours"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Suit Colours:</property> + </widget> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_cardstyle"> + <property name="visible">True</property> + ... [truncated message content] |
From: <umg...@us...> - 2007-06-24 16:28:22
|
Revision: 450 http://svn.sourceforge.net/pybridge/?rev=450&view=rev Author: umgangee Date: 2007-06-24 09:28:19 -0700 (Sun, 24 Jun 2007) Log Message: ----------- Update and augment readme files for 0.3.0. Modified Paths: -------------- trunk/pybridge/AUTHORS trunk/pybridge/INSTALL trunk/pybridge/README Modified: trunk/pybridge/AUTHORS =================================================================== --- trunk/pybridge/AUTHORS 2007-06-24 10:03:36 UTC (rev 449) +++ trunk/pybridge/AUTHORS 2007-06-24 16:28:19 UTC (rev 450) @@ -1,6 +1,10 @@ Authors: Michael Banks <mi...@ba...> + + +Contributors: + Sourav K. Mandal <so...@so...> Modified: trunk/pybridge/INSTALL =================================================================== --- trunk/pybridge/INSTALL 2007-06-24 10:03:36 UTC (rev 449) +++ trunk/pybridge/INSTALL 2007-06-24 16:28:19 UTC (rev 450) @@ -6,15 +6,22 @@ python setup.py install -We recommend that, if your distribution provides PyBridge packages, you should -install from packages. Packages are available for Debian GNU/Linux and its -derivatives (including Ubuntu) thanks to David Watson <dw...@de...>. - Alternatively, you can run PyBridge from the extracted tarball archive. Change -to the PyBridge "bin/" directory, then type "./pybridge" to run the graphical -client, or "./pybridge-server" to run the standalone server. +to the PyBridge 'bin/' directory, then type './pybridge' to run the graphical +client, or './pybridge-server' to run the standalone server. +PyBridge packages are available for Debian GNU/Linux and Ubuntu systems, thanks +to David Watson <dw...@de...>. Please visit: + - For Debian: http://packages.debian.org/pybridge/ + - For Ubuntu: http://packages.ubuntu.com/pybridge/ + +Users of Microsoft Windows may wish to use the 'py2exe' PyBridge distribution, +which provides native executable (.exe) versions of the 'pybridge' and +'pybridge-server' scripts, and bundles all the library software (see below) +required to run PyBridge. + + Requirements ============ @@ -46,7 +53,7 @@ By default, the standalone server creates and uses a SQLite database in the ~/.pybridge/ directory. This is suitable for hosting LAN games, but if you wish to operate a high-load PyBridge server on the Internet, it may be necessary -to switch to an external RDBMS, such as MySQL or PostgreSQL. +to switch to an external database server, such as MySQL or PostgreSQL. To change the database settings, edit the ~/.pybridge/server.cfg file. The fields to change are documented in the pybridge/server/config.py module. Modified: trunk/pybridge/README =================================================================== --- trunk/pybridge/README 2007-06-24 10:03:36 UTC (rev 449) +++ trunk/pybridge/README 2007-06-24 16:28:19 UTC (rev 450) @@ -21,20 +21,22 @@ - Connect to a public server. A list of known public servers can be found on the project website. - - Run a game server yourself, using the pybridge-server script. + - Run a PyBridge game server yourself, using the pybridge-server script. -When connecting to a server for the first time, you need to ensure that the -"Register as New User" checkbox is ticked. +When connecting to a PyBridge server for the first time, you need to ensure +that the "Register as New User" checkbox is ticked. -Installation instructions can be found in the INSTALL file. Details of changes -made in this release can be found in the NEWS file. +Installation instructions can be found in the INSTALL file. Details of new +features, bug fixes and other changes can be found in the NEWS file. Your feedback, bug reports and ideas for new features are especially welcome. -Forums: http://sourceforge.net/forum/?group_id=114287 -Bug reports: http://sourceforge.net/tracker/?group_id=114287&atid=667822 -Feature requests: http://sourceforge.net/tracker/?group_id=114287&atid=667825 + - Forums: http://sourceforge.net/forum/?group_id=114287 + - Bug reports: http://sourceforge.net/tracker/?group_id=114287&atid=667822 + + - Feature ideas: http://sourceforge.net/tracker/?group_id=114287&atid=667825 + If you are a competent (or aspiring!) Python programmer and would like to contribute code to PyBridge, then please get in touch with the developers! This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-06-25 10:16:54
|
Revision: 452 http://svn.sourceforge.net/pybridge/?rev=452&view=rev Author: umgangee Date: 2007-06-25 03:16:56 -0700 (Mon, 25 Jun 2007) Log Message: ----------- Add a desktop entry for PyBridge program. Modified Paths: -------------- trunk/pybridge/setup.py Added Paths: ----------- trunk/pybridge/bin/pybridge.desktop Added: trunk/pybridge/bin/pybridge.desktop =================================================================== --- trunk/pybridge/bin/pybridge.desktop (rev 0) +++ trunk/pybridge/bin/pybridge.desktop 2007-06-25 10:16:56 UTC (rev 452) @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=PyBridge +Comment[en]=An online contract bridge game +Exec=pybridge +Icon=/usr/share/pybridge/pixmaps/pybridge.png +Terminal=false +Type=Application +Categories=Application;Game;CardGame Modified: trunk/pybridge/setup.py =================================================================== --- trunk/pybridge/setup.py 2007-06-25 09:46:35 UTC (rev 451) +++ trunk/pybridge/setup.py 2007-06-25 10:16:56 UTC (rev 452) @@ -21,10 +21,10 @@ url = 'http://sourceforge.net/projects/pybridge/', description = 'A free online bridge game.', download_url = 'http://sourceforge.net/project/showfiles.php?group_id=114287', - packages = ['pybridge', 'pybridge.bridge', 'pybridge.interfaces', - 'pybridge.network', 'pybridge.server', 'pybridge.ui'], + packages = ['pybridge', 'pybridge.bridge', 'pybridge.interfaces', 'pybridge.network', 'pybridge.server', 'pybridge.ui'], scripts = ['bin/pybridge', 'bin/pybridge-server'], - data_files = [('share/doc/pybridge', ['AUTHORS', 'COPYING', 'INSTALL', 'NEWS', 'README']), + data_files = [('share/applications', ['bin/pybridge.desktop']), + ('share/doc/pybridge', ['AUTHORS', 'COPYING', 'INSTALL', 'NEWS', 'README']), ('share/pybridge/glade', glob.glob('glade/*.glade')), ('share/pybridge/pixmaps', glob.glob('pixmaps/*')), ], This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-06-25 13:15:04
|
Revision: 454 http://svn.sourceforge.net/pybridge/?rev=454&view=rev Author: umgangee Date: 2007-06-25 06:14:59 -0700 (Mon, 25 Jun 2007) Log Message: ----------- Provide user with option of drawing suits as symbols. This is useful for GTK on win32, which does not appear to render suit symbols correctly. Modified Paths: -------------- trunk/pybridge/glade/pybridge.glade trunk/pybridge/pybridge/ui/config.py trunk/pybridge/pybridge/ui/dialog_preferences.py trunk/pybridge/pybridge/ui/vocabulary.py Modified: trunk/pybridge/glade/pybridge.glade =================================================================== --- trunk/pybridge/glade/pybridge.glade 2007-06-25 11:36:23 UTC (rev 453) +++ trunk/pybridge/glade/pybridge.glade 2007-06-25 13:14:59 UTC (rev 454) @@ -326,51 +326,51 @@ <property name="column_spacing">8</property> <property name="row_spacing">2</property> <child> - <widget class="GtkLabel" id="label_tabletype"> + <widget class="GtkLabel" id="label63"> <property name="visible">True</property> <property name="xalign">0</property> + <property name="label" translatable="yes">ID:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label65"> + <widget class="GtkLabel" id="label_tableid"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Type:</property> </widget> <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label_tableid"> + <widget class="GtkLabel" id="label65"> <property name="visible">True</property> <property name="xalign">0</property> + <property name="label" translatable="yes">Type:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label63"> + <widget class="GtkLabel" id="label_tabletype"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">ID:</property> </widget> <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> @@ -464,24 +464,24 @@ <property name="column_spacing">8</property> <property name="row_spacing">2</property> <child> - <widget class="GtkLabel" id="label_personname"> + <widget class="GtkLabel" id="label67"> <property name="visible">True</property> <property name="xalign">0</property> + <property name="label" translatable="yes">Name:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label67"> + <widget class="GtkLabel" id="label_personname"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Name:</property> </widget> <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> @@ -568,23 +568,30 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> - <widget class="GtkEntry" id="entry_portnum"> - <property name="width_request">80</property> + <widget class="GtkLabel" id="label_portnum"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="max_length">5</property> - <property name="invisible_char">*</property> - <signal name="changed" handler="on_field_changed"/> + <property name="xalign">0</property> + <property name="label" translatable="yes">Port:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> <child> + <widget class="GtkLabel" id="label_hostname"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Host Name:</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> <widget class="GtkEntry" id="entry_hostname"> <property name="width_request">140</property> <property name="visible">True</property> @@ -599,26 +606,19 @@ </packing> </child> <child> - <widget class="GtkLabel" id="label_hostname"> + <widget class="GtkEntry" id="entry_portnum"> + <property name="width_request">80</property> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Host Name:</property> + <property name="can_focus">True</property> + <property name="max_length">5</property> + <property name="invisible_char">*</property> + <signal name="changed" handler="on_field_changed"/> </widget> <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_portnum"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Port:</property> - </widget> - <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> @@ -661,20 +661,26 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> - <widget class="GtkEntry" id="entry_password"> - <property name="width_request">120</property> + <widget class="GtkLabel" id="label_username"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="max_length">40</property> - <property name="visibility">False</property> - <property name="invisible_char">*</property> - <signal name="changed" handler="on_field_changed"/> + <property name="xalign">0</property> + <property name="label" translatable="yes">User Name:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_password"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Password:</property> + </widget> + <packing> <property name="top_attach">1</property> <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> @@ -694,29 +700,23 @@ </packing> </child> <child> - <widget class="GtkLabel" id="label_password"> + <widget class="GtkEntry" id="entry_password"> + <property name="width_request">120</property> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Password:</property> + <property name="can_focus">True</property> + <property name="max_length">40</property> + <property name="visibility">False</property> + <property name="invisible_char">*</property> + <signal name="changed" handler="on_field_changed"/> </widget> <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> - <child> - <widget class="GtkLabel" id="label_username"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">User Name:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> </widget> </child> <child> @@ -839,16 +839,6 @@ <property name="column_spacing">4</property> <property name="row_spacing">2</property> <child> - <widget class="GtkLabel" id="label_tablename"> - <property name="visible">True</property> - <property name="label" translatable="yes">Table Name:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> <widget class="GtkEntry" id="entry_tablename"> <property name="width_request">140</property> <property name="visible">True</property> @@ -862,6 +852,16 @@ <property name="y_options"></property> </packing> </child> + <child> + <widget class="GtkLabel" id="label_tablename"> + <property name="visible">True</property> + <property name="label" translatable="yes">Table Name:</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> </widget> </child> </widget> @@ -1131,14 +1131,23 @@ <property name="column_spacing">8</property> <property name="row_spacing">2</property> <child> - <widget class="GtkLabel" id="label_vuln"> + <widget class="GtkLabel" id="label59"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="use_markup">True</property> + <property name="label" translatable="yes">Dealer:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label60"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Vulnerability:</property> + </widget> + <packing> <property name="top_attach">1</property> <property name="bottom_attach">2</property> <property name="x_options">GTK_FILL</property> @@ -1158,29 +1167,20 @@ </packing> </child> <child> - <widget class="GtkLabel" id="label60"> + <widget class="GtkLabel" id="label_vuln"> <property name="visible">True</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Vulnerability:</property> + <property name="use_markup">True</property> </widget> <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> - <child> - <widget class="GtkLabel" id="label59"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Dealer:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> </widget> <packing> <property name="expand">False</property> @@ -1454,6 +1454,72 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> + <widget class="GtkFileChooserButton" id="background"> + <property name="width_request">160</property> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="selection_changed" handler="on_background_changed"/> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cardstyle"> + <property name="width_request">160</property> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="changed" handler="on_cardstyle_changed"/> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_background"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Background:</property> + </widget> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_cardstyle"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Card Style:</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_suitcolours"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Suit Colours:</property> + </widget> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> <widget class="GtkHBox" id="hbox2"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> @@ -1470,7 +1536,7 @@ <widget class="GtkLabel" id="label_clubcolour"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">♣</property> + <property name="label" translatable="yes">C</property> <property name="use_markup">True</property> </widget> </child> @@ -1490,7 +1556,7 @@ <widget class="GtkLabel" id="label_diamondcolour"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">♦</property> + <property name="label" translatable="yes">D</property> <property name="use_markup">True</property> </widget> </child> @@ -1511,7 +1577,7 @@ <widget class="GtkLabel" id="label_heartcolour"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">♥</property> + <property name="label" translatable="yes">H</property> <property name="use_markup">True</property> </widget> </child> @@ -1532,7 +1598,7 @@ <widget class="GtkLabel" id="label_spadecolour"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">♠</property> + <property name="label" translatable="yes">S</property> <property name="use_markup">True</property> </widget> </child> @@ -1550,78 +1616,24 @@ <property name="bottom_attach">3</property> </packing> </child> - <child> - <widget class="GtkLabel" id="label_suitcolours"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Suit Colours:</property> - </widget> - <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_cardstyle"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Card Style:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_background"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Background:</property> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkComboBox" id="cardstyle"> - <property name="width_request">160</property> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <signal name="changed" handler="on_cardstyle_changed"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - </packing> - </child> - <child> - <widget class="GtkFileChooserButton" id="background"> - <property name="width_request">160</property> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <signal name="selection_changed" handler="on_background_changed"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - </packing> - </child> </widget> <packing> <property name="expand">False</property> </packing> </child> <child> + <widget class="GtkCheckButton" id="check_suitsymbols"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">Display suits as symbols?</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + <child> <widget class="GtkLabel" id="label_changenote"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> @@ -1630,7 +1642,7 @@ <property name="wrap">True</property> </widget> <packing> - <property name="position">1</property> + <property name="position">2</property> </packing> </child> </widget> Modified: trunk/pybridge/pybridge/ui/config.py =================================================================== --- trunk/pybridge/pybridge/ui/config.py 2007-06-25 11:36:23 UTC (rev 453) +++ trunk/pybridge/pybridge/ui/config.py 2007-06-25 13:14:59 UTC (rev 454) @@ -38,6 +38,7 @@ [Appearance] CardStyle = string BackgroundImage = string + SuitSymbols = boolean(default=True) [[Colours]] Club = int_list(3, 3) Modified: trunk/pybridge/pybridge/ui/dialog_preferences.py =================================================================== --- trunk/pybridge/pybridge/ui/dialog_preferences.py 2007-06-25 11:36:23 UTC (rev 453) +++ trunk/pybridge/pybridge/ui/dialog_preferences.py 2007-06-25 13:14:59 UTC (rev 454) @@ -27,7 +27,7 @@ from pybridge.bridge.symbols import Suit -SUIT_LABEL_TEMPLATE = "<span color=\'%s\' size=\'xx-large\'>%s</span>" +SUIT_LABEL_TEMPLATE = "<span color=\'%s\' size=\'x-large\'>%s</span>" class DialogPreferences(GladeWrapper): @@ -76,7 +76,10 @@ label = getattr(self, 'label_%scolour' % suit.key.lower()) label.set_markup(SUIT_LABEL_TEMPLATE % (hexrep, SUIT_SYMBOLS[suit])) + use_suitsymbols = config['Appearance'].get('SuitSymbols') + self.check_suitsymbols.set_active(use_suitsymbols) + # Signal handlers. @@ -128,5 +131,7 @@ iter = self.cardstyle.get_active_iter() config['Appearance']['CardStyle'] = model.get_value(iter, 0) + config['Appearance']['SuitSymbols'] = self.check_suitsymbols.get_active() + wm.close(self) Modified: trunk/pybridge/pybridge/ui/vocabulary.py =================================================================== --- trunk/pybridge/pybridge/ui/vocabulary.py 2007-06-25 11:36:23 UTC (rev 453) +++ trunk/pybridge/pybridge/ui/vocabulary.py 2007-06-25 13:14:59 UTC (rev 454) @@ -103,12 +103,20 @@ Suit.Spade: _('Spades'), } -SUIT_SYMBOLS = { - Suit.Club: u'\N{BLACK CLUB SUIT}', - Suit.Diamond: u'\N{BLACK DIAMOND SUIT}', - Suit.Heart: u'\N{BLACK HEART SUIT}', - Suit.Spade: u'\N{BLACK SPADE SUIT}', -} +if config['Appearance'].get('SuitSymbols'): + SUIT_SYMBOLS = { + Suit.Club: u'\N{BLACK CLUB SUIT}', + Suit.Diamond: u'\N{BLACK DIAMOND SUIT}', + Suit.Heart: u'\N{BLACK HEART SUIT}', + Suit.Spade: u'\N{BLACK SPADE SUIT}', + } +else: + SUIT_SYMBOLS = { + Suit.Club: 'C', + Suit.Diamond: 'D', + Suit.Heart: 'H', + Suit.Spade: 'S', + } STRAIN_NAMES = { Strain.Club: _('Club'), @@ -118,19 +126,28 @@ Strain.NoTrump: _('No Trump'), } -STRAIN_SYMBOLS = { - Strain.Club: u'\N{BLACK CLUB SUIT}', - Strain.Diamond: u'\N{BLACK DIAMOND SUIT}', - Strain.Heart: u'\N{BLACK HEART SUIT}', - Strain.Spade: u'\N{BLACK SPADE SUIT}', - Strain.NoTrump: u'NT', -} +if config['Appearance'].get('SuitSymbols'): + STRAIN_SYMBOLS = { + Strain.Club: u'\N{BLACK CLUB SUIT}', + Strain.Diamond: u'\N{BLACK DIAMOND SUIT}', + Strain.Heart: u'\N{BLACK HEART SUIT}', + Strain.Spade: u'\N{BLACK SPADE SUIT}', + Strain.NoTrump: 'NT', + } +else: + STRAIN_SYMBOLS = { + Strain.Club: 'C', + Strain.Diamond: 'D', + Strain.Heart: 'H', + Strain.Spade: 'S', + Strain.NoTrump: 'NT', + } VULN_SYMBOLS = { Vulnerable.All: _('All'), - Vulnerable.NorthSouth : _('N/S'), - Vulnerable.EastWest : _('E/W'), - Vulnerable.None : _('None'), + Vulnerable.NorthSouth: _('N/S'), + Vulnerable.EastWest: _('E/W'), + Vulnerable.None: _('None'), } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-07-10 13:55:51
|
Revision: 467 http://svn.sourceforge.net/pybridge/?rev=467&view=rev Author: umgangee Date: 2007-07-10 06:55:49 -0700 (Tue, 10 Jul 2007) Log Message: ----------- Whoops! These manpages should have been committed long ago! Added Paths: ----------- trunk/pybridge/man/ trunk/pybridge/man/pybridge-server.6 trunk/pybridge/man/pybridge.6 Added: trunk/pybridge/man/pybridge-server.6 =================================================================== --- trunk/pybridge/man/pybridge-server.6 (rev 0) +++ trunk/pybridge/man/pybridge-server.6 2007-07-10 13:55:49 UTC (rev 467) @@ -0,0 +1,35 @@ +.TH PYBRIDGE-SERVER 6 "5 September 2006" "" "" + +.SH NAME +PyBridge Server \- a game server for PyBridge. + +.SH SYNOPSIS +\fBpybridge-server\fR [options] + +.SH DESCRIPTION +\fBpybridge-server\fR is a game server for PyBridge. It accepts incoming network connections from \fBpybridge\fR clients. + +For more information, visit \fIhttp://pybridge.sourceforge.net/\fR. + +.SH OPTIONS + +.TP +\fB\-h\fR, \fB--help\fR +Print help message and exit. + +.TP +\fB\-p\fR \fIportnum\fR, \fB--port\fB \fIportnum\fR +Listen for incoming connections on port \fIportnum\fR. (The default port is 5040.) + +.TP +.BR \fB\-v\fR, \fB--version\fR +Print version information and exit. + +.SH SEE ALSO +\fBpybridge\fR(6) + +.SH AUTHOR +This manual page was written by Michael Banks <mi...@ba...>. + +.SH BUGS +Plenty. Please report any bugs you find. Added: trunk/pybridge/man/pybridge.6 =================================================================== --- trunk/pybridge/man/pybridge.6 (rev 0) +++ trunk/pybridge/man/pybridge.6 2007-07-10 13:55:49 UTC (rev 467) @@ -0,0 +1,24 @@ +.TH PYBRIDGE 6 "5 September 2006" "" "" + +.SH NAME +PyBridge \- a free online bridge game. + +.SH SYNOPSIS +.B pybridge + +.SH DESCRIPTION +\fBpybridge\fR is a graphical interface for playing the card game of (contract) bridge over the Internet or a local network. + +To actually use \fBpybridge\fR, you need to connect to a PyBridge game server. You may run a game server yourself (see \fBpybridge-server\fR) or connect to a public server. A list of public servers, along with other information, can be found at \fIhttp://pybridge.sourceforge.net/\fR. + +.SH OPTIONS +\fBpybridge\fR accepts no options. + +.SH SEE ALSO +\fBpybridge-server\fR(6) + +.SH AUTHOR +This manual page was written by Michael Banks <mi...@ba...>. + +.SH BUGS +Plenty. Please report any bugs you find. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
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. |
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. |
From: <umg...@us...> - 2007-07-19 15:30:38
|
Revision: 484 http://svn.sourceforge.net/pybridge/?rev=484&view=rev Author: umgangee Date: 2007-07-19 08:30:30 -0700 (Thu, 19 Jul 2007) Log Message: ----------- Allow user to specify which game is played at new table. Modified Paths: -------------- trunk/pybridge/glade/pybridge.glade trunk/pybridge/pybridge/ui/dialog_newtable.py Modified: trunk/pybridge/glade/pybridge.glade =================================================================== --- trunk/pybridge/glade/pybridge.glade 2007-07-16 15:28:30 UTC (rev 483) +++ trunk/pybridge/glade/pybridge.glade 2007-07-19 15:30:30 UTC (rev 484) @@ -13,9 +13,9 @@ <widget class="GtkMenuBar" id="menubar_main"> <property name="visible">True</property> <child> - <widget class="GtkMenuItem" id="menu_server"> + <widget class="GtkMenuItem" id="menu_connection"> <property name="visible">True</property> - <property name="label" translatable="yes">_Server</property> + <property name="label" translatable="yes">_Connection</property> <property name="use_underline">True</property> <child> <widget class="GtkMenu" id="menu_server_menu"> @@ -815,7 +815,7 @@ </widget> <widget class="GtkDialog" id="dialog_newtable"> <property name="visible">True</property> - <property name="title" translatable="yes">New Table</property> + <property name="title" translatable="yes">Create a New Table</property> <property name="resizable">False</property> <property name="modal">True</property> <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> @@ -835,12 +835,39 @@ <child> <widget class="GtkTable" id="table2"> <property name="visible">True</property> - <property name="n_rows">1</property> + <property name="n_rows">2</property> <property name="n_columns">2</property> - <property name="column_spacing">4</property> - <property name="row_spacing">2</property> + <property name="column_spacing">8</property> + <property name="row_spacing">4</property> <child> - <widget class="GtkEntry" id="entry_tablename"> + <widget class="GtkLabel" id="label_gamelist"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Game at Table:</property> + </widget> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="gamelist"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="changed" handler="on_gamelist_changed"/> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="y_options">GTK_FILL</property> + </packing> + </child> + <child> + <widget class="GtkEntry" id="tablename"> <property name="width_request">140</property> <property name="visible">True</property> <property name="can_focus">True</property> @@ -850,16 +877,16 @@ <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="y_options"></property> + <property name="y_options">GTK_FILL</property> </packing> </child> <child> <widget class="GtkLabel" id="label_tablename"> <property name="visible">True</property> + <property name="xalign">0</property> <property name="label" translatable="yes">Table Name:</property> </widget> <packing> - <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> Modified: trunk/pybridge/pybridge/ui/dialog_newtable.py =================================================================== --- trunk/pybridge/pybridge/ui/dialog_newtable.py 2007-07-16 15:28:30 UTC (rev 483) +++ trunk/pybridge/pybridge/ui/dialog_newtable.py 2007-07-19 15:30:30 UTC (rev 484) @@ -30,8 +30,17 @@ def setUp(self): + # Build and populate list of supported games. + model = gtk.ListStore(str) + self.gamelist.set_model(model) + cell = gtk.CellRendererText() + self.gamelist.pack_start(cell, True) + self.gamelist.add_attribute(cell, 'text', 0) + + for gamename in sorted(SUPPORTED_GAMES): + iter = model.append((gamename, )) + self.gamelist.set_active_iter(iter) # TODO: display intersection of games supported by client and server. - pass def createSuccess(self, table): @@ -43,13 +52,16 @@ dialog = gtk.MessageDialog(parent=self.window, flags=gtk.DIALOG_MODAL, type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK) dialog.set_title(_('Could not create table')) - dialog.set_markup(_('The table could not be created.')) + dialog.set_markup(_('The table was not created by the server.')) dialog.format_secondary_text(_('Reason: %s') % error) - dialog.run() - dialog.destroy() + def dialog_response_cb(dialog, response_id): + dialog.destroy() + dialog.connect('response', dialog_response_cb) + dialog.show() + # Signal handlers. @@ -58,15 +70,19 @@ def on_okbutton_clicked(self, widget, *args): - tableid = self.entry_tablename.get_text() - d = client.joinTable(tableid, gameclass=SUPPORTED_GAMES['Bridge'], - host=True) + model = self.gamelist.get_model() + iter = self.gamelist.get_active_iter() + gamename = model.get_value(iter, 0) + + tableid = self.tablename.get_text() + gameclass = SUPPORTED_GAMES[gamename] + d = client.joinTable(tableid, gameclass, host=True) d.addCallbacks(self.createSuccess, self.createFailure) def on_tablename_changed(self, widget, *args): # Disable the OK button if the table name field is empty. - sensitive = self.entry_tablename.get_text() != "" + sensitive = self.tablename.get_text() != "" self.okbutton.set_property('sensitive', sensitive) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-07-20 14:32:17
|
Revision: 485 http://svn.sourceforge.net/pybridge/?rev=485&view=rev Author: umgangee Date: 2007-07-20 07:32:16 -0700 (Fri, 20 Jul 2007) Log Message: ----------- New Deal class replaces Deck. Deck-specific methods become Deal classmethods. Use 1..D range instead of 0..D-1 for consistency with IBB. (although the IBB algorithm itself deals in ranges 0..D-1) Modified Paths: -------------- trunk/pybridge/pybridge/games/bridge/board.py Added Paths: ----------- trunk/pybridge/pybridge/games/bridge/deal.py trunk/pybridge/tests/bridge/test_deal.py Removed Paths: ------------- trunk/pybridge/pybridge/games/bridge/deck.py trunk/pybridge/tests/bridge/test_deck.py Modified: trunk/pybridge/pybridge/games/bridge/board.py =================================================================== --- trunk/pybridge/pybridge/games/bridge/board.py 2007-07-19 15:30:30 UTC (rev 484) +++ trunk/pybridge/pybridge/games/bridge/board.py 2007-07-20 14:32:16 UTC (rev 485) @@ -18,7 +18,7 @@ import random import time -from deck import Deck +from deal import Deal from symbols import Direction, Vulnerable @@ -53,8 +53,7 @@ @param result: @type result: """ - deck = Deck() - self['deal'] = deck.randomDeal() + self['deal'] = Deal.fromRandom() self['num'] = self.get('num', 0) + 1 self['time'] = tuple(time.localtime()) Copied: trunk/pybridge/pybridge/games/bridge/deal.py (from rev 480, trunk/pybridge/pybridge/games/bridge/deck.py) =================================================================== --- trunk/pybridge/pybridge/games/bridge/deal.py (rev 0) +++ trunk/pybridge/pybridge/games/bridge/deal.py 2007-07-20 14:32:16 UTC (rev 485) @@ -0,0 +1,184 @@ +# 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 copy import copy +from operator import mul +import random + +from card import Card +from symbols import Direction, Rank, Suit + + +# See http://mail.python.org/pipermail/edu-sig/2001-May/001288.html for details. +comb = lambda n, k: reduce(mul, range(n, n-k, -1)) / reduce(mul, range(1, k+1)) + + +class Deal(dict): + """Represents a deal of hands as a dict containing lists of cards. + + Operations to encode/decode deals into a variety of formats are provided, + including "impossible bridge book" index values and PBN strings. + + Definitions: + - A hand is a collection of 13 cards from the deck. + - A deal is a distribution of all 52 cards to four hands. + + There are exactly 52! / (13!)**4 (comb(52,13) * comb(39,13) * comb(26,13)) + distinct deals of 13 cards to 4 positions from a standard 52-card deck. + """ + + # Required order: Ace of Spades, King of Spades, ..., Two of Clubs. + __cards = [Card(r, s) for s in reversed(Suit) for r in reversed(Rank)] + + __Nmax = comb(52, 13) + __Emax = comb(39, 13) + __Smax = comb(26, 13) + __D = __Nmax * __Emax * __Smax + + + def __init__(self, mapping): + super(Deal, self).__init__(mapping) + for hand in self.values(): + hand.sort() + + + @classmethod + def fromRandom(cls): + """Generates a random deal of hands from a 'shuffled' deck. + + @return: an instance of Deal. + """ + # This is more efficient than calling fromIndex() with a random number. + deck = copy(cls.__cards) + random.shuffle(deck) + hands = dict((pos, sorted(deck[13*i : 13*(i+1)])) + for i, pos in enumerate(Direction)) + return cls(hands) + + + @classmethod + def fromIndex(cls, num): + """Generates the deal which corresponds to the specified "page number". + + This implements the "impossible bridge book" decoding algorithm by + Thomas Andrews, see http://bridge.thomasoandrews.com/impossible/. + + @param num: integer in range 1..D. + @return: a Deal object containing the corresponding deal. + """ + assert isinstance(num, (int, long)), "index must be an integer" + assert 1 <= num <= cls.__D, "index not in range %s..%s" % (1, cls.__D) + + cardSeq = copy(cls.__cards) # Make a copy for modification. + hands = dict((pos, []) for pos in Direction) + num -= 1 # Decrement page number to fit within range 0..D-1. + + # Split index into hand indexes. + indexes = {Direction.North : (num / cls.__Smax) / cls.__Emax, + Direction.East : (num / cls.__Smax) % cls.__Emax, + Direction.South : (num % cls.__Smax) } + + for position in (Direction.North, Direction.East, Direction.South): + for k in range(13, 0, -1): + + # Find the largest n such that comb(n, k) <= indexes[position]. + n = k-1 # n < k implies comb(n, k) = 0 + # comb(n+1, k) = + # n-k == -1 => comb(n, k) * (n+1) + # otherwise => (comb(n, k) * (n+1)) / (n+1 - k) + while comb(n+1, k) <= indexes[position]: + n += 1 + + # Remove card index from indices, add card to hand. + indexes[position] -= comb(n, k) + card = cardSeq[n] + hands[position].append(card) + cardSeq.remove(card) + + hands[Direction.West] = cardSeq # West has the remaining cards. + + return cls(hands) + + + def toIndex(self): + """Computes the "page number" which corresponds to this deal. + + This implements the "impossible bridge book" encoding algorithm by + Thomas Andrews, see http://bridge.thomasoandrews.com/impossible/. + + @return: integer in range 1..D + """ + cardSeq = copy(self.__cards) # Make a copy for modification. + indexes = {} + + # For each hand, compute indexes of cards in cardSeq. + for position in (Direction.North, Direction.East, Direction.South): + indexes[position] = 0 + self[position].sort(reverse=False) + # It is desirable to remove cards from cardSeq when adding their + # indexes, instead of doing so in an extra step. + # Removing cards backwards preserves the indexes of later cards. + for i, card in enumerate(self[position]): + indexes[position] += comb(cardSeq.index(card), 13-i) + cardSeq.remove(card) + + # Deal index = (Nindex * Emax * Smax) + (Eindex * Smax) + Sindex + indexes[Direction.North] *= self.__Emax * self.__Smax + indexes[Direction.East] *= self.__Smax + + num = sum(indexes.values()) + 1 # Increment to fit within range 1..D. + return long(num) + + + __pbnDirection = dict(zip('NESW', Direction)) + __pbnRank = dict(zip('23456789TJQKA', Rank)) + + + @classmethod + def fromString(cls, dealstr): + """Generates the deal which corresponds to the given PBN deal string. + + As per the PBN specification, the given deal string should conform to + the format "<first>:<1st_hand> <2nd_hand> <3rd_hand> <4th_hand>". + + @param dealstr: a PBN deal string. + @return: a Deal object containing the corresponding deal. + """ + # Reconstruct deal. + first, hands = dealstr.split(":") + firstindex = cls.__pbnDirection[first.strip()].index + order = Direction[firstindex:] + Direction[:firstindex] + + deal = dict((pos, []) for pos in Direction) + + for position, hand in zip(order, hands.strip().split(' ')): + for suit, suitcards in zip(reversed(Suit), hand.split('.')): + for rank in suitcards: + card = Card(cls.__pbnRank[rank], suit) + deal[position].append(card) + + return cls(deal) + + + def toString(self): + """Computes the PBN deal string which corresponds to this deal. + + @return: a PBN deal string. + """ + raise NotImplementedError + Deleted: trunk/pybridge/pybridge/games/bridge/deck.py =================================================================== --- trunk/pybridge/pybridge/games/bridge/deck.py 2007-07-19 15:30:30 UTC (rev 484) +++ trunk/pybridge/pybridge/games/bridge/deck.py 2007-07-20 14:32:16 UTC (rev 485) @@ -1,157 +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 copy import copy -from operator import mul -from random import shuffle - -from card import Card -from symbols import Direction, Rank, Suit - - -# See http://mail.python.org/pipermail/edu-sig/2001-May/001288.html for details. -comb = lambda n, k: reduce(mul, range(n, n-k, -1)) / reduce(mul, range(1, k+1)) - - -# TODO: consider making Hand a subclass of List, with additional constraints. - -class Deck(object): - """A Deck object provides operations for dealing Card objects. - - A hand is a collection of 13 cards from the deck. - A deal is a distribution of all 52 cards to four hands. - - A deal is represented as a dictionary, mapping Direction labels to - lists (hands) of Card objects. - - There are exactly 52! / (13!)**4 (comb(52,13) * comb(39,13) * comb(26,13)) - distinct deals of 13 cards to 4 positions from a standard 52-card deck. - """ - - cards = [Card(r, s) for r in Rank for s in Suit] - cardSeq = copy(cards) - cardSeq.sort(reverse=True) # Required order: Ace of Spades -> Two of Clubs. - - Nmax = comb(52, 13) - Emax = comb(39, 13) - Smax = comb(26, 13) - D = Nmax * Emax * Smax - - - def isValidDeal(self, deal): - """Checks that structure of deal conforms to requirements: - - * 4-element dict, mapping Direction objects to hand lists. - * Hand lists contain exactly 13 Card objects. - * No card may be repeated in the same hand, or between hands. - * The cards in hands may be in any order. - - @param deal: a deal dict. - @return: True if deal is valid, False otherwise. - """ - return True # TODO - if invalid, perhaps give reason - - - def randomDeal(self): - """Shuffles the deck and generates a random deal of hands. - - @return: a deal dictionary. - """ - shuffle(self.cards) - hands = {} - for position in Direction: - hands[position] = [] - for index, card in enumerate(self.cards): - hands[Direction[index % len(Direction)]].append(card) - for hand in hands.values(): - hand.sort() - return hands - - - def dealToIndex(self, deal): - """Computes the index which corresponds to the specified deal. - - This implements the "impossible bridge book" encoding algorithm by - Thomas Andrews, see http://bridge.thomasoandrews.com/impossible/. - - @param deal: dict representing a valid deal. - @return: integer in range 0..D-1 - """ - assert self.isValidDeal(deal) - - cardSeq = copy(self.cardSeq) # Make a copy for modification. - indexes = {} - - # For each hand, compute indexes of cards in cardSeq. - for position in (Direction.North, Direction.East, Direction.South): - indexes[position] = 0 - deal[position].sort(reverse=False) - # It is desirable to remove cards from cardSeq when adding their - # indexes, instead of doing so in an extra step. - # Removing cards backwards preserves the indexes of later cards. - for i, card in enumerate(deal[position]): - indexes[position] += comb(cardSeq.index(card), 13-i) - cardSeq.remove(card) - - # Deal index = (Nindex * Emax * Smax) + (Eindex * Smax) + Sindex - indexes[Direction.North] *= self.Emax * self.Smax - indexes[Direction.East] *= self.Smax - return long(sum(indexes.values())) - - - def indexToDeal(self, num): - """Generates the deal which corresponds to the specified index. - - This implements the "impossible bridge book" decoding algorithm by - Thomas Andrews, see http://bridge.thomasoandrews.com/impossible/. - - @param num: integer in range 0..D-1. - @return: dict representing a valid deal. - """ - assert type(num) in (int, long), "index must be an integer" - assert 0 <= num < self.D, "index not in required range" - - cardSeq = copy(self.cardSeq) # Make a copy for modification. - deal = {} - - # Split index into hand indexes. - indexes = {Direction.North : (num / self.Smax) / self.Emax, - Direction.East : (num / self.Smax) % self.Emax, - Direction.South : (num % self.Smax) } - - for position in (Direction.North, Direction.East, Direction.South): - deal[position] = [] - for k in range(13, 0, -1): - # Find the largest n such that comb(n, k) <= indexes[position]. - n = k-1 # n < k implies comb(n, k) = 0 - - # comb(n+1, k) = - # n-k = -1 => comb(n, k) * (n+1) - # otherwise => (comb(n, k) * (n+1)) / (n+1 - k) - while comb(n+1, k) <= indexes[position]: - n += 1 - - # Remove card index from indices, add card to hand. - indexes[position] -= comb(n, k) - card = cardSeq[n] - deal[position].append(card) - cardSeq.remove(card) - - deal[Direction.West] = cardSeq # West has the remaining cards. - return deal - Copied: trunk/pybridge/tests/bridge/test_deal.py (from rev 480, trunk/pybridge/tests/bridge/test_deck.py) =================================================================== --- trunk/pybridge/tests/bridge/test_deal.py (rev 0) +++ trunk/pybridge/tests/bridge/test_deal.py 2007-07-20 14:32:16 UTC (rev 485) @@ -0,0 +1,83 @@ +import unittest + +from pybridge.games.bridge.card import Card +from pybridge.games.bridge.deal import Deal +from pybridge.games.bridge.symbols import Direction, Rank, Suit + + +class TestDeck(unittest.TestCase): + + cards = sorted(Card(r, s) for r in Rank for s in Suit) + + samples = {} + + samples[1] = Deal({Direction.North: [Card(r, Suit.Spade) for r in Rank], + Direction.East: [Card(r, Suit.Heart) for r in Rank], + Direction.South: [Card(r, Suit.Diamond) for r in Rank], + Direction.West: [Card(r, Suit.Club) for r in Rank]}) + + # http://bridgehands.com/D/Duke_of_Cumberland_Hand.htm + samples[25216995119420903953708290155] = Deal.fromString( + "N:..Q8765432.AQT84 65432.T9872.JT9. T987.6543..76532 AKQJ.AKQJ.AK.KJ9") + + # http://bridgehands.com/B/John_Bennett_Murder.htm + samples[49115408832893597588305377049] = Deal.fromString( + "S:KJ985.K762.85.KT Q72.AJ3.AQT92.J6 AT63.T85.4.A9842 4.Q94.KJ763.Q753") + + # From the PBN v2.0 specification document. + samples[51845212465382378289082480212] = Deal.fromString( + "N:.63.AKQ987.A9732 A8654.KQ5.T.QJT6 J973.J98742.3.K4 KQT2.AT.J6542.85") + + # http://bridgehands.com/M/Mississippi_Heart_Hand.htm + samples[53520933857671775260919265981] = Deal.fromString( + "S:AKQ.AKQJT9..AKQJ .8765432.AKQJT9. T5432..5432.5432 J9876..876.T9876") + + + def validateDeal(self, deal): + """Checks that structure of deal conforms to requirements: + + - Each position in Direction maps to a hand, represented as a list. + - Hand lists contain exactly 13 Card objects. + - No card may be repeated in the same hand, or between hands. + + @param deal: a Deal instance. + """ + assert isinstance(deal, Deal), "deal not a Deal instance" + assert set(deal.keys()) == set(Direction), "invalid set of keys" + + extractcards = [] + for pos, hand in deal.items(): + assert len(hand) == 13, "%s hand does not contain 13 cards" % pos + extractcards.extend(hand) + assert self.cards == sorted(extractcards), "not a pure set of cards" + + + def test_generateRandom(self): + """Testing generation of random deals""" + deal = Deal.fromRandom() + try: + self.validateDeal(deal) + except Exception, e: + self.fail(e, deal) + + + def test_toIndex(self): + """Testing toIndex method over a set of known deals""" + for index, deal in self.samples.items(): + self.assertEqual(deal.toIndex(), index) + + + def test_fromIndex(self): + """Testing Deal.fromIndex over a set of known indexes""" + for index, deal in self.samples.items(): + self.assertEqual(Deal.fromIndex(index), deal) + + +def main(): + suite = unittest.makeSuite(TestDeck) + unittest.TextTestRunner(verbosity=2).run(suite) + + +if __name__ == '__main__': + main() + Deleted: trunk/pybridge/tests/bridge/test_deck.py =================================================================== --- trunk/pybridge/tests/bridge/test_deck.py 2007-07-19 15:30:30 UTC (rev 484) +++ trunk/pybridge/tests/bridge/test_deck.py 2007-07-20 14:32:16 UTC (rev 485) @@ -1,52 +0,0 @@ -import unittest - -from pybridge.games.bridge.deck import Deck - - -class TestDeck(unittest.TestCase): - - - def setUp(self): - self.deck = Deck() - - - def tearDown(self): - self.deck = None - - - def testRandomDeal(self): - """Testing randomDeal""" - for i in range(100): - deal = self.deck.randomDeal() - self.assert_(self.deck.isValidDeal(deal)) - - - def testDealToIndex(self): - """Testing dealToIndex (assuming indexToDeal correct)""" - n = 1 - while n < self.deck.D: - deal = self.deck.indexToDeal(n) - pn = self.deck.dealToIndex(deal) - self.assertEqual(n, pn) - n = n*2 + 1 - - - def testIndexToDeal(self): - """Testing indexToDeal (assuming dealToIndex and isValidDeal correct)""" - n = 1 - while n < self.deck.D: - deal = self.deck.indexToDeal(n) - self.assert_(self.deck.isValidDeal(deal)) - pn = self.deck.dealToIndex(deal) - self.assertEqual(n, pn) - n = n*2 + 1 - - -def main(): - suite = unittest.makeSuite(TestDeck) - unittest.TextTestRunner(verbosity=2).run(suite) - - -if __name__ == '__main__': - main() - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-07-23 11:28:51
|
Revision: 490 http://svn.sourceforge.net/pybridge/?rev=490&view=rev Author: umgangee Date: 2007-07-23 04:28:54 -0700 (Mon, 23 Jul 2007) Log Message: ----------- Add support for requesting and displaying user information. Modified Paths: -------------- trunk/pybridge/glade/pybridge.glade trunk/pybridge/pybridge/server/user.py trunk/pybridge/pybridge/ui/window_main.py Added Paths: ----------- trunk/pybridge/pybridge/ui/dialog_userinfo.py Modified: trunk/pybridge/glade/pybridge.glade =================================================================== --- trunk/pybridge/glade/pybridge.glade 2007-07-22 18:02:34 UTC (rev 489) +++ trunk/pybridge/glade/pybridge.glade 2007-07-23 11:28:54 UTC (rev 490) @@ -307,93 +307,6 @@ <property name="position">1</property> </packing> </child> - <child> - <widget class="GtkFrame" id="frame_tableinfo"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <child> - <widget class="GtkAlignment" id="alignment21"> - <property name="visible">True</property> - <property name="top_padding">4</property> - <property name="bottom_padding">4</property> - <property name="left_padding">4</property> - <property name="right_padding">4</property> - <child> - <widget class="GtkTable" id="table_tableinfo"> - <property name="visible">True</property> - <property name="n_rows">2</property> - <property name="n_columns">2</property> - <property name="column_spacing">8</property> - <property name="row_spacing">2</property> - <child> - <widget class="GtkLabel" id="label63"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">ID:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_tableid"> - <property name="visible">True</property> - <property name="xalign">0</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label65"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Type:</property> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_tabletype"> - <property name="visible">True</property> - <property name="xalign">0</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkLabel" id="label57"> - <property name="visible">True</property> - <property name="label" translatable="yes">Table Information</property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="type">label_item</property> - </packing> - </child> - </widget> - <packing> - <property name="position">2</property> - </packing> - </child> </widget> <packing> <property name="expand">False</property> @@ -406,9 +319,9 @@ </packing> </child> <child> - <widget class="GtkLabel" id="tab_tables"> + <widget class="GtkLabel" id="label_tabletab"> <property name="visible">True</property> - <property name="label" translatable="yes">Available Tables</property> + <property name="label" translatable="yes">Tables</property> </widget> <packing> <property name="type">tab</property> @@ -431,75 +344,29 @@ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> <property name="shadow_type">GTK_SHADOW_IN</property> <child> - <widget class="GtkIconView" id="peopleview"> + <widget class="GtkIconView" id="userview"> <property name="visible">True</property> <property name="can_focus">True</property> - <signal name="item_activated" handler="on_peopleview_item_activated"/> - <signal name="selection_changed" handler="on_peopleview_selection_changed"/> + <signal name="item_activated" handler="on_userview_item_activated"/> + <signal name="selection_changed" handler="on_userview_selection_changed"/> </widget> </child> </widget> </child> <child> - <widget class="GtkVBox" id="vbox17"> - <property name="width_request">160</property> + <widget class="GtkVButtonBox" id="buttonbox_users"> <property name="visible">True</property> - <property name="spacing">4</property> + <property name="sensitive">False</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="layout_style">GTK_BUTTONBOX_START</property> <child> - <widget class="GtkFrame" id="frame_personinfo"> + <widget class="GtkButton" id="button_userinfo"> <property name="visible">True</property> - <property name="sensitive">False</property> - <child> - <widget class="GtkAlignment" id="alignment22"> - <property name="visible">True</property> - <property name="top_padding">4</property> - <property name="bottom_padding">4</property> - <property name="left_padding">4</property> - <property name="right_padding">4</property> - <child> - <widget class="GtkTable" id="table_personinfo"> - <property name="visible">True</property> - <property name="n_rows">1</property> - <property name="n_columns">2</property> - <property name="column_spacing">8</property> - <property name="row_spacing">2</property> - <child> - <widget class="GtkLabel" id="label67"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Name:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_personname"> - <property name="visible">True</property> - <property name="xalign">0</property> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - </widget> - </child> - </widget> - </child> - <child> - <widget class="GtkLabel" id="label58"> - <property name="visible">True</property> - <property name="label" translatable="yes">Person Information</property> - <property name="use_markup">True</property> - </widget> - <packing> - <property name="type">label_item</property> - </packing> - </child> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">User Information</property> + <signal name="clicked" handler="on_userinfo_clicked"/> </widget> </child> </widget> @@ -515,9 +382,9 @@ </packing> </child> <child> - <widget class="GtkLabel" id="label_people"> + <widget class="GtkLabel" id="label_usertab"> <property name="visible">True</property> - <property name="label" translatable="yes">People Online</property> + <property name="label" translatable="yes">Users</property> </widget> <packing> <property name="type">tab</property> @@ -568,30 +435,23 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> - <widget class="GtkLabel" id="label_portnum"> + <widget class="GtkEntry" id="entry_portnum"> + <property name="width_request">80</property> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Port:</property> + <property name="can_focus">True</property> + <property name="max_length">5</property> + <property name="invisible_char">*</property> + <signal name="changed" handler="on_field_changed"/> </widget> <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkLabel" id="label_hostname"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Host Name:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> <widget class="GtkEntry" id="entry_hostname"> <property name="width_request">140</property> <property name="visible">True</property> @@ -606,19 +466,26 @@ </packing> </child> <child> - <widget class="GtkEntry" id="entry_portnum"> - <property name="width_request">80</property> + <widget class="GtkLabel" id="label_hostname"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="max_length">5</property> - <property name="invisible_char">*</property> - <signal name="changed" handler="on_field_changed"/> + <property name="xalign">0</property> + <property name="label" translatable="yes">Host Name:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_portnum"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Port:</property> + </widget> + <packing> <property name="top_attach">1</property> <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> @@ -661,26 +528,20 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> - <widget class="GtkLabel" id="label_username"> + <widget class="GtkEntry" id="entry_password"> + <property name="width_request">120</property> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">User Name:</property> + <property name="can_focus">True</property> + <property name="max_length">40</property> + <property name="visibility">False</property> + <property name="invisible_char">*</property> + <signal name="changed" handler="on_field_changed"/> </widget> <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_password"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Password:</property> - </widget> - <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> @@ -700,23 +561,29 @@ </packing> </child> <child> - <widget class="GtkEntry" id="entry_password"> - <property name="width_request">120</property> + <widget class="GtkLabel" id="label_password"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="max_length">40</property> - <property name="visibility">False</property> - <property name="invisible_char">*</property> - <signal name="changed" handler="on_field_changed"/> + <property name="xalign">0</property> + <property name="label" translatable="yes">Password:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> + <child> + <widget class="GtkLabel" id="label_username"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">User Name:</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> </widget> </child> <child> @@ -818,6 +685,7 @@ <property name="title" translatable="yes">Create a New Table</property> <property name="resizable">False</property> <property name="modal">True</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> <property name="skip_taskbar_hint">True</property> <property name="gravity">GDK_GRAVITY_CENTER</property> @@ -840,53 +708,53 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> - <widget class="GtkLabel" id="label_gamelist"> + <widget class="GtkLabel" id="label_tablename"> <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Game at Table:</property> + <property name="label" translatable="yes">Table Name:</property> </widget> <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkComboBox" id="gamelist"> + <widget class="GtkEntry" id="tablename"> + <property name="width_request">140</property> <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <signal name="changed" handler="on_gamelist_changed"/> + <property name="can_focus">True</property> + <property name="invisible_char">*</property> + <signal name="changed" handler="on_tablename_changed"/> </widget> <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> <property name="y_options">GTK_FILL</property> </packing> </child> <child> - <widget class="GtkEntry" id="tablename"> - <property name="width_request">140</property> + <widget class="GtkComboBox" id="gamelist"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">*</property> - <signal name="changed" handler="on_tablename_changed"/> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="changed" handler="on_gamelist_changed"/> </widget> <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> <property name="y_options">GTK_FILL</property> </packing> </child> <child> - <widget class="GtkLabel" id="label_tablename"> + <widget class="GtkLabel" id="label_gamelist"> <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Table Name:</property> + <property name="label" translatable="yes">Game at Table:</property> </widget> <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> <property name="y_options"></property> </packing> </child> @@ -942,6 +810,7 @@ <property name="border_width">5</property> <property name="title" translatable="yes">PyBridge Preferences</property> <property name="resizable">False</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> <property name="has_separator">False</property> <child internal-child="vbox"> @@ -966,72 +835,6 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> - <widget class="GtkFileChooserButton" id="background"> - <property name="width_request">160</property> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <signal name="selection_changed" handler="on_background_changed"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - </packing> - </child> - <child> - <widget class="GtkComboBox" id="cardstyle"> - <property name="width_request">160</property> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <signal name="changed" handler="on_cardstyle_changed"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_background"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Background:</property> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_cardstyle"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Card Style:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_suitcolours"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Suit Colours:</property> - </widget> - <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> <widget class="GtkHBox" id="hbox2"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> @@ -1128,6 +931,72 @@ <property name="bottom_attach">3</property> </packing> </child> + <child> + <widget class="GtkLabel" id="label_suitcolours"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Suit Colours:</property> + </widget> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_cardstyle"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Card Style:</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_background"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Background:</property> + </widget> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cardstyle"> + <property name="width_request">160</property> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="changed" handler="on_cardstyle_changed"/> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <widget class="GtkFileChooserButton" id="background"> + <property name="width_request">160</property> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="selection_changed" handler="on_background_changed"/> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> </widget> <packing> <property name="expand">False</property> @@ -1211,4 +1080,95 @@ </widget> </child> </widget> + <widget class="GtkDialog" id="dialog_userinfo"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="border_width">5</property> + <property name="title" translatable="yes">User Information</property> + <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="has_separator">False</property> + <signal name="delete_event" handler="on_delete_event"/> + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox6"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="spacing">2</property> + <child> + <widget class="GtkAlignment" id="alignment1"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="top_padding">4</property> + <property name="bottom_padding">4</property> + <property name="left_padding">4</property> + <property name="right_padding">4</property> + <child> + <widget class="GtkVBox" id="vbox3"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="spacing">8</property> + <child> + <widget class="GtkLabel" id="label_userinfo"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">0</property> + <property name="use_markup">True</property> + </widget> + <packing> + <property name="expand">False</property> + </packing> + </child> + <child> + <widget class="GtkScrolledWindow" id="scrolled_userinfo"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <child> + <widget class="GtkTextView" id="userinfo"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="editable">False</property> + </widget> + </child> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + </widget> + </child> + </widget> + <packing> + <property name="position">1</property> + </packing> + </child> + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area6"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + <child> + <widget class="GtkButton" id="closebutton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label" translatable="yes">gtk-close</property> + <property name="use_stock">True</property> + <signal name="clicked" handler="on_closebutton_clicked"/> + </widget> + </child> + </widget> + <packing> + <property name="expand">False</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + </widget> + </child> + </widget> </glade-interface> Modified: trunk/pybridge/pybridge/server/user.py =================================================================== --- trunk/pybridge/pybridge/server/user.py 2007-07-22 18:02:34 UTC (rev 489) +++ trunk/pybridge/pybridge/server/user.py 2007-07-23 11:28:54 UTC (rev 490) @@ -75,7 +75,7 @@ def perspective_getUserInformation(self, username=None): """Returns public information for user with specified username. - If username is unspecified, returns user's own profile. + If username is unspecified, returns user's own public information. """ if username is None: username = self.name @@ -85,8 +85,13 @@ except IndexError: raise DeniedRequest, "Specified user does not exist" - return {'realname': user.realname, 'email': user.email, - 'profile': user.profile} + info = {} + for field in 'realname', 'email', 'country', 'profile': + value = getattr(user, field, None) + # Do not send unspecified (null) values. + if value is not None: + info[field] = value + return info # def perspective_setProfile(self, **kwargs): Added: trunk/pybridge/pybridge/ui/dialog_userinfo.py =================================================================== --- trunk/pybridge/pybridge/ui/dialog_userinfo.py (rev 0) +++ trunk/pybridge/pybridge/ui/dialog_userinfo.py 2007-07-23 11:28:54 UTC (rev 490) @@ -0,0 +1,79 @@ +# 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. + + +import gtk, pango + +from manager import wm +from wrapper import GladeWrapper + + +class DialogUserInfo(GladeWrapper): + + glade_name = 'dialog_userinfo' + + fields = [('realname', _('Real Name')), + ('email', _('Email Address')), + ('country', ('Country')), + ('profile', _('Profile'))] + + texttags = {'heading': {'weight': pango.WEIGHT_BOLD}, + 'value': {}, + 'value-unknown': {'foreground': 'gray'}, + } + + + def setUp(self): + self.userinfo.set_size_request(320, 160) + + # Populate information textview with text tags. + tagtable = self.userinfo.get_buffer().get_tag_table() + for tagname, tagattrs in self.texttags.items(): + tag = gtk.TextTag(tagname) + for attrname, attrvalue in tagattrs.items(): + tag.set_property(attrname, attrvalue) + tagtable.add(tag) + + + def setUserInfo(self, username, info): + self.label_userinfo.set_markup("<span size='large'><b>%s</b></span>" % + _('Information for %(user)s') % {'user': username}) + + # Populate information textview. + buffer = self.userinfo.get_buffer() + + # Display recognised fields in order. + for id, title in self.fields: + buffer.insert_with_tags_by_name(buffer.get_end_iter(), title, 'heading') + buffer.insert(buffer.get_end_iter(), ': ') + + value = info.get(id) + if value: + buffer.insert_with_tags_by_name(buffer.get_end_iter(), value, 'value') + else: + buffer.insert_with_tags_by_name(buffer.get_end_iter(), _('not specified'), 'value-unknown') + + buffer.insert(buffer.get_end_iter(), '\n') + + + def on_closebutton_clicked(self, widget, *args): + wm.close(self) + + + def on_delete_event(self, widget, *args): + self.on_closebutton_clicked(widget, *args) + Modified: trunk/pybridge/pybridge/ui/window_main.py =================================================================== --- trunk/pybridge/pybridge/ui/window_main.py 2007-07-22 18:02:34 UTC (rev 489) +++ trunk/pybridge/pybridge/ui/window_main.py 2007-07-23 11:28:54 UTC (rev 490) @@ -33,6 +33,7 @@ from dialog_connection import DialogConnection from dialog_newtable import DialogNewtable from dialog_preferences import DialogPreferences +from dialog_userinfo import DialogUserInfo # TODO: import all Window*Table classes automatically. from pybridge.games.bridge.ui.window_bridgetable import WindowBridgeTable @@ -46,7 +47,7 @@ glade_name = 'window_main' tableview_icon = gtk.gdk.pixbuf_new_from_file_at_size(TABLE_ICON, 48, 48) - peopleview_icon = gtk.gdk.pixbuf_new_from_file_at_size(USER_ICON, 48, 48) + userview_icon = gtk.gdk.pixbuf_new_from_file_at_size(USER_ICON, 48, 48) def setUp(self): @@ -56,17 +57,16 @@ # Set up table model and icon view. self.tableview.set_text_column(0) self.tableview.set_pixbuf_column(1) - self.tableview_model = gtk.ListStore(str, gtk.gdk.Pixbuf) - self.tableview_model.set_sort_column_id(0, gtk.SORT_ASCENDING) - self.tableview.set_model(self.tableview_model) + model = gtk.ListStore(str, gtk.gdk.Pixbuf) + model.set_sort_column_id(0, gtk.SORT_ASCENDING) + self.tableview.set_model(model) - # Set up people model and icon view. - # TODO: allow users to provide their own "avatar" icons. - self.peopleview.set_text_column(0) - self.peopleview.set_pixbuf_column(1) - self.peopleview_model = gtk.ListStore(str, gtk.gdk.Pixbuf) - self.peopleview_model.set_sort_column_id(0, gtk.SORT_ASCENDING) - self.peopleview.set_model(self.peopleview_model) + # Set up user model and icon view. + self.userview.set_text_column(0) + self.userview.set_pixbuf_column(1) + model = gtk.ListStore(str, gtk.gdk.Pixbuf) + model.set_sort_column_id(0, gtk.SORT_ASCENDING) + self.userview.set_model(model) # Attach event handler to listen for events. self.eventHandler = SimpleEventHandler(self) @@ -87,6 +87,7 @@ def quit(self): """Shut down gracefully.""" + client.detach(self.eventHandler) wm.close(self) reactor.stop() gtk.main_quit() @@ -94,6 +95,7 @@ def errback(self, failure): print "Error: %s" % failure.getErrorMessage() + print failure.getTraceback() # Event handlers. @@ -115,10 +117,11 @@ self.menu_connect.set_property('visible', True) self.menu_disconnect.set_property('visible', False) self.menu_newtable.set_property('sensitive', False) - self.newtable.set_property('sensitive', False) + #self.newtable.set_property('sensitive', False) - self.tableview_model.clear() - self.peopleview_model.clear() + print self.tableview.get_model() + self.tableview.get_model().clear() + self.userview.get_model().clear() def event_connectionLost(self, host, port): @@ -142,8 +145,8 @@ def event_gotRoster(self, name, roster): - lookup = {'tables' : (self.tableview_model, self.tableview_icon), - 'users' : (self.peopleview_model, self.peopleview_icon)} + lookup = {'tables' : (self.tableview.get_model(), self.tableview_icon), + 'users' : (self.userview.get_model(), self.userview_icon)} try: model, icon = lookup[name] @@ -167,7 +170,7 @@ """Adds a table to the table listing.""" # Only display table if it supported by client. if info['gamename'] in SUPPORTED_GAMES: - self.tableview_model.append([tableid, self.tableview_icon]) + self.tableview.get_model().append([tableid, self.tableview_icon]) def event_closeTable(self, tableid): @@ -177,13 +180,14 @@ if model.get_value(iter, 0) in user_data: model.remove(iter) return True - - self.tableview_model.foreach(func, tableid) + model = self.tableview.get_model() + model.foreach(func, tableid) + def event_userLogin(self, username, info): """Adds a user to the people listing.""" - self.peopleview_model.append([username, self.peopleview_icon]) + self.userview.get_model().append([username, self.userview_icon]) def event_userLogout(self, username): @@ -193,10 +197,11 @@ if model.get_value(iter, 0) in user_data: model.remove(iter) return True - - self.peopleview_model.foreach(func, username) + model = self.userview.get_model() + model.foreach(func, username) + # Signal handlers. @@ -205,8 +210,9 @@ def on_tableview_item_activated(self, iconview, path, *args): - iter = self.tableview_model.get_iter(path) - tableid = self.tableview_model.get_value(iter, 0) + model = self.tableview.get_model() + iter = model.get_iter(path) + tableid = model.get_value(iter, 0) if tableid not in client.tables: d = client.joinTable(tableid) d.addErrback(self.errback) @@ -216,32 +222,40 @@ def on_tableview_selection_changed(self, iconview, *args): cursor = self.tableview.get_cursor() if cursor: # Ensure cursor contains a path, not None. - iter = self.tableview_model.get_iter(cursor[0]) # Path. - tableid = self.tableview_model.get_value(iter, 0) + model = self.tableview.get_model() + iter = model.get_iter(cursor[0]) # Path. + tableid = model.get_value(iter, 0) # If client not joined to table, enable Join Table button. sensitive = tableid not in client.tables self.jointable.set_property('sensitive', sensitive) - # Display information about table. - self.frame_tableinfo.set_property('sensitive', True) - self.label_tableid.set_text(tableid) - self.label_tabletype.set_text(client.tableRoster[tableid]['gamename']) else: - self.frame_tableinfo.set_property('sensitive', False) - self.label_tableid.set_text('') - self.label_tabletype.set_text('') + self.jointable.set_property('sensitive', False) - def on_peopleview_selection_changed(self, iconview, *args): - cursor = self.peopleview.get_cursor() + def on_userview_item_activated(self, iconview, path, *args): + model = self.userview.get_model() + iter = model.get_iter(path) + username = model.get_value(iter, 0) + + # Allow one DialogUserInfo instance for each user. + winid = (DialogUserInfo, username) + + def gotUserInfo(info): + w = wm.open(DialogUserInfo, winid) + w.setUserInfo(username, info) + + if not wm.get(winid): + # TODO: if user info in cache, do not request again from server. + d = client.getUserInformation(username) + d.addCallback(gotUserInfo) + + + def on_userview_selection_changed(self, iconview, *args): + cursor = self.userview.get_cursor() if cursor: # Ensure cursor contains a path, not None. - iter = self.peopleview_model.get_iter(cursor[0]) # Path. - person = self.peopleview_model.get_value(iter, 0) - # Display information about person. - self.frame_personinfo.set_property('sensitive', True) - self.label_personname.set_text(person) + self.buttonbox_users.set_property('sensitive', True) else: - self.frame_personinfo.set_property('sensitive', False) - self.label_personname.set_text('') + self.buttonbox_users.set_property('sensitive', False) def on_window_main_delete_event(self, widget, *args): @@ -258,6 +272,11 @@ self.on_tableview_item_activated(self.tableview, path) + def on_userinfo_clicked(self, widget, *args): + path = self.userview.get_cursor()[0] + self.on_userview_item_activated(self.userview, path) + + def on_connect_activate(self, widget, *args): if not wm.get(DialogConnection): wm.open(DialogConnection) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2007-07-24 19:30:20
|
Revision: 494 http://svn.sourceforge.net/pybridge/?rev=494&view=rev Author: umgangee Date: 2007-07-24 12:30:16 -0700 (Tue, 24 Jul 2007) Log Message: ----------- Improvements to the logic and appearance of tableview and userview widgets, plus a fix for https://bugs.launchpad.net/pybridge/+bug/127974 Modified Paths: -------------- trunk/pybridge/glade/pybridge.glade trunk/pybridge/pybridge/ui/window_main.py Modified: trunk/pybridge/glade/pybridge.glade =================================================================== --- trunk/pybridge/glade/pybridge.glade 2007-07-24 17:22:23 UTC (rev 493) +++ trunk/pybridge/glade/pybridge.glade 2007-07-24 19:30:16 UTC (rev 494) @@ -5,7 +5,7 @@ <widget class="GtkWindow" id="window_main"> <property name="visible">True</property> <property name="title" translatable="yes">PyBridge</property> - <signal name="delete_event" handler="on_window_main_delete_event"/> + <signal name="delete_event" handler="on_delete_event"/> <child> <widget class="GtkVBox" id="vbox1"> <property name="visible">True</property> @@ -189,7 +189,7 @@ <property name="border_width">8</property> <property name="spacing">8</property> <child> - <widget class="GtkScrolledWindow" id="scrolledwindow5"> + <widget class="GtkScrolledWindow" id="scrolled_tableview"> <property name="width_request">320</property> <property name="height_request">240</property> <property name="visible">True</property> @@ -208,103 +208,33 @@ </widget> </child> <child> - <widget class="GtkVBox" id="vbox16"> - <property name="width_request">160</property> + <widget class="GtkToolbar" id="toolbar_tables"> <property name="visible">True</property> - <property name="spacing">4</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="orientation">GTK_ORIENTATION_VERTICAL</property> + <property name="toolbar_style">GTK_TOOLBAR_BOTH</property> <child> - <widget class="GtkButton" id="newtable"> + <widget class="GtkToolButton" id="newtable"> <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label">New Table...</property> + <property name="stock_id">gtk-new</property> <signal name="clicked" handler="on_newtable_clicked"/> - <child> - <widget class="GtkAlignment" id="alignment19"> - <property name="visible">True</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <child> - <widget class="GtkHBox" id="hbox24"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <widget class="GtkImage" id="image322"> - <property name="visible">True</property> - <property name="stock">gtk-new</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label55"> - <property name="visible">True</property> - <property name="label" translatable="yes">New Table...</property> - <property name="use_underline">True</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </widget> - </child> - </widget> - </child> </widget> <packing> <property name="expand">False</property> - <property name="fill">False</property> </packing> </child> <child> - <widget class="GtkButton" id="jointable"> + <widget class="GtkToolButton" id="jointable"> <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="label">Join Table</property> + <property name="stock_id">gtk-jump-to</property> <signal name="clicked" handler="on_jointable_clicked"/> - <child> - <widget class="GtkAlignment" id="alignment20"> - <property name="visible">True</property> - <property name="xscale">0</property> - <property name="yscale">0</property> - <child> - <widget class="GtkHBox" id="hbox25"> - <property name="visible">True</property> - <property name="spacing">2</property> - <child> - <widget class="GtkImage" id="image323"> - <property name="visible">True</property> - <property name="stock">gtk-jump-to</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label56"> - <property name="visible">True</property> - <property name="label" translatable="yes">Join This Table</property> - <property name="use_underline">True</property> - </widget> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </widget> - </child> - </widget> - </child> </widget> <packing> <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> </packing> </child> </widget> @@ -321,7 +251,7 @@ <child> <widget class="GtkLabel" id="label_tabletab"> <property name="visible">True</property> - <property name="label" translatable="yes">Tables</property> + <property name="label" translatable="yes">Open Tables</property> </widget> <packing> <property name="type">tab</property> @@ -335,7 +265,7 @@ <property name="border_width">8</property> <property name="spacing">8</property> <child> - <widget class="GtkScrolledWindow" id="scrolledwindow9"> + <widget class="GtkScrolledWindow" id="scrolled_userview"> <property name="width_request">320</property> <property name="height_request">240</property> <property name="visible">True</property> @@ -354,20 +284,21 @@ </widget> </child> <child> - <widget class="GtkVButtonBox" id="buttonbox_users"> + <widget class="GtkToolbar" id="toolbar_users"> <property name="visible">True</property> - <property name="sensitive">False</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="layout_style">GTK_BUTTONBOX_START</property> + <property name="orientation">GTK_ORIENTATION_VERTICAL</property> + <property name="toolbar_style">GTK_TOOLBAR_BOTH</property> <child> - <widget class="GtkButton" id="button_userinfo"> + <widget class="GtkToolButton" id="userinfo"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="label" translatable="yes">User Information</property> + <property name="stock_id">gtk-info</property> <signal name="clicked" handler="on_userinfo_clicked"/> </widget> + <packing> + <property name="expand">False</property> + </packing> </child> </widget> <packing> @@ -384,7 +315,7 @@ <child> <widget class="GtkLabel" id="label_usertab"> <property name="visible">True</property> - <property name="label" translatable="yes">Users</property> + <property name="label" translatable="yes">Users Online</property> </widget> <packing> <property name="type">tab</property> @@ -435,23 +366,30 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> - <widget class="GtkEntry" id="entry_portnum"> - <property name="width_request">80</property> + <widget class="GtkLabel" id="label_portnum"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="max_length">5</property> - <property name="invisible_char">*</property> - <signal name="changed" handler="on_field_changed"/> + <property name="xalign">0</property> + <property name="label" translatable="yes">Port:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> <child> + <widget class="GtkLabel" id="label_hostname"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Host Name:</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> <widget class="GtkEntry" id="entry_hostname"> <property name="width_request">140</property> <property name="visible">True</property> @@ -466,26 +404,19 @@ </packing> </child> <child> - <widget class="GtkLabel" id="label_hostname"> + <widget class="GtkEntry" id="entry_portnum"> + <property name="width_request">80</property> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Host Name:</property> + <property name="can_focus">True</property> + <property name="max_length">5</property> + <property name="invisible_char">*</property> + <signal name="changed" handler="on_field_changed"/> </widget> <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_portnum"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Port:</property> - </widget> - <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> @@ -528,20 +459,26 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> - <widget class="GtkEntry" id="entry_password"> - <property name="width_request">120</property> + <widget class="GtkLabel" id="label_username"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="max_length">40</property> - <property name="visibility">False</property> - <property name="invisible_char">*</property> - <signal name="changed" handler="on_field_changed"/> + <property name="xalign">0</property> + <property name="label" translatable="yes">User Name:</property> </widget> <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_password"> + <property name="visible">True</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Password:</property> + </widget> + <packing> <property name="top_attach">1</property> <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> @@ -561,29 +498,23 @@ </packing> </child> <child> - <widget class="GtkLabel" id="label_password"> + <widget class="GtkEntry" id="entry_password"> + <property name="width_request">120</property> <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Password:</property> + <property name="can_focus">True</property> + <property name="max_length">40</property> + <property name="visibility">False</property> + <property name="invisible_char">*</property> + <signal name="changed" handler="on_field_changed"/> </widget> <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> <property name="top_attach">1</property> <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> <property name="y_options"></property> </packing> </child> - <child> - <widget class="GtkLabel" id="label_username"> - <property name="visible">True</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">User Name:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> </widget> </child> <child> @@ -708,53 +639,53 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> - <widget class="GtkLabel" id="label_tablename"> + <widget class="GtkLabel" id="label_gamelist"> <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Table Name:</property> + <property name="label" translatable="yes">Game at Table:</property> </widget> <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> <property name="y_options"></property> </packing> </child> <child> - <widget class="GtkEntry" id="tablename"> - <property name="width_request">140</property> + <widget class="GtkComboBox" id="gamelist"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="invisible_char">*</property> - <signal name="changed" handler="on_tablename_changed"/> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="changed" handler="on_gamelist_changed"/> </widget> <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> <property name="y_options">GTK_FILL</property> </packing> </child> <child> - <widget class="GtkComboBox" id="gamelist"> + <widget class="GtkEntry" id="tablename"> + <property name="width_request">140</property> <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <signal name="changed" handler="on_gamelist_changed"/> + <property name="can_focus">True</property> + <property name="invisible_char">*</property> + <signal name="changed" handler="on_tablename_changed"/> </widget> <packing> <property name="left_attach">1</property> <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> <property name="y_options">GTK_FILL</property> </packing> </child> <child> - <widget class="GtkLabel" id="label_gamelist"> + <widget class="GtkLabel" id="label_tablename"> <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="xalign">0</property> - <property name="label" translatable="yes">Game at Table:</property> + <property name="label" translatable="yes">Table Name:</property> </widget> <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> <property name="y_options"></property> </packing> </child> @@ -835,6 +766,72 @@ <property name="column_spacing">8</property> <property name="row_spacing">4</property> <child> + <widget class="GtkFileChooserButton" id="background"> + <property name="width_request">160</property> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="selection_changed" handler="on_background_changed"/> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + </packing> + </child> + <child> + <widget class="GtkComboBox" id="cardstyle"> + <property name="width_request">160</property> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <signal name="changed" handler="on_cardstyle_changed"/> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_background"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Background:</property> + </widget> + <packing> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_cardstyle"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Card Style:</property> + </widget> + <packing> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> + <widget class="GtkLabel" id="label_suitcolours"> + <property name="visible">True</property> + <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> + <property name="xalign">0</property> + <property name="label" translatable="yes">Suit Colours:</property> + </widget> + <packing> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">GTK_FILL</property> + <property name="y_options"></property> + </packing> + </child> + <child> <widget class="GtkHBox" id="hbox2"> <property name="visible">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> @@ -931,72 +928,6 @@ <property name="bottom_attach">3</property> </packing> </child> - <child> - <widget class="GtkLabel" id="label_suitcolours"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Suit Colours:</property> - </widget> - <packing> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_cardstyle"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Card Style:</property> - </widget> - <packing> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkLabel" id="label_background"> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="xalign">0</property> - <property name="label" translatable="yes">Background:</property> - </widget> - <packing> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - <property name="x_options">GTK_FILL</property> - <property name="y_options"></property> - </packing> - </child> - <child> - <widget class="GtkComboBox" id="cardstyle"> - <property name="width_request">160</property> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <signal name="changed" handler="on_cardstyle_changed"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - </packing> - </child> - <child> - <widget class="GtkFileChooserButton" id="background"> - <property name="width_request">160</property> - <property name="visible">True</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <signal name="selection_changed" handler="on_background_changed"/> - </widget> - <packing> - <property name="left_attach">1</property> - <property name="right_attach">2</property> - <property name="top_attach">1</property> - <property name="bottom_attach">2</property> - </packing> - </child> </widget> <packing> <property name="expand">False</property> Modified: trunk/pybridge/pybridge/ui/window_main.py =================================================================== --- trunk/pybridge/pybridge/ui/window_main.py 2007-07-24 17:22:23 UTC (rev 493) +++ trunk/pybridge/pybridge/ui/window_main.py 2007-07-24 19:30:16 UTC (rev 494) @@ -28,6 +28,7 @@ from pybridge.network.client import client from eventhandler import SimpleEventHandler +from excepthook import exceptdialog from manager import wm from dialog_connection import DialogConnection @@ -39,33 +40,29 @@ # TODO: import all Window*Table classes automatically. from pybridge.games.bridge.ui.window_bridgetable import WindowBridgeTable -TABLE_ICON = env.find_pixmap("table.png") -USER_ICON = env.find_pixmap("user.png") +TABLE_ICON = env.find_pixmap('table.png') +USER_ICON = env.find_pixmap('user.png') class WindowMain(GladeWrapper): glade_name = 'window_main' - tableview_icon = gtk.gdk.pixbuf_new_from_file_at_size(TABLE_ICON, 48, 48) - userview_icon = gtk.gdk.pixbuf_new_from_file_at_size(USER_ICON, 48, 48) + table_icon = gtk.gdk.pixbuf_new_from_file_at_size(TABLE_ICON, 48, 48) + user_icon = gtk.gdk.pixbuf_new_from_file_at_size(USER_ICON, 48, 48) def setUp(self): - # Set up table model and icon view. - self.tableview.set_text_column(0) - self.tableview.set_pixbuf_column(1) - model = gtk.ListStore(str, gtk.gdk.Pixbuf) - model.set_sort_column_id(0, gtk.SORT_ASCENDING) - self.tableview.set_model(model) + # Track iters in ListStore objects, for O(1) lookups. + self.tableview_iters, self.userview_iters = {}, {} + # Set up tableview and userview. + for view in self.tableview, self.userview: + view.set_text_column(0) + view.set_pixbuf_column(1) + model = gtk.ListStore(str, gtk.gdk.Pixbuf) + model.set_sort_column_id(0, gtk.SORT_ASCENDING) + view.set_model(model) - # Set up user model and icon view. - self.userview.set_text_column(0) - self.userview.set_pixbuf_column(1) - model = gtk.ListStore(str, gtk.gdk.Pixbuf) - model.set_sort_column_id(0, gtk.SORT_ASCENDING) - self.userview.set_model(model) - # Attach event handler to listen for events. self.eventHandler = SimpleEventHandler(self) client.attach(self.eventHandler) @@ -75,25 +72,23 @@ def tearDown(self): - # TODO: detach event handler from all attached subjects. - - # Close all windows. - for window in wm.values(): - wm.close(window) client.disconnect() + client.detach(self.eventHandler) + # Terminate. + reactor.stop() + gtk.main_quit() def quit(self): """Shut down gracefully.""" - client.detach(self.eventHandler) - wm.close(self) - reactor.stop() - gtk.main_quit() + # TODO: if playing a game, ensure that user really wants to quit. + wm.close(self) # Triggers tearDown. def errback(self, failure): - print "Error: %s" % failure.getErrorMessage() - print failure.getTraceback() + message = "Network error: %s\n\n%s" % (failure.getErrorMessage(), + failure.getTraceback()) + exceptdialog(message) # Event handlers. @@ -104,7 +99,10 @@ self.menu_connect.set_property('visible', False) self.menu_disconnect.set_property('visible', True) self.menu_newtable.set_property('sensitive', True) + self.newtable.set_property('sensitive', True) + self.jointable.set_property('sensitive', False) + self.userinfo.set_property('sensitive', False) def event_loggedOut(self): @@ -116,10 +114,9 @@ self.menu_connect.set_property('visible', True) self.menu_disconnect.set_property('visible', False) self.menu_newtable.set_property('sensitive', False) - #self.newtable.set_property('sensitive', False) - self.tableview.get_model().clear() - self.userview.get_model().clear() + self.tableview.get_model().clear(); self.tableview_iters.clear() + self.userview.get_model().clear(); self.userview_iters.clear() def event_connectionLost(self, host, port): @@ -143,54 +140,48 @@ def event_gotRoster(self, name, roster): - lookup = {'tables' : (self.tableview.get_model(), self.tableview_icon), - 'users' : (self.userview.get_model(), self.userview_icon)} - + lookup = {'tables' : (self.tableview.get_model(), self.table_icon, self.tableview_iters), + 'users' : (self.userview.get_model(), self.user_icon, self.userview_iters)} try: - model, icon = lookup[name] + model, icon, view_iters = lookup[name] for id, info in roster.items(): - model.append([id, icon]) + iter = model.append([id, icon]) + view_iters[id] = iter roster.attach(self.eventHandler) except KeyError: pass # Ignore an unrecognised roster. def event_openTable(self, tableid, info): - """Adds a table to the table listing.""" # Only display table if it supported by client. if info['gamename'] in SUPPORTED_GAMES: - self.tableview.get_model().append([tableid, self.tableview_icon]) + model = self.tableview.get_model() + iter = model.append([tableid, self.table_icon]) + self.tableview_iters[tableid] = iter def event_closeTable(self, tableid): - """Removes a table from the table listing.""" - - def func(model, path, iter, user_data): - if model.get_value(iter, 0) in user_data: - model.remove(iter) - return True + iter = self.tableview_iters.get(tableid) + if iter: + model = self.tableview.get_model() + model.remove(iter) + del self.tableview_iters[tableid] - model = self.tableview.get_model() - model.foreach(func, tableid) - def event_userLogin(self, username, info): - """Adds a user to the people listing.""" - self.userview.get_model().append([username, self.userview_icon]) + model = self.userview.get_model() + iter = model.append([username, self.user_icon]) + self.userview_iters[username] = iter def event_userLogout(self, username): - """Removes a user from the people listing.""" - - def func(model, path, iter, user_data): - if model.get_value(iter, 0) in user_data: - model.remove(iter) - return True + iter = self.userview_iters.get(username) + if iter: + model = self.userview.get_model() + model.remove(iter) + del self.userview_iters[username] - model = self.userview.get_model() - model.foreach(func, username) - # Signal handlers. @@ -199,16 +190,16 @@ def on_tableview_item_activated(self, iconview, path, *args): + model = self.tableview.get_model() + iter = model.get_iter(path) + tableid = model.get_value(iter, 0) def joinedTable(table): # TODO: select correct table window class. window = wm.open(WindowBridgeTable, id=tableid) window.setTable(table) - model = self.tableview.get_model() - iter = model.get_iter(path) - tableid = model.get_value(iter, 0) - if tableid not in client.tables: + if tableid not in client.tables: # Already joined table? d = client.joinTable(tableid) d.addCallbacks(joinedTable, self.errback) self.jointable.set_property('sensitive', False) @@ -236,27 +227,20 @@ winid = (DialogUserInfo, username) def gotUserInfo(info): - w = wm.open(DialogUserInfo, winid) + w = wm.open(DialogUserInfo, id=winid) w.setUserInfo(username, info) if not wm.get(winid): - # TODO: if user info in cache, do not request again from server. d = client.getUserInformation(username) d.addCallback(gotUserInfo) def on_userview_selection_changed(self, iconview, *args): cursor = self.userview.get_cursor() - if cursor: # Ensure cursor contains a path, not None. - self.buttonbox_users.set_property('sensitive', True) - else: - self.buttonbox_users.set_property('sensitive', False) + # If cursor contains a path, enable User Info button. + self.userinfo.set_property('sensitive', bool(cursor)) - def on_window_main_delete_event(self, widget, *args): - self.quit() - - def on_newtable_clicked(self, widget, *args): if not wm.get(DialogNewtable): wm.open(DialogNewtable) @@ -335,3 +319,8 @@ about.connect('response', dialog_response_cb) about.show() + + def on_delete_event(self, widget, *args): + self.quit() + return True # Stops window deletion taking place. + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <umg...@us...> - 2008-05-10 09:51:33
|
Revision: 507 http://pybridge.svn.sourceforge.net/pybridge/?rev=507&view=rev Author: umgangee Date: 2008-05-10 02:51:38 -0700 (Sat, 10 May 2008) Log Message: ----------- A variety of changes, that, for some reason, weren't committed last year. Modified Paths: -------------- trunk/pybridge/INSTALL trunk/pybridge/NEWS trunk/pybridge/README trunk/pybridge/locale/src/Makefile trunk/pybridge/pybridge/__init__.py trunk/pybridge/pybridge/games/bridge/ui/window_scoresheet.py trunk/pybridge/pybridge/network/remotetable.py trunk/pybridge/pybridge/server/database.py trunk/pybridge/pybridge/ui/dialog_connection.py trunk/pybridge/pybridge/ui/window_chat.py trunk/pybridge/pybridge/ui/window_gametable.py trunk/pybridge/setup.py trunk/pybridge/tests/bridge/test_deal.py trunk/pybridge/tests/monkey.py Modified: trunk/pybridge/INSTALL =================================================================== --- trunk/pybridge/INSTALL 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/INSTALL 2008-05-10 09:51:38 UTC (rev 507) @@ -38,7 +38,7 @@ - PyGTK (>= 2.8) - http://www.pygtk.org/ - Cairo (>= 1.0) - http://cairographics.org/ - PyCairo (>= 1.0) - http://cairographics.org/pycairo/ - - ConfigObj (>= 4.0) -http://www.voidspace.org.uk/python/configobj.html + - ConfigObj (>= 4.0) - http://www.voidspace.org.uk/python/configobj.html To run the standalone PyBridge server, the following software is also required: Modified: trunk/pybridge/NEWS =================================================================== --- trunk/pybridge/NEWS 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/NEWS 2008-05-10 09:51:38 UTC (rev 507) @@ -1,3 +1,39 @@ +========== +0.4.0 (??) +========== + +New features +------------ + + - Architecture: + + - Full support for other games. + + + - User interface: + + - Separation of bridge table UI from generic table window. Tables for particular games inherit. + + - Enhanced chat support. + + +Bug fixes +--------- + + - Fixed https://bugs.launchpad.net/pybridge/+bug/127974 + + +Translations +------------ + + - French: Aldo Reset <al...@pl...> + + - Polish: + + Please help with translating PyBridge into your native language! + See https://translations.launchpad.net/pybridge/ to get started. + + ===================== 0.3.0 (25 June 2007) ===================== Modified: trunk/pybridge/README =================================================================== --- trunk/pybridge/README 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/README 2008-05-10 09:51:38 UTC (rev 507) @@ -1,6 +1,7 @@ -PyBridge 0.3.0 - a free online bridge game +PyBridge 0.4.0 - a free online bridge game http://pybridge.sourceforge.net/ http://sourceforge.net/projects/pybridge/ +https://launchpad.net/pybridge About PyBridge @@ -31,12 +32,12 @@ Your feedback, bug reports and ideas for new features are especially welcome. - - Forums: http://sourceforge.net/forum/?group_id=114287 + - Bug reports: https://bugs.launchpad.net/pybridge/ - - Bug reports: http://sourceforge.net/tracker/?group_id=114287&atid=667822 + - Feature ideas: https://blueprints.launchpad.net/pybridge/ + + - Translations: https://translations.launchpad.net/pybridge/ - - Feature ideas: http://sourceforge.net/tracker/?group_id=114287&atid=667825 - If you are a competent (or aspiring!) Python programmer and would like to contribute code to PyBridge, then please get in touch with the developers! Modified: trunk/pybridge/locale/src/Makefile =================================================================== --- trunk/pybridge/locale/src/Makefile 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/locale/src/Makefile 2008-05-10 09:51:38 UTC (rev 507) @@ -18,12 +18,12 @@ msgmerge -UN $@ $< #Generic rule for POT files -%.pot: ../../glade/pybridge.glade ../../pybridge/ui/*.py +%.pot: ../../glade/pybridge.glade ############ #CREATING $@ ############ intltool-extract --type=gettext/glade ../../glade/pybridge.glade - xgettext -k_ -kN_ --from-code=UTF-8 -o $@ ../../glade/pybridge.glade.h ../../pybridge/ui/*.py + xgettext -k_ -kN_ --from-code=UTF-8 -o $@ ../../glade/pybridge.glade.h ../../pybridge/ui/*.py ../../pybridge/games/bridge/ui/*.py update: $(shell ls *.po) Modified: trunk/pybridge/pybridge/__init__.py =================================================================== --- trunk/pybridge/pybridge/__init__.py 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/pybridge/__init__.py 2008-05-10 09:51:38 UTC (rev 507) @@ -2,7 +2,7 @@ PyBridge - a free online bridge game. """ -__version__ = '0.3.0' +__version__ = '0.4.0' __author__ = 'Michael Banks <mi...@ba...>' __license__ = 'GNU General Public License, Version 2 or later' Modified: trunk/pybridge/pybridge/games/bridge/ui/window_scoresheet.py =================================================================== --- trunk/pybridge/pybridge/games/bridge/ui/window_scoresheet.py 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/pybridge/games/bridge/ui/window_scoresheet.py 2008-05-10 09:51:38 UTC (rev 507) @@ -124,10 +124,15 @@ self.window.set_title(_('Score Sheet')) #self.window.connect('delete_event', self.on_delete_event) + self.sw = gtk.ScrolledWindow() + self.sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_ALWAYS) + self.sw.set_size_request(-1, 150) + self.window.add(self.sw) + self.eventHandler = SimpleEventHandler(self) self.table = None - self.window.show() + self.window.show_all() def tearDown(self): @@ -150,7 +155,7 @@ for result in self.table.game.results: self.scoresheet.add_result(result) - self.window.add(self.scoresheet) + self.sw.add(self.scoresheet) self.scoresheet.show() @@ -164,7 +169,6 @@ self.scoresheet.add_result(result) - def event_makeCall(self, call, position): self.update() Modified: trunk/pybridge/pybridge/network/remotetable.py =================================================================== --- trunk/pybridge/pybridge/network/remotetable.py 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/pybridge/network/remotetable.py 2008-05-10 09:51:38 UTC (rev 507) @@ -49,6 +49,8 @@ if state['gamename'] in SUPPORTED_GAMES: gameclass = SUPPORTED_GAMES[state['gamename']] self.game = gameclass() + # TODO: encapsulate within a try/except block, so errors are not + # propagated back to server, and client drops table gracefully. self.game.setState(state['gamestate']) else: raise NameError, "Unsupported game class %s" % state['gamename'] Modified: trunk/pybridge/pybridge/server/database.py =================================================================== --- trunk/pybridge/pybridge/server/database.py 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/pybridge/server/database.py 2008-05-10 09:51:38 UTC (rev 507) @@ -99,6 +99,7 @@ # Don't split name field - see http://people.w3.org/rishida/blog/?p=100 realname = UnicodeCol(default=None, length=40) profile = UnicodeCol(default=None) + #country = StringCol(length=2, default=None) # ISO 3166 country code. created = DateTimeCol(default=datetime.now) lastLogin = DateTimeCol(default=None) # friends = MultipleJoin('UserFriend', joinColumn='from_user') Modified: trunk/pybridge/pybridge/ui/dialog_connection.py =================================================================== --- trunk/pybridge/pybridge/ui/dialog_connection.py 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/pybridge/ui/dialog_connection.py 2008-05-10 09:51:38 UTC (rev 507) @@ -41,7 +41,7 @@ self.entry_username.set_text(connection.get('Username', '')) password = connection.get('Password', '').decode('rot13') self.entry_password.set_text(password) - self.check_savepassword.set_active(password != '') + self.check_savepassword.set_active(bool(password)) else: self.entry_portnum.set_text(str(TCP_PORT)) Modified: trunk/pybridge/pybridge/ui/window_chat.py =================================================================== --- trunk/pybridge/pybridge/ui/window_chat.py 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/pybridge/ui/window_chat.py 2008-05-10 09:51:38 UTC (rev 507) @@ -115,12 +115,13 @@ # People list display. self.people = PeopleBox() hpaned.pack2(self.people, resize=False, shrink=True) - self.pack1(hpaned, resize=True, shrink=False) + self.pack1(hpaned, resize=True, shrink=True) self.textentry = gtk.TextView() self.textentry.set_editable(True) self.textentry.set_property('sensitive', False) - self.conversation.set_wrap_mode(gtk.WRAP_WORD) + self.textentry.set_wrap_mode(gtk.WRAP_WORD) + #self.textentry.set_size_request(30, 30) self.textentry.connect('key_press_event', self.on_textentry_key_pressed) sw = gtk.ScrolledWindow() sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) @@ -129,7 +130,7 @@ frame.set_shadow_type(gtk.SHADOW_IN) frame.add(sw) frame.set_border_width(6) - self.pack2(frame, resize=False, shrink=False) + self.pack2(frame, resize=True, shrink=True) # Populate conversation textview with text tags. tagtable = self.conversation.get_buffer().get_tag_table() @@ -251,6 +252,7 @@ self.chatboxes = {} # Maps Chat objects to their ChatBox instances. self.notebook = gtk.Notebook() + self.notebook.set_scrollable(True) self.notebook.connect('switch-page', self.on_switch_page) self.window.add(self.notebook) self.window.set_border_width(4) Modified: trunk/pybridge/pybridge/ui/window_gametable.py =================================================================== --- trunk/pybridge/pybridge/ui/window_gametable.py 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/pybridge/ui/window_gametable.py 2008-05-10 09:51:38 UTC (rev 507) @@ -89,18 +89,18 @@ self.toolbar.insert(gtk.SeparatorToolItem(), -1) self.fullscreen = gtk.ToggleToolButton(gtk.STOCK_FULLSCREEN) + self.fullscreen.set_label(_('Full Screen')) self.fullscreen.connect('clicked', self.on_fullscreen_clicked) - #self.fullscreen.set_tooltip() self.toolbar.insert(self.fullscreen, -1) - self.toolbar.insert(gtk.SeparatorToolItem(), -1) - self.leavetable = gtk.ToolButton(gtk.STOCK_QUIT) self.leavetable.set_label(_('Leave Table')) self.leavetable.connect('clicked', self.on_leavetable_clicked) self.toolbar.insert(self.leavetable, -1) + self.toolbar.insert(gtk.SeparatorToolItem(), -1) + def tearDown(self): # Close all child windows. for window in self.children.values(): @@ -115,6 +115,12 @@ self.table = None # Dereference table. + def errback(self, failure): + # TODO: display error in window. + print "Error: %s" % failure.getErrorMessage() + print failure.getBriefTraceback() + + def setTable(self, table): """Set display to follow specified table object. Modified: trunk/pybridge/setup.py =================================================================== --- trunk/pybridge/setup.py 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/setup.py 2008-05-10 09:51:38 UTC (rev 507) @@ -21,7 +21,7 @@ url = 'http://sourceforge.net/projects/pybridge/', description = 'A free online bridge game.', download_url = 'http://sourceforge.net/project/showfiles.php?group_id=114287', - packages = ['pybridge', 'pybridge.bridge', 'pybridge.interfaces', 'pybridge.network', 'pybridge.server', 'pybridge.ui'], + packages = ['pybridge', 'pybridge.games', 'pybridge.interfaces', 'pybridge.network', 'pybridge.server', 'pybridge.ui'], scripts = ['bin/pybridge', 'bin/pybridge-server'], data_files = [('share/applications', ['bin/pybridge.desktop']), ('share/doc/pybridge', ['AUTHORS', 'COPYING', 'INSTALL', 'NEWS', 'README']), Modified: trunk/pybridge/tests/bridge/test_deal.py =================================================================== --- trunk/pybridge/tests/bridge/test_deal.py 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/tests/bridge/test_deal.py 2008-05-10 09:51:38 UTC (rev 507) @@ -73,6 +73,12 @@ self.assertEqual(Deal.fromIndex(index), deal) +# def test_toString(self): +# """Testing toString method over a set of known deals""" +# for deal in self.samples.values(): +# self.assertEqual(Deal.fromString(deal.toString())) + + def main(): suite = unittest.makeSuite(TestDeck) unittest.TextTestRunner(verbosity=2).run(suite) Modified: trunk/pybridge/tests/monkey.py =================================================================== --- trunk/pybridge/tests/monkey.py 2007-10-04 16:40:59 UTC (rev 506) +++ trunk/pybridge/tests/monkey.py 2008-05-10 09:51:38 UTC (rev 507) @@ -150,7 +150,7 @@ # Selection of calls and cards. - calls = [lambda : Bid(random.choice(Level), random.choice(Strain)), + calls = [lambda : Bid(Level.One, random.choice(Strain)), Pass, Double, Redouble] def chooseCall(self): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |