You can subscribe to this list here.
| 2006 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(8) |
Sep
(3) |
Oct
(5) |
Nov
|
Dec
(1) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2007 |
Jan
|
Feb
(7) |
Mar
(17) |
Apr
(37) |
May
|
Jun
(46) |
Jul
(40) |
Aug
(2) |
Sep
(4) |
Oct
(2) |
Nov
|
Dec
|
| 2008 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
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.
|
|
From: <umg...@us...> - 2007-10-04 16:40:59
|
Revision: 506
http://pybridge.svn.sourceforge.net/pybridge/?rev=506&view=rev
Author: umgangee
Date: 2007-10-04 09:40:59 -0700 (Thu, 04 Oct 2007)
Log Message:
-----------
Pop-up score sheet in own window, remove expanding frame for bidding view.
Modified Paths:
--------------
trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py
Modified: trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py 2007-10-04 16:37:16 UTC (rev 505)
+++ trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py 2007-10-04 16:40:59 UTC (rev 506)
@@ -29,7 +29,7 @@
from pybridge.ui.window_gametable import WindowGameTable
from window_bidbox import WindowBidbox
-from window_scoresheet import ScoreSheet
+from window_scoresheet import WindowScoreSheet
class BiddingView(gtk.TreeView):
@@ -187,6 +187,12 @@
self.takeseat_menuitems[position] = item
self.takeseat.set_menu(menu)
+ # Set up bridge-specific toolbar buttons.
+ self.showscores = gtk.ToggleToolButton(gtk.STOCK_EDIT)
+ self.showscores.set_label(_('Show Scoresheet'))
+ self.showscores.connect('clicked', self.on_showscores_clicked)
+ self.toolbar.insert(self.showscores, -1)
+
# Set up CardArea widget.
self.cardarea = CardArea(positions=Direction)
@@ -205,10 +211,7 @@
sw.add(self.biddingview)
frame = gtk.Frame()
frame.add(sw)
- exp = gtk.Expander(_('Bidding'))
- exp.set_expanded(True)
- exp.add(frame)
- self.sidebar.pack_start(exp, expand=True)
+ self.sidebar.pack_start(frame, expand=True)
self.trickarea = TrickArea(positions=Direction)
self.trickarea.set_size_request(-1, 180)
@@ -219,16 +222,16 @@
exp.add(frame)
self.sidebar.pack_start(exp, expand=False)
- self.scoresheet = ScoreSheet()
- sw = gtk.ScrolledWindow()
- sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- sw.add(self.scoresheet)
- frame = gtk.Frame()
- frame.add(sw)
- exp = gtk.Expander(_('Score Sheet'))
- exp.set_expanded(False)
- exp.add(frame)
- self.sidebar.pack_start(exp, expand=False)
+# self.scoresheet = ScoreSheet()
+# sw = gtk.ScrolledWindow()
+# sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+# sw.add(self.scoresheet)
+# frame = gtk.Frame()
+# frame.add(sw)
+# exp = gtk.Expander(_('Score Sheet'))
+# exp.set_expanded(False)
+# exp.add(frame)
+# self.sidebar.pack_start(exp, expand=False)
def setTable(self, table):
@@ -263,7 +266,6 @@
bidbox.setCallSelectHandler(self.on_call_selected)
bidbox.setTable(self.table, self.position)
-
# Initialise seat menu and player labels.
for position in Direction:
player = self.table.players.get(position) # Player name or None.
@@ -298,7 +300,7 @@
# Determine and display score in dialog box and score sheet.
if self.table.game.contract:
- self.scoresheet.add_result(self.table.game.result)
+ #self.scoresheet.add_result(self.table.game.result)
tricksMade = self.table.game.result.tricksMade
tricksRequired = self.table.game.contract.bid.level.index + 7
@@ -565,3 +567,15 @@
d = super(WindowBridgeTable, self).on_leaveseat_clicked(widget, *args)
d.addCallback(success)
+
+ def on_showscores_clicked(self, widget, *args):
+ if self.showscores.get_active():
+ w = self.children.open(WindowScoreSheet)
+ # This re-invokes on_showscores_clicked if user closes w.
+ delete_event = lambda w, e: self.showscores.set_active(False)
+ w.window.connect('delete_event', delete_event)
+ w.setTable(self.table)
+
+ else:
+ self.children.close(self.children[WindowScoreSheet])
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-10-04 16:37:17
|
Revision: 505
http://pybridge.svn.sourceforge.net/pybridge/?rev=505&view=rev
Author: umgangee
Date: 2007-10-04 09:37:16 -0700 (Thu, 04 Oct 2007)
Log Message:
-----------
Make Contract and Result objects copyable, send results over-the-wire for display on clients.
Modified Paths:
--------------
trunk/pybridge/pybridge/games/bridge/auction.py
trunk/pybridge/pybridge/games/bridge/game.py
trunk/pybridge/pybridge/games/bridge/result.py
trunk/pybridge/pybridge/games/bridge/ui/window_scoresheet.py
Modified: trunk/pybridge/pybridge/games/bridge/auction.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/auction.py 2007-09-26 13:02:19 UTC (rev 504)
+++ trunk/pybridge/pybridge/games/bridge/auction.py 2007-10-04 16:37:16 UTC (rev 505)
@@ -16,11 +16,13 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from twisted.spread import pb
+
from call import Bid, Pass, Double, Redouble
from symbols import Direction
-class Contract(object):
+class Contract(object, pb.Copyable, pb.RemoteCopy):
"""Represents the result of an auction."""
@@ -54,8 +56,19 @@
self.redoubleBy = auction.whoCalled(auction.currentRedouble)
+ def getStateToCopy(self):
+ return self.bid, self.declarer, self.doubleBy, self.redoubleBy
+ def setCopyableState(self, state):
+ self.bid, self.declarer, self.doubleBy, self.redoubleBy = state
+
+
+pb.setUnjellyableForClass(Contract, Contract)
+
+
+
+
class Auction(list):
"""The auction (bidding phase) of a game of bridge."""
Modified: trunk/pybridge/pybridge/games/bridge/game.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/game.py 2007-09-26 13:02:19 UTC (rev 504)
+++ trunk/pybridge/pybridge/games/bridge/game.py 2007-10-04 16:37:16 UTC (rev 505)
@@ -87,6 +87,8 @@
if board: # Use specified board.
self.board = board
+ elif self.boardQueue: # Use pre-specified board.
+ self.board = self.boardQueue.pop(0)
elif self.board: # Advance to next round.
self.board = self.board.next()
else: # Create an initial board.
@@ -136,6 +138,9 @@
def getState(self):
state = {}
+ state['options'] = self.options
+ state['results'] = self.results
+
if self.inProgress():
# Remove hidden hands from deal.
visibleBoard = self.board.copy()
@@ -151,6 +156,8 @@
def setState(self, state):
+ self.options = state.get('options', {})
+
if state.get('board'):
self.start(state['board'])
@@ -172,7 +179,9 @@
else:
self.playCard(card, position=turn)
+ self.results = state.get('results', []) # Overwrites current game result.
+
def updateState(self, event, *args, **kwargs):
allowed = ['start', 'makeCall', 'playCard', 'revealHand']
if event in allowed:
Modified: trunk/pybridge/pybridge/games/bridge/result.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/result.py 2007-09-26 13:02:19 UTC (rev 504)
+++ trunk/pybridge/pybridge/games/bridge/result.py 2007-10-04 16:37:16 UTC (rev 505)
@@ -16,6 +16,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+from twisted.spread import pb
+
from symbols import Direction, Strain, Vulnerable
@@ -40,6 +42,7 @@
self.contract = contract
self.tricksMade = tricksMade
+ self.isVulnerable = None
if self.contract:
vuln = self.board.get('vuln', Vulnerable.None)
self.isVulnerable = self.contract.declarer in self.__vulnMap[vuln]
@@ -47,6 +50,16 @@
self.score = self._getScore()
+ def getStateToCopy(self):
+ return (self.board.copy(), self.contract, self.tricksMade,
+ self.isVulnerable, self.score)
+
+
+ def setCopyableState(self, state):
+ self.board, self.contract, self.tricksMade, self.isVulnerable, self.score = state
+ # assert self.score == self._getScore()
+
+
def _getScoreComponents(self):
"""Compute the component values which contribute to the score.
Note that particular scoring schemes may ignore some of the components.
@@ -178,7 +191,7 @@
-class DuplicateResult(GameResult):
+class DuplicateResult(GameResult, pb.Copyable, pb.RemoteCopy):
"""Represents the result of a completed round of duplicate bridge."""
@@ -196,9 +209,12 @@
return score
+pb.setUnjellyableForClass(DuplicateResult, DuplicateResult)
-class RubberResult(GameResult):
+
+
+class RubberResult(GameResult, pb.Copyable, pb.RemoteCopy):
"""Represents the result of a completed round of rubber bridge."""
@@ -219,8 +235,11 @@
return above, below
+pb.setUnjellyableForClass(RubberResult, RubberResult)
+
+
class Rubber(list):
"""A rubber set, in which pairs compete to make two consecutive games.
Modified: trunk/pybridge/pybridge/games/bridge/ui/window_scoresheet.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/ui/window_scoresheet.py 2007-09-26 13:02:19 UTC (rev 504)
+++ trunk/pybridge/pybridge/games/bridge/ui/window_scoresheet.py 2007-10-04 16:37:16 UTC (rev 505)
@@ -52,7 +52,7 @@
score = result.score
if result.contract is None: # Bidding passed out.
- row = (result.board['num'], _('Passed out'), '-', '-', '', '')
+ row = (result.board['num'], _('Passed out'), '-', '', '')
else:
if result.contract.declarer in (Direction.North, Direction.South) and score > 0 \
@@ -122,19 +122,53 @@
if parent:
self.window.set_transient_for(parent.window)
self.window.set_title(_('Score Sheet'))
- self.window.connect('delete_event', self.on_delete_event)
- #self.window.set_resizable(False)
+ #self.window.connect('delete_event', self.on_delete_event)
self.eventHandler = SimpleEventHandler(self)
self.table = None
+ self.window.show()
+
def tearDown(self):
- pass
+ self.table.game.detach(self.eventHandler)
+ self.table = None # Dereference table.
+ def setTable(self, table):
+ self.table = table
+ self.table.game.attach(self.eventHandler)
- def on_delete_event(self, widget, *args):
- # TODO: call wm.close(self)
- return True # Stops window deletion taking place.
+ if hasattr(self.table.game, 'rubbers'):
+ self.scoresheet = RubberScoreSheet()
+ if self.table.game.rubbers:
+ rubber = self.table.game.rubbers[-1]
+ self.scoresheet.set_rubber(rubber)
+ else: # Duplicate-style list of results.
+ self.scoresheet = ScoreSheet()
+ for result in self.table.game.results:
+ self.scoresheet.add_result(result)
+
+ self.window.add(self.scoresheet)
+ self.scoresheet.show()
+
+
+ def update(self):
+ if self.table.game.results and not self.table.game.inProgress():
+ if isinstance(self.scoresheet, RubberScoreSheet):
+ rubber = self.table.game.rubbers[-1]
+ self.scoresheet.set_rubber(rubber)
+ else:
+ result = self.table.game.results[-1]
+ self.scoresheet.add_result(result)
+
+
+
+ def event_makeCall(self, call, position):
+ self.update()
+
+
+ def event_playCard(self, card, position):
+ self.update()
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-09-26 13:02:20
|
Revision: 504
http://pybridge.svn.sourceforge.net/pybridge/?rev=504&view=rev
Author: umgangee
Date: 2007-09-26 06:02:19 -0700 (Wed, 26 Sep 2007)
Log Message:
-----------
Polish translation of PyBridge UI, thanks to Monsz. Update French PO and MO files.
Modified Paths:
--------------
trunk/pybridge/locale/fr/LC_MESSAGES/pybridge.mo
trunk/pybridge/locale/fr/LC_MESSAGES/pybridge.po
Added Paths:
-----------
trunk/pybridge/locale/pl/
trunk/pybridge/locale/pl/LC_MESSAGES/
trunk/pybridge/locale/pl/LC_MESSAGES/pybridge.mo
trunk/pybridge/locale/pl/LC_MESSAGES/pybridge.po
Modified: trunk/pybridge/locale/fr/LC_MESSAGES/pybridge.mo
===================================================================
(Binary files differ)
Modified: trunk/pybridge/locale/fr/LC_MESSAGES/pybridge.po
===================================================================
--- trunk/pybridge/locale/fr/LC_MESSAGES/pybridge.po 2007-09-26 12:51:30 UTC (rev 503)
+++ trunk/pybridge/locale/fr/LC_MESSAGES/pybridge.po 2007-09-26 13:02:19 UTC (rev 504)
@@ -3,20 +3,32 @@
# This file is distributed under the same license as the pybridge package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2007.
#
-#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pybridge\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
-"POT-Creation-Date: 2007-08-26 18:09+0100\n"
+"POT-Creation-Date: 2007-09-22 12:25+0100\n"
"PO-Revision-Date: 2007-09-02 13:13+0000\n"
"Last-Translator: Aldo Reset <al...@pl...>\n"
"Language-Team: French <fr...@li...>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Rosetta-Export-Date: 2007-09-02 14:18:13+0000\n"
+"X-Launchpad-Export-Date: 2007-09-26 12:48+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+#~ msgid "gtk-cancel"
+#~ msgstr "gtk-cancel"
+
+#~ msgid "gtk-close"
+#~ msgstr "gtk-close"
+
+#~ msgid "gtk-ok"
+#~ msgstr "gtk-ok"
+
+#~ msgid "gtk-preferences"
+#~ msgstr "gtk-preferences"
+
#: ../../glade/pybridge.glade.h:1
msgid "<b>Server Address</b>"
msgstr "<b>Adresse du Serveur</b>"
@@ -76,109 +88,101 @@
msgstr "Nom du Poste"
#: ../../glade/pybridge.glade.h:15
+msgid "Join Table"
+msgstr ""
+
+#: ../../glade/pybridge.glade.h:16
+msgid "New Table..."
+msgstr ""
+
+#: ../../glade/pybridge.glade.h:17
msgid "Open Tables"
msgstr "Tables Ouvertes"
-#: ../../glade/pybridge.glade.h:16
+#: ../../glade/pybridge.glade.h:18
msgid "Password:"
msgstr "Mot de Passe"
-#: ../../glade/pybridge.glade.h:17
+#: ../../glade/pybridge.glade.h:19
msgid "Port:"
msgstr "Port:"
-#: ../../glade/pybridge.glade.h:18
+#: ../../glade/pybridge.glade.h:20
msgid "PyBridge"
msgstr "PyBridge"
-#: ../../glade/pybridge.glade.h:19
+#: ../../glade/pybridge.glade.h:21
msgid "PyBridge Preferences"
msgstr "PyBridge Prfrences"
-#: ../../glade/pybridge.glade.h:20
+#: ../../glade/pybridge.glade.h:22
msgid "PyBridge _Home Page"
msgstr "PyBridge _Page d'accueil"
-#: ../../glade/pybridge.glade.h:21
+#: ../../glade/pybridge.glade.h:23
msgid "Register as New User"
msgstr "Inscrire Nouveau Joueur"
-#: ../../glade/pybridge.glade.h:22 ../../pybridge/ui/vocabulary.py:53
+#: ../../glade/pybridge.glade.h:24 ../../pybridge/ui/vocabulary.py:53
msgid "S"
msgstr "S"
-#: ../../glade/pybridge.glade.h:23
+#: ../../glade/pybridge.glade.h:25
msgid "Save Password"
msgstr "Sauvegarder Mot de Passe"
-#: ../../glade/pybridge.glade.h:24
+#: ../../glade/pybridge.glade.h:26
msgid "Suit Colours:"
msgstr ""
-#: ../../glade/pybridge.glade.h:25
+#: ../../glade/pybridge.glade.h:27
msgid "Table Name:"
msgstr "Nom de la Table"
-#: ../../glade/pybridge.glade.h:26
+#: ../../glade/pybridge.glade.h:28
msgid "User Information"
msgstr "Information Joueur"
-#: ../../glade/pybridge.glade.h:27
+#: ../../glade/pybridge.glade.h:29
msgid "User Name:"
msgstr "Nom du Joueur"
-#: ../../glade/pybridge.glade.h:28
+#: ../../glade/pybridge.glade.h:30
msgid "Users Online"
msgstr "Joueurs en Ligne"
-#: ../../glade/pybridge.glade.h:29
+#: ../../glade/pybridge.glade.h:31
msgid "_About PyBridge"
msgstr "_Au sujet de Pybridge"
-#: ../../glade/pybridge.glade.h:30
+#: ../../glade/pybridge.glade.h:32
msgid "_Connect to Server..."
msgstr "_Connexion au Serveur"
-#: ../../glade/pybridge.glade.h:31
+#: ../../glade/pybridge.glade.h:33
msgid "_Connection"
msgstr "_Connexion"
-#: ../../glade/pybridge.glade.h:32
+#: ../../glade/pybridge.glade.h:34
msgid "_Disconnect"
msgstr "_Dconnexion"
-#: ../../glade/pybridge.glade.h:33
+#: ../../glade/pybridge.glade.h:35
msgid "_Help"
msgstr "_Aide"
-#: ../../glade/pybridge.glade.h:34
+#: ../../glade/pybridge.glade.h:36
msgid "_New Table..."
msgstr "_Nouvelle Table"
-#: ../../glade/pybridge.glade.h:35
+#: ../../glade/pybridge.glade.h:37
msgid "_Open Game..."
msgstr "_Ouvrir Jeu..."
-#: ../../glade/pybridge.glade.h:36
+#: ../../glade/pybridge.glade.h:38
msgid "_Options"
msgstr "_Options"
-#: ../../glade/pybridge.glade.h:37
-msgid "gtk-cancel"
-msgstr "gtk-cancel"
-
-#: ../../glade/pybridge.glade.h:38
-msgid "gtk-close"
-msgstr "gtk-close"
-
-#: ../../glade/pybridge.glade.h:39
-msgid "gtk-ok"
-msgstr "gtk-ok"
-
-#: ../../glade/pybridge.glade.h:40
-msgid "gtk-preferences"
-msgstr "gtk-preferences"
-
#: ../../pybridge/ui/dialog_connection.py:74
msgid "Connection failed"
msgstr "Connexion choue"
@@ -382,14 +386,14 @@
msgstr "Tout"
#: ../../pybridge/ui/vocabulary.py:148
-#: ../../pybridge/games/bridge/ui/scoresheet.py:42
-#: ../../pybridge/games/bridge/ui/scoresheet.py:87
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:42
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:87
msgid "N/S"
msgstr "N/S"
#: ../../pybridge/ui/vocabulary.py:149
-#: ../../pybridge/games/bridge/ui/scoresheet.py:42
-#: ../../pybridge/games/bridge/ui/scoresheet.py:87
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:42
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:87
msgid "E/W"
msgstr "E/O"
@@ -453,7 +457,7 @@
msgstr "Prendre Place"
#: ../../pybridge/ui/window_gametable.py:84
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:336
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:342
msgid "Leave Seat"
msgstr "Quitter Place"
@@ -520,27 +524,6 @@
msgid "A free online bridge game."
msgstr "Un jeu libre de brige en ligne"
-#: ../../pybridge/games/bridge/ui/scoresheet.py:42
-msgid "Board"
-msgstr ""
-
-#: ../../pybridge/games/bridge/ui/scoresheet.py:42
-msgid "Contract"
-msgstr "Contrat"
-
-#: ../../pybridge/games/bridge/ui/scoresheet.py:42
-msgid "Made"
-msgstr ""
-
-#: ../../pybridge/games/bridge/ui/scoresheet.py:55
-msgid "Passed out"
-msgstr ""
-
-#: ../../pybridge/games/bridge/ui/scoresheet.py:124
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:228
-msgid "Score Sheet"
-msgstr "Scores"
-
#: ../../pybridge/games/bridge/ui/window_bidbox.py:41
msgid "Bidding Box"
msgstr "Enchre"
@@ -569,90 +552,114 @@
msgid "Contract Bridge"
msgstr "Contrat"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:208
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:192
+msgid "Show Scoresheet"
+msgstr ""
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:214
msgid "Bidding"
msgstr "Ouverture"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:217
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:223
msgid "Previous Trick"
msgstr "Leve prcdente"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:297
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:303
msgid "Game result"
msgstr "Resultat de la Partie"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:311
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:317
#, python-format
msgid "Contract %(contract)s made by 1 trick."
msgstr "Le Contrat %(contract)s raliser d'une leve."
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:313
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:319
#, python-format
msgid "Contract %(contract)s made by %(offset)s tricks."
msgstr "Le Contrat %(contract)s raliser avec %(offset)s leves."
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:316
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:322
#, python-format
msgid "Contract %(contract)s failed by 1 trick."
msgstr "Le contrat %(contract)s chute d'une leve"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:318
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:324
#, python-format
msgid "Contract %(contract)s failed by %(offset)s tricks."
msgstr "Le contrat %(contract)s chute de %(offset)s leves"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:320
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:326
#, python-format
msgid "Contract %(contract)s made exactly."
msgstr "Le contrat %(contract)s russit"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:326
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:332
msgid "declarer"
msgstr "dclare"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:326
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:332
msgid "defence"
msgstr "Intervention"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:327
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:333
#, python-format
msgid "Score %(points)s points for %(pair)s."
msgstr "Score %(points)s points pour %(pair)s."
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:332
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:338
msgid "Bidding passed out."
msgstr "Enchere passe"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:333
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:339
msgid "No score."
msgstr "Pas de point"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:337
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:343
msgid "Click OK to start next game."
msgstr "Cliquer Ok pour dmarrer la prochaine partie"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:408
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:414
msgid "Play a card from your hand."
msgstr "Jouer une carte de votre main"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:410
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:416
msgid "Play a card from dummy's hand."
msgstr "Jouer une carte de la main du mort"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:412
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:418
#, python-format
msgid "It is %s's turn to play a card."
msgstr "Ce n'est pas %s's de jouer une carte"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:416
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:422
msgid "Make a call from the bidding box."
msgstr "Faire un appel de l'enchre"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:418
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:424
#, python-format
msgid "It is %s's turn to make a call."
msgstr "Ce n'est pas le tour de %s's de faire un appel"
-#: ../../pybridge/games/bridge/ui/window_bridgetable.py:421
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:427
msgid "Waiting for next game to start."
-msgstr "Attender que la prochaine partie commence"
\ No newline at end of file
+msgstr "Attender que la prochaine partie commence"
+
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:42
+msgid "Board"
+msgstr ""
+
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:42
+msgid "Contract"
+msgstr "Contrat"
+
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:42
+msgid "Made"
+msgstr ""
+
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:55
+msgid "Passed out"
+msgstr ""
+
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:124
+msgid "Score Sheet"
+msgstr "Scores"
Added: trunk/pybridge/locale/pl/LC_MESSAGES/pybridge.mo
===================================================================
(Binary files differ)
Property changes on: trunk/pybridge/locale/pl/LC_MESSAGES/pybridge.mo
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/pybridge/locale/pl/LC_MESSAGES/pybridge.po
===================================================================
--- trunk/pybridge/locale/pl/LC_MESSAGES/pybridge.po (rev 0)
+++ trunk/pybridge/locale/pl/LC_MESSAGES/pybridge.po 2007-09-26 13:02:19 UTC (rev 504)
@@ -0,0 +1,677 @@
+# Polish translation for pybridge
+# Copyright (c) 2007 Rosetta Contributors and Canonical Ltd 2007
+# This file is distributed under the same license as the pybridge package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2007.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: pybridge\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2007-09-22 12:25+0100\n"
+"PO-Revision-Date: 2007-09-20 15:49+0000\n"
+"Last-Translator: Piotr Kwilński <eu...@ho...>\n"
+"Language-Team: Polish <pl...@li...>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2007-09-26 12:48+0000\n"
+"X-Generator: Launchpad (build Unknown)\n"
+
+#~ msgid "gtk-cancel"
+#~ msgstr "gtk-anuluj"
+
+#~ msgid "gtk-close"
+#~ msgstr "gtk-zamknij"
+
+#~ msgid "gtk-ok"
+#~ msgstr "gtk-ok"
+
+#~ msgid "gtk-preferences"
+#~ msgstr "gtk-właściwości"
+
+#: ../../glade/pybridge.glade.h:1
+msgid "<b>Server Address</b>"
+msgstr "<b>Adres serwera</b>"
+
+#: ../../glade/pybridge.glade.h:2
+msgid "<b>User Account</b>"
+msgstr "<b>Konto użytkownika</b>"
+
+#: ../../glade/pybridge.glade.h:3
+msgid ""
+"<i>Changes to these settings are effective after restarting PyBridge.</i>"
+msgstr ""
+"<i>Zmiany ustawień zostaną uwzględnione przy ponownym uruchomieniu "
+"PyBridge.</i>"
+
+#: ../../glade/pybridge.glade.h:4
+msgid "Background:"
+msgstr "Tło:"
+
+#: ../../glade/pybridge.glade.h:5
+msgid "C"
+msgstr "C"
+
+#: ../../glade/pybridge.glade.h:6
+msgid "Card Style:"
+msgstr "Styl kart:"
+
+#: ../../glade/pybridge.glade.h:7
+msgid "Connect to Server"
+msgstr "Połącz z serwerem"
+
+#: ../../glade/pybridge.glade.h:8
+msgid "Create a New Table"
+msgstr "Utwórz nowy stół"
+
+#: ../../glade/pybridge.glade.h:9
+msgid "D"
+msgstr "D"
+
+#: ../../glade/pybridge.glade.h:10
+msgid "Display suits as symbols?"
+msgstr "Wyświetlać kolory kart jako symbole?"
+
+#: ../../glade/pybridge.glade.h:11
+#, fuzzy
+msgid "Game Display"
+msgstr "Wyświetlanie gry"
+
+#: ../../glade/pybridge.glade.h:12
+msgid "Game at Table:"
+msgstr "Gra na stole:"
+
+#: ../../glade/pybridge.glade.h:13
+msgid "H"
+msgstr "H"
+
+#: ../../glade/pybridge.glade.h:14
+msgid "Host Name:"
+msgstr "Nazwa hosta:"
+
+#: ../../glade/pybridge.glade.h:15
+msgid "Join Table"
+msgstr ""
+
+#: ../../glade/pybridge.glade.h:16
+msgid "New Table..."
+msgstr ""
+
+#: ../../glade/pybridge.glade.h:17
+#, fuzzy
+msgid "Open Tables"
+msgstr "Stoły otwarte"
+
+#: ../../glade/pybridge.glade.h:18
+msgid "Password:"
+msgstr "Hasło:"
+
+#: ../../glade/pybridge.glade.h:19
+msgid "Port:"
+msgstr "Port:"
+
+#: ../../glade/pybridge.glade.h:20
+msgid "PyBridge"
+msgstr "PyBridge"
+
+#: ../../glade/pybridge.glade.h:21
+msgid "PyBridge Preferences"
+msgstr "Ustawienia PyBridge"
+
+#: ../../glade/pybridge.glade.h:22
+msgid "PyBridge _Home Page"
+msgstr "Strona _domowa PyBridge"
+
+#: ../../glade/pybridge.glade.h:23
+msgid "Register as New User"
+msgstr "Zarejestruj jako nowyego użytkownika"
+
+#: ../../glade/pybridge.glade.h:24 ../../pybridge/ui/vocabulary.py:53
+msgid "S"
+msgstr "S"
+
+#: ../../glade/pybridge.glade.h:25
+msgid "Save Password"
+msgstr "Zapisz hasło"
+
+#: ../../glade/pybridge.glade.h:26
+msgid "Suit Colours:"
+msgstr "Kolory kart:"
+
+#: ../../glade/pybridge.glade.h:27
+msgid "Table Name:"
+msgstr "Nazwa stołu:"
+
+#: ../../glade/pybridge.glade.h:28
+msgid "User Information"
+msgstr "Informacje użytkownika"
+
+#: ../../glade/pybridge.glade.h:29
+msgid "User Name:"
+msgstr "Nazwa uzytkownika:"
+
+#: ../../glade/pybridge.glade.h:30
+msgid "Users Online"
+msgstr "Użytkowników On-line"
+
+#: ../../glade/pybridge.glade.h:31
+msgid "_About PyBridge"
+msgstr "_O programie PYBridge"
+
+#: ../../glade/pybridge.glade.h:32
+msgid "_Connect to Server..."
+msgstr "_Połącz z serwerem..."
+
+#: ../../glade/pybridge.glade.h:33
+msgid "_Connection"
+msgstr "P_ołączenie"
+
+#: ../../glade/pybridge.glade.h:34
+msgid "_Disconnect"
+msgstr "_Rozłącz"
+
+#: ../../glade/pybridge.glade.h:35
+msgid "_Help"
+msgstr "Po_moc"
+
+#: ../../glade/pybridge.glade.h:36
+msgid "_New Table..."
+msgstr "_Nowy stół..."
+
+#: ../../glade/pybridge.glade.h:37
+msgid "_Open Game..."
+msgstr "_Otwórz grę..."
+
+#: ../../glade/pybridge.glade.h:38
+msgid "_Options"
+msgstr "_Opcje"
+
+#: ../../pybridge/ui/dialog_connection.py:74
+msgid "Connection failed"
+msgstr "Nie udało się połączyć"
+
+#: ../../pybridge/ui/dialog_connection.py:75
+msgid "Could not connect to server."
+msgstr "Nie można połączyć z serwerem."
+
+#: ../../pybridge/ui/dialog_connection.py:76
+#: ../../pybridge/ui/dialog_newtable.py:62
+#, python-format
+msgid "Reason: %s"
+msgstr "Przyczyna: %s"
+
+#: ../../pybridge/ui/dialog_newtable.py:60
+msgid "Could not create table"
+msgstr "Nie można utworzyć stołu"
+
+#: ../../pybridge/ui/dialog_newtable.py:61
+msgid "The table was not created by the server."
+msgstr "Stół nie został utworzony przez serwer."
+
+#: ../../pybridge/ui/dialog_preferences.py:43
+msgid "PNG images"
+msgstr "Obrazy PNG"
+
+#: ../../pybridge/ui/dialog_preferences.py:98
+#, python-format
+msgid "Select colour for %s symbol"
+msgstr "Wybierz kolor dla symbolu %s"
+
+#: ../../pybridge/ui/dialog_userinfo.py:29
+msgid "Real Name"
+msgstr "Prawdziwa nazwa"
+
+#: ../../pybridge/ui/dialog_userinfo.py:30
+msgid "Email Address"
+msgstr "Adres e-mail"
+
+#: ../../pybridge/ui/dialog_userinfo.py:32
+msgid "Profile"
+msgstr "Profil"
+
+#: ../../pybridge/ui/dialog_userinfo.py:54
+#, python-format
+msgid "Information for %(user)s"
+msgstr "Informacja dla %(user)s"
+
+#: ../../pybridge/ui/dialog_userinfo.py:68
+msgid "not specified"
+msgstr "nie określony"
+
+#: ../../pybridge/ui/excepthook.py:34
+msgid "Program error"
+msgstr "Błąd programu"
+
+#: ../../pybridge/ui/excepthook.py:35
+msgid ""
+"PyBridge detected an unexpected program error. You should close and restart "
+"PyBridge."
+msgstr ""
+"PyBridge wykrył nieoczekiwany błąd programu. Zamknij i ponownie uruchom "
+"PyBridge."
+
+#: ../../pybridge/ui/excepthook.py:36
+msgid ""
+"If you continue to experience this error, please submit a bug report, "
+"attaching the following error trace."
+msgstr ""
+"Jeśli błąd będzie nadal występował zgłoś go nam proszę załączając "
+"następujący opis błędu."
+
+#: ../../pybridge/ui/vocabulary.py:32
+msgid "Pass"
+msgstr "Pas"
+
+#: ../../pybridge/ui/vocabulary.py:33
+#, fuzzy
+msgid "Double"
+msgstr "Kontra"
+
+#: ../../pybridge/ui/vocabulary.py:34
+#, fuzzy
+msgid "Redouble"
+msgstr "Rekontra"
+
+#: ../../pybridge/ui/vocabulary.py:44
+msgid "North"
+msgstr "Północ"
+
+#: ../../pybridge/ui/vocabulary.py:45
+msgid "East"
+msgstr "Wschód"
+
+#: ../../pybridge/ui/vocabulary.py:46
+msgid "South"
+msgstr "Południe"
+
+#: ../../pybridge/ui/vocabulary.py:47
+msgid "West"
+msgstr "Zachód"
+
+#: ../../pybridge/ui/vocabulary.py:51
+msgid "N"
+msgstr "N"
+
+#: ../../pybridge/ui/vocabulary.py:52
+msgid "E"
+msgstr "E"
+
+#: ../../pybridge/ui/vocabulary.py:54
+msgid "W"
+msgstr "W"
+
+#: ../../pybridge/ui/vocabulary.py:68
+msgid "Two"
+msgstr "Dwa"
+
+#: ../../pybridge/ui/vocabulary.py:69
+msgid "Three"
+msgstr "Trzy"
+
+#: ../../pybridge/ui/vocabulary.py:70
+msgid "Four"
+msgstr "Cztery"
+
+#: ../../pybridge/ui/vocabulary.py:71
+msgid "Five"
+msgstr "Pięć"
+
+#: ../../pybridge/ui/vocabulary.py:72
+msgid "Six"
+msgstr "Sześć"
+
+#: ../../pybridge/ui/vocabulary.py:73
+msgid "Seven"
+msgstr "Siedem"
+
+#: ../../pybridge/ui/vocabulary.py:74
+msgid "Eight"
+msgstr "Osiem"
+
+#: ../../pybridge/ui/vocabulary.py:75
+msgid "Nine"
+msgstr "Dziewięć"
+
+#: ../../pybridge/ui/vocabulary.py:76
+msgid "Ten"
+msgstr "Dziesięć"
+
+#: ../../pybridge/ui/vocabulary.py:77
+msgid "Jack"
+msgstr "Walet"
+
+#: ../../pybridge/ui/vocabulary.py:78
+msgid "Queen"
+msgstr "Dama"
+
+#: ../../pybridge/ui/vocabulary.py:79
+msgid "King"
+msgstr "Król"
+
+#: ../../pybridge/ui/vocabulary.py:80
+msgid "Ace"
+msgstr "As"
+
+#: ../../pybridge/ui/vocabulary.py:100
+msgid "Clubs"
+msgstr "Trefle"
+
+#: ../../pybridge/ui/vocabulary.py:101
+msgid "Diamonds"
+msgstr "Kara"
+
+#: ../../pybridge/ui/vocabulary.py:102
+msgid "Hearts"
+msgstr "Kiery"
+
+#: ../../pybridge/ui/vocabulary.py:103
+msgid "Spades"
+msgstr "Piki"
+
+#: ../../pybridge/ui/vocabulary.py:122
+msgid "Club"
+msgstr "Trefl"
+
+#: ../../pybridge/ui/vocabulary.py:123
+msgid "Diamond"
+msgstr "Karo"
+
+#: ../../pybridge/ui/vocabulary.py:124
+msgid "Heart"
+msgstr "Kier"
+
+#: ../../pybridge/ui/vocabulary.py:125
+msgid "Spade"
+msgstr "Pik"
+
+#: ../../pybridge/ui/vocabulary.py:126
+msgid "No Trump"
+msgstr "Bez atu"
+
+#: ../../pybridge/ui/vocabulary.py:147
+msgid "All"
+msgstr "Wszystko"
+
+#: ../../pybridge/ui/vocabulary.py:148
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:42
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:87
+msgid "N/S"
+msgstr "N/S"
+
+#: ../../pybridge/ui/vocabulary.py:149
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:42
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:87
+msgid "E/W"
+msgstr "E/W"
+
+#: ../../pybridge/ui/vocabulary.py:150
+msgid "None"
+msgstr "Żaden"
+
+#: ../../pybridge/ui/vocabulary.py:169
+#, python-format
+msgid "%(level)s %(strain)s"
+msgstr "%(level)s %(strain)s"
+
+#: ../../pybridge/ui/vocabulary.py:183
+#, python-format
+msgid "%(rank)s of %(suit)s"
+msgstr "%(rank)s z %(suit)s"
+
+#: ../../pybridge/ui/vocabulary.py:201
+#, python-format
+msgid "%(bid)s %(doubled)s by %(declarer)s"
+msgstr "%(bid)s %(doubled)s przez %(declarer)s"
+
+#: ../../pybridge/ui/vocabulary.py:203
+#, python-format
+msgid "%(bid)s by %(declarer)s"
+msgstr "%(bid)s przez %(declarer)s"
+
+#: ../../pybridge/ui/window_chat.py:73
+msgid "1 person in room"
+msgstr "1 osoba w pokoju"
+
+#: ../../pybridge/ui/window_chat.py:75
+#, python-format
+msgid "%(num)s people in room"
+msgstr "%(num)s osób w pokoju"
+
+#: ../../pybridge/ui/window_chat.py:194
+#, python-format
+msgid "%(user)s has joined the conversation"
+msgstr "%(user)s dołączył do konwersacji"
+
+#: ../../pybridge/ui/window_chat.py:196
+#, python-format
+msgid "%(user)s has left the conversation"
+msgstr "%(user)s opuścił konwersację"
+
+#: ../../pybridge/ui/window_chat.py:290
+msgid "Chat"
+msgstr "Chat"
+
+#: ../../pybridge/ui/window_gametable.py:37
+msgid "Unnamed Game"
+msgstr "Gra bez nazwy"
+
+#: ../../pybridge/ui/window_gametable.py:46
+msgid "Table"
+msgstr "Stół"
+
+#: ../../pybridge/ui/window_gametable.py:78
+msgid "Take Seat"
+msgstr "Zajmij miejsce"
+
+#: ../../pybridge/ui/window_gametable.py:84
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:342
+msgid "Leave Seat"
+msgstr "Opuść miejsce"
+
+#: ../../pybridge/ui/window_gametable.py:99
+#: ../../pybridge/ui/window_gametable.py:193
+msgid "Leave Table"
+msgstr "Opuść stół"
+
+#: ../../pybridge/ui/window_gametable.py:135
+#, python-format
+msgid "%(tablename)s (%(gametype)s)"
+msgstr "%(tablename)s (%(gametype)s)"
+
+#: ../../pybridge/ui/window_gametable.py:191
+msgid "Leave table?"
+msgstr "Opuścić stół?"
+
+#: ../../pybridge/ui/window_gametable.py:194
+msgid "Are you sure you wish to leave this table?"
+msgstr "Czy jesteś pewien że chcesz opuścić ten stół?"
+
+#: ../../pybridge/ui/window_gametable.py:195
+msgid ""
+"You are currently playing a game. Leaving may forfeit the game, or incur "
+"penalties."
+msgstr ""
+"Aktualnie grasz. Rozłączenie może spowodowac utratę gry lub wywołać kary."
+
+#: ../../pybridge/ui/window_main.py:125
+msgid "Connection to server lost"
+msgstr "Utracono połączenie z serwerem"
+
+#: ../../pybridge/ui/window_main.py:126
+#, python-format
+msgid "The connection to %s was lost unexpectedly."
+msgstr "Nieoczekiwanie utracono połączenie z %s."
+
+#: ../../pybridge/ui/window_main.py:127
+msgid ""
+"Please check your computer's network connection status before reconnecting. "
+"If you cannot reconnect, the server may be offline."
+msgstr ""
+"Sprawdź stan swojego połączenie przed ponownym podłączeniem. Jeśli nie "
+"możesz ponownie połączyć serwer mże być off-line."
+
+#: ../../pybridge/ui/window_main.py:272
+msgid "Disconnect from server"
+msgstr "Odłącz od serwera"
+
+#: ../../pybridge/ui/window_main.py:275
+msgid "Are you sure you wish to disconnect?"
+msgstr "Czy jesteś pewien że chcesz odłączyć?"
+
+#: ../../pybridge/ui/window_main.py:276
+msgid ""
+"You are playing at a table. Disconnecting may forfeit the game, or incur "
+"penalties."
+msgstr ""
+"Grasz na stole. Rozłączenie może spowodowac utratę gry lub wywołać kary."
+
+#: ../../pybridge/ui/window_main.py:305
+msgid "A free online bridge game."
+msgstr "Bezpłatna gra w brydża on-line."
+
+#: ../../pybridge/games/bridge/ui/window_bidbox.py:41
+msgid "Bidding Box"
+msgstr "Bidding Box"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:103
+#, fuzzy
+msgid "Declarer"
+msgstr "Deklarujący"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:109
+msgid "Defence"
+msgstr "Obrona"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:132
+msgid "No contract"
+msgstr "Bez kontraktu"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:154
+#, fuzzy
+msgid "Dealer"
+msgstr "Rozdający"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:162
+#, fuzzy
+msgid "Vuln"
+msgstr "Założenia"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:169
+#, fuzzy
+msgid "Contract Bridge"
+msgstr "Kontrakt brydż"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:192
+msgid "Show Scoresheet"
+msgstr ""
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:214
+msgid "Bidding"
+msgstr "Licytowanie"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:223
+msgid "Previous Trick"
+msgstr "Poprzednia lewa"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:303
+msgid "Game result"
+msgstr "Wynik gry"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:317
+#, python-format
+msgid "Contract %(contract)s made by 1 trick."
+msgstr "Kontrakt %(contract)s wykonano z 1 dadatkową lewą."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:319
+#, python-format
+msgid "Contract %(contract)s made by %(offset)s tricks."
+msgstr "Kontrakt %(contract)s wykonano z dodatkowymi %(offset)s lewami."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:322
+#, python-format
+msgid "Contract %(contract)s failed by 1 trick."
+msgstr "Kontraktu %(contract)s nie wykonano o 1 lewę."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:324
+#, python-format
+msgid "Contract %(contract)s failed by %(offset)s tricks."
+msgstr "Kontraktu %(contract)s nie wykonano o %(offset)s lew."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:326
+#, python-format
+msgid "Contract %(contract)s made exactly."
+msgstr "Kontrakt %(contract)s wykonany dokładnie."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:332
+#, fuzzy
+msgid "declarer"
+msgstr "deklarujący"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:332
+msgid "defence"
+msgstr "obrona"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:333
+#, python-format
+msgid "Score %(points)s points for %(pair)s."
+msgstr "Punkty %(points)s punkty dla %(pair)s."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:338
+msgid "Bidding passed out."
+msgstr "Licytowanie spasowane."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:339
+msgid "No score."
+msgstr "Brak punktów."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:343
+msgid "Click OK to start next game."
+msgstr "Kliknij OK by rozpocząć nową grę."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:414
+msgid "Play a card from your hand."
+msgstr "Graj kartą z ręki."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:416
+#, fuzzy
+msgid "Play a card from dummy's hand."
+msgstr "Graj kartą ze stołu."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:418
+#, python-format
+msgid "It is %s's turn to play a card."
+msgstr "Kolej %s na rozegranie karty."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:422
+msgid "Make a call from the bidding box."
+msgstr ""
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:424
+#, fuzzy
+msgid "It is %s's turn to make a call."
+msgstr "Kolej %s's na odzywkę."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:427
+msgid "Waiting for next game to start."
+msgstr "Oczekiwanie na rozpoczęcie nowej gry."
+
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:42
+#, fuzzy
+msgid "Board"
+msgstr "Plansza"
+
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:42
+msgid "Contract"
+msgstr "Kontrakt"
+
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:42
+msgid "Made"
+msgstr "Wykonano"
+
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:55
+msgid "Passed out"
+msgstr "Pas"
+
+#: ../../pybridge/games/bridge/ui/window_scoresheet.py:124
+msgid "Score Sheet"
+msgstr "Lista wyników"
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-09-26 12:51:34
|
Revision: 503
http://pybridge.svn.sourceforge.net/pybridge/?rev=503&view=rev
Author: umgangee
Date: 2007-09-26 05:51:30 -0700 (Wed, 26 Sep 2007)
Log Message:
-----------
Set "translatable" property on a couple strings, unset for "gtk-ok", "gtk-cancel" etc.
Modified Paths:
--------------
trunk/pybridge/glade/pybridge.glade
Modified: trunk/pybridge/glade/pybridge.glade
===================================================================
--- trunk/pybridge/glade/pybridge.glade 2007-09-02 14:26:54 UTC (rev 502)
+++ trunk/pybridge/glade/pybridge.glade 2007-09-26 12:51:30 UTC (rev 503)
@@ -115,7 +115,7 @@
<child>
<widget class="GtkImageMenuItem" id="menu_preferences">
<property name="visible">True</property>
- <property name="label" translatable="yes">gtk-preferences</property>
+ <property name="label">gtk-preferences</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_preferences_activate"/>
@@ -217,7 +217,7 @@
<widget class="GtkToolButton" id="newtable">
<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">New Table...</property>
+ <property name="label" translatable="yes">New Table...</property>
<property name="stock_id">gtk-new</property>
<signal name="clicked" handler="on_newtable_clicked"/>
</widget>
@@ -229,7 +229,7 @@
<widget class="GtkToolButton" id="jointable">
<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">Join Table</property>
+ <property name="label" translatable="yes">Join Table</property>
<property name="stock_id">gtk-jump-to</property>
<signal name="clicked" handler="on_jointable_clicked"/>
</widget>
@@ -244,9 +244,6 @@
</packing>
</child>
</widget>
- <packing>
- <property name="tab_expand">False</property>
- </packing>
</child>
<child>
<widget class="GtkLabel" id="label_tabletab">
@@ -255,7 +252,6 @@
</widget>
<packing>
<property name="type">tab</property>
- <property name="tab_expand">False</property>
<property name="tab_fill">False</property>
</packing>
</child>
@@ -309,7 +305,6 @@
</widget>
<packing>
<property name="position">1</property>
- <property name="tab_expand">False</property>
</packing>
</child>
<child>
@@ -320,7 +315,6 @@
<packing>
<property name="type">tab</property>
<property name="position">1</property>
- <property name="tab_expand">False</property>
<property name="tab_fill">False</property>
</packing>
</child>
@@ -523,6 +517,7 @@
<property name="can_focus">True</property>
<property name="label" translatable="yes">Save Password</property>
<property name="use_underline">True</property>
+ <property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
@@ -537,6 +532,7 @@
<property name="can_focus">True</property>
<property name="label" translatable="yes">Register as New User</property>
<property name="use_underline">True</property>
+ <property name="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
@@ -843,6 +839,7 @@
<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="response_id">0</property>
<signal name="clicked" handler="on_suitcolour_clicked"/>
<child>
<widget class="GtkLabel" id="label_clubcolour">
@@ -863,6 +860,7 @@
<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="response_id">0</property>
<signal name="clicked" handler="on_suitcolour_clicked"/>
<child>
<widget class="GtkLabel" id="label_diamondcolour">
@@ -884,6 +882,7 @@
<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="response_id">0</property>
<signal name="clicked" handler="on_suitcolour_clicked"/>
<child>
<widget class="GtkLabel" id="label_heartcolour">
@@ -905,6 +904,7 @@
<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="response_id">0</property>
<signal name="clicked" handler="on_suitcolour_clicked"/>
<child>
<widget class="GtkLabel" id="label_spadecolour">
@@ -939,6 +939,7 @@
<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="response_id">0</property>
<property name="draw_indicator">True</property>
</widget>
<packing>
@@ -958,9 +959,6 @@
</packing>
</child>
</widget>
- <packing>
- <property name="tab_expand">False</property>
- </packing>
</child>
<child>
<widget class="GtkLabel" id="label_gamedisplay">
@@ -969,7 +967,6 @@
</widget>
<packing>
<property name="type">tab</property>
- <property name="tab_expand">False</property>
<property name="tab_fill">False</property>
</packing>
</child>
@@ -986,16 +983,18 @@
<child>
<widget class="GtkButton" id="cancelbutton">
<property name="visible">True</property>
- <property name="label" translatable="yes">gtk-cancel</property>
+ <property name="label">gtk-cancel</property>
<property name="use_stock">True</property>
+ <property name="response_id">0</property>
<signal name="clicked" handler="on_cancelbutton_clicked"/>
</widget>
</child>
<child>
<widget class="GtkButton" id="okbutton">
<property name="visible">True</property>
- <property name="label" translatable="yes">gtk-ok</property>
+ <property name="label">gtk-ok</property>
<property name="use_stock">True</property>
+ <property name="response_id">0</property>
<signal name="clicked" handler="on_okbutton_clicked"/>
</widget>
<packing>
@@ -1088,8 +1087,9 @@
<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="label">gtk-close</property>
<property name="use_stock">True</property>
+ <property name="response_id">0</property>
<signal name="clicked" handler="on_closebutton_clicked"/>
</widget>
</child>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-09-02 14:26:52
|
Revision: 502
http://pybridge.svn.sourceforge.net/pybridge/?rev=502&view=rev
Author: umgangee
Date: 2007-09-02 07:26:54 -0700 (Sun, 02 Sep 2007)
Log Message:
-----------
French translation for PyBridge UI, thanks to Aldo Reset <al...@pl...>.
Added Paths:
-----------
trunk/pybridge/locale/fr/
trunk/pybridge/locale/fr/LC_MESSAGES/
trunk/pybridge/locale/fr/LC_MESSAGES/pybridge.mo
trunk/pybridge/locale/fr/LC_MESSAGES/pybridge.po
Added: trunk/pybridge/locale/fr/LC_MESSAGES/pybridge.mo
===================================================================
(Binary files differ)
Property changes on: trunk/pybridge/locale/fr/LC_MESSAGES/pybridge.mo
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Added: trunk/pybridge/locale/fr/LC_MESSAGES/pybridge.po
===================================================================
--- trunk/pybridge/locale/fr/LC_MESSAGES/pybridge.po (rev 0)
+++ trunk/pybridge/locale/fr/LC_MESSAGES/pybridge.po 2007-09-02 14:26:54 UTC (rev 502)
@@ -0,0 +1,658 @@
+# French translation for pybridge
+# Copyright (c) 2007 Rosetta Contributors and Canonical Ltd 2007
+# This file is distributed under the same license as the pybridge package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2007.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: pybridge\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2007-08-26 18:09+0100\n"
+"PO-Revision-Date: 2007-09-02 13:13+0000\n"
+"Last-Translator: Aldo Reset <al...@pl...>\n"
+"Language-Team: French <fr...@li...>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Rosetta-Export-Date: 2007-09-02 14:18:13+0000\n"
+
+#: ../../glade/pybridge.glade.h:1
+msgid "<b>Server Address</b>"
+msgstr "<b>Adresse du Serveur</b>"
+
+#: ../../glade/pybridge.glade.h:2
+msgid "<b>User Account</b>"
+msgstr "<b>Compte Joueur</b>"
+
+#: ../../glade/pybridge.glade.h:3
+msgid ""
+"<i>Changes to these settings are effective after restarting PyBridge.</i>"
+msgstr ""
+"<i>Les modifications seront effectives au redemmarage de PyBridge.</i>"
+
+#: ../../glade/pybridge.glade.h:4
+msgid "Background:"
+msgstr "Arrire Plan"
+
+#: ../../glade/pybridge.glade.h:5
+msgid "C"
+msgstr "C"
+
+#: ../../glade/pybridge.glade.h:6
+msgid "Card Style:"
+msgstr "Modle Carte"
+
+#: ../../glade/pybridge.glade.h:7
+msgid "Connect to Server"
+msgstr "Connexion au Serveur"
+
+#: ../../glade/pybridge.glade.h:8
+msgid "Create a New Table"
+msgstr "Crer une nouvelle Table"
+
+#: ../../glade/pybridge.glade.h:9
+msgid "D"
+msgstr "D"
+
+#: ../../glade/pybridge.glade.h:10
+msgid "Display suits as symbols?"
+msgstr "Reprsenter les couleurs par des symboles ?"
+
+#: ../../glade/pybridge.glade.h:11
+msgid "Game Display"
+msgstr "Affichage du Jeu"
+
+#: ../../glade/pybridge.glade.h:12
+msgid "Game at Table:"
+msgstr "Jeu la table:"
+
+#: ../../glade/pybridge.glade.h:13
+msgid "H"
+msgstr "H"
+
+#: ../../glade/pybridge.glade.h:14
+msgid "Host Name:"
+msgstr "Nom du Poste"
+
+#: ../../glade/pybridge.glade.h:15
+msgid "Open Tables"
+msgstr "Tables Ouvertes"
+
+#: ../../glade/pybridge.glade.h:16
+msgid "Password:"
+msgstr "Mot de Passe"
+
+#: ../../glade/pybridge.glade.h:17
+msgid "Port:"
+msgstr "Port:"
+
+#: ../../glade/pybridge.glade.h:18
+msgid "PyBridge"
+msgstr "PyBridge"
+
+#: ../../glade/pybridge.glade.h:19
+msgid "PyBridge Preferences"
+msgstr "PyBridge Prfrences"
+
+#: ../../glade/pybridge.glade.h:20
+msgid "PyBridge _Home Page"
+msgstr "PyBridge _Page d'accueil"
+
+#: ../../glade/pybridge.glade.h:21
+msgid "Register as New User"
+msgstr "Inscrire Nouveau Joueur"
+
+#: ../../glade/pybridge.glade.h:22 ../../pybridge/ui/vocabulary.py:53
+msgid "S"
+msgstr "S"
+
+#: ../../glade/pybridge.glade.h:23
+msgid "Save Password"
+msgstr "Sauvegarder Mot de Passe"
+
+#: ../../glade/pybridge.glade.h:24
+msgid "Suit Colours:"
+msgstr ""
+
+#: ../../glade/pybridge.glade.h:25
+msgid "Table Name:"
+msgstr "Nom de la Table"
+
+#: ../../glade/pybridge.glade.h:26
+msgid "User Information"
+msgstr "Information Joueur"
+
+#: ../../glade/pybridge.glade.h:27
+msgid "User Name:"
+msgstr "Nom du Joueur"
+
+#: ../../glade/pybridge.glade.h:28
+msgid "Users Online"
+msgstr "Joueurs en Ligne"
+
+#: ../../glade/pybridge.glade.h:29
+msgid "_About PyBridge"
+msgstr "_Au sujet de Pybridge"
+
+#: ../../glade/pybridge.glade.h:30
+msgid "_Connect to Server..."
+msgstr "_Connexion au Serveur"
+
+#: ../../glade/pybridge.glade.h:31
+msgid "_Connection"
+msgstr "_Connexion"
+
+#: ../../glade/pybridge.glade.h:32
+msgid "_Disconnect"
+msgstr "_Dconnexion"
+
+#: ../../glade/pybridge.glade.h:33
+msgid "_Help"
+msgstr "_Aide"
+
+#: ../../glade/pybridge.glade.h:34
+msgid "_New Table..."
+msgstr "_Nouvelle Table"
+
+#: ../../glade/pybridge.glade.h:35
+msgid "_Open Game..."
+msgstr "_Ouvrir Jeu..."
+
+#: ../../glade/pybridge.glade.h:36
+msgid "_Options"
+msgstr "_Options"
+
+#: ../../glade/pybridge.glade.h:37
+msgid "gtk-cancel"
+msgstr "gtk-cancel"
+
+#: ../../glade/pybridge.glade.h:38
+msgid "gtk-close"
+msgstr "gtk-close"
+
+#: ../../glade/pybridge.glade.h:39
+msgid "gtk-ok"
+msgstr "gtk-ok"
+
+#: ../../glade/pybridge.glade.h:40
+msgid "gtk-preferences"
+msgstr "gtk-preferences"
+
+#: ../../pybridge/ui/dialog_connection.py:74
+msgid "Connection failed"
+msgstr "Connexion choue"
+
+#: ../../pybridge/ui/dialog_connection.py:75
+msgid "Could not connect to server."
+msgstr "Impossible de se connecter au serveur"
+
+#: ../../pybridge/ui/dialog_connection.py:76
+#: ../../pybridge/ui/dialog_newtable.py:62
+#, python-format
+msgid "Reason: %s"
+msgstr "Raison: %s"
+
+#: ../../pybridge/ui/dialog_newtable.py:60
+msgid "Could not create table"
+msgstr "Impossible de crer la table"
+
+#: ../../pybridge/ui/dialog_newtable.py:61
+msgid "The table was not created by the server."
+msgstr "La table n'a pas t cre par le serveur"
+
+#: ../../pybridge/ui/dialog_preferences.py:43
+msgid "PNG images"
+msgstr "Images PNG"
+
+#: ../../pybridge/ui/dialog_preferences.py:98
+#, python-format
+msgid "Select colour for %s symbol"
+msgstr "Choisir la couleur comem symbole %s"
+
+#: ../../pybridge/ui/dialog_userinfo.py:29
+msgid "Real Name"
+msgstr "Nom rel"
+
+#: ../../pybridge/ui/dialog_userinfo.py:30
+msgid "Email Address"
+msgstr "Adresse courriel"
+
+#: ../../pybridge/ui/dialog_userinfo.py:32
+msgid "Profile"
+msgstr "Profil"
+
+#: ../../pybridge/ui/dialog_userinfo.py:54
+#, python-format
+msgid "Information for %(user)s"
+msgstr "Information pour %(user)s"
+
+#: ../../pybridge/ui/dialog_userinfo.py:68
+msgid "not specified"
+msgstr "Non prcis"
+
+#: ../../pybridge/ui/excepthook.py:34
+msgid "Program error"
+msgstr "Erreur de programme"
+
+#: ../../pybridge/ui/excepthook.py:35
+msgid ""
+"PyBridge detected an unexpected program error. You should close and restart "
+"PyBridge."
+msgstr "Pybridge a dtect une erreur. vosu devez fermer et relancer Pybridge."
+
+#: ../../pybridge/ui/excepthook.py:36
+msgid ""
+"If you continue to experience this error, please submit a bug report, "
+"attaching the following error trace."
+msgstr ""
+"Si cette erreur est frquente, svp informer nous du bug, en attachant les "
+"informations suivantes."
+
+#: ../../pybridge/ui/vocabulary.py:32
+msgid "Pass"
+msgstr "Passe"
+
+#: ../../pybridge/ui/vocabulary.py:33
+msgid "Double"
+msgstr "Contre"
+
+#: ../../pybridge/ui/vocabulary.py:34
+msgid "Redouble"
+msgstr "Surcintre"
+
+#: ../../pybridge/ui/vocabulary.py:44
+msgid "North"
+msgstr "Nord"
+
+#: ../../pybridge/ui/vocabulary.py:45
+msgid "East"
+msgstr "Est"
+
+#: ../../pybridge/ui/vocabulary.py:46
+msgid "South"
+msgstr "Sud"
+
+#: ../../pybridge/ui/vocabulary.py:47
+msgid "West"
+msgstr "Ouest"
+
+#: ../../pybridge/ui/vocabulary.py:51
+msgid "N"
+msgstr "N"
+
+#: ../../pybridge/ui/vocabulary.py:52
+msgid "E"
+msgstr "E"
+
+#: ../../pybridge/ui/vocabulary.py:54
+msgid "W"
+msgstr "O"
+
+#: ../../pybridge/ui/vocabulary.py:68
+msgid "Two"
+msgstr "Deux"
+
+#: ../../pybridge/ui/vocabulary.py:69
+msgid "Three"
+msgstr "Trois"
+
+#: ../../pybridge/ui/vocabulary.py:70
+msgid "Four"
+msgstr "Quatre"
+
+#: ../../pybridge/ui/vocabulary.py:71
+msgid "Five"
+msgstr "Cinq"
+
+#: ../../pybridge/ui/vocabulary.py:72
+msgid "Six"
+msgstr "Six"
+
+#: ../../pybridge/ui/vocabulary.py:73
+msgid "Seven"
+msgstr "Sept"
+
+#: ../../pybridge/ui/vocabulary.py:74
+msgid "Eight"
+msgstr "Huit"
+
+#: ../../pybridge/ui/vocabulary.py:75
+msgid "Nine"
+msgstr "Neuf"
+
+#: ../../pybridge/ui/vocabulary.py:76
+msgid "Ten"
+msgstr "Dix"
+
+#: ../../pybridge/ui/vocabulary.py:77
+msgid "Jack"
+msgstr "Valet"
+
+#: ../../pybridge/ui/vocabulary.py:78
+msgid "Queen"
+msgstr "Dame"
+
+#: ../../pybridge/ui/vocabulary.py:79
+msgid "King"
+msgstr "Roi"
+
+#: ../../pybridge/ui/vocabulary.py:80
+msgid "Ace"
+msgstr "As"
+
+#: ../../pybridge/ui/vocabulary.py:100
+msgid "Clubs"
+msgstr "Trefles"
+
+#: ../../pybridge/ui/vocabulary.py:101
+msgid "Diamonds"
+msgstr "Carreaux"
+
+#: ../../pybridge/ui/vocabulary.py:102
+msgid "Hearts"
+msgstr "Coeurs"
+
+#: ../../pybridge/ui/vocabulary.py:103
+msgid "Spades"
+msgstr "Piques"
+
+#: ../../pybridge/ui/vocabulary.py:122
+msgid "Club"
+msgstr "Trefle"
+
+#: ../../pybridge/ui/vocabulary.py:123
+msgid "Diamond"
+msgstr "Carreau"
+
+#: ../../pybridge/ui/vocabulary.py:124
+msgid "Heart"
+msgstr "Coeur"
+
+#: ../../pybridge/ui/vocabulary.py:125
+msgid "Spade"
+msgstr "Pique"
+
+#: ../../pybridge/ui/vocabulary.py:126
+msgid "No Trump"
+msgstr "Sans Atout"
+
+#: ../../pybridge/ui/vocabulary.py:147
+msgid "All"
+msgstr "Tout"
+
+#: ../../pybridge/ui/vocabulary.py:148
+#: ../../pybridge/games/bridge/ui/scoresheet.py:42
+#: ../../pybridge/games/bridge/ui/scoresheet.py:87
+msgid "N/S"
+msgstr "N/S"
+
+#: ../../pybridge/ui/vocabulary.py:149
+#: ../../pybridge/games/bridge/ui/scoresheet.py:42
+#: ../../pybridge/games/bridge/ui/scoresheet.py:87
+msgid "E/W"
+msgstr "E/O"
+
+#: ../../pybridge/ui/vocabulary.py:150
+msgid "None"
+msgstr "Aucun"
+
+#: ../../pybridge/ui/vocabulary.py:169
+#, python-format
+msgid "%(level)s %(strain)s"
+msgstr ""
+
+#: ../../pybridge/ui/vocabulary.py:183
+#, python-format
+msgid "%(rank)s of %(suit)s"
+msgstr ""
+
+#: ../../pybridge/ui/vocabulary.py:201
+#, python-format
+msgid "%(bid)s %(doubled)s by %(declarer)s"
+msgstr "%(bid)s %(doubled)s par %(declarer)s"
+
+#: ../../pybridge/ui/vocabulary.py:203
+#, python-format
+msgid "%(bid)s by %(declarer)s"
+msgstr "%(bid)s par %(declarer)s"
+
+#: ../../pybridge/ui/window_chat.py:73
+msgid "1 person in room"
+msgstr "1 personne dans la pice"
+
+#: ../../pybridge/ui/window_chat.py:75
+#, python-format
+msgid "%(num)s people in room"
+msgstr "%(num)s personne dans la pice"
+
+#: ../../pybridge/ui/window_chat.py:194
+#, python-format
+msgid "%(user)s has joined the conversation"
+msgstr "%(user)s a rejoint la conversation"
+
+#: ../../pybridge/ui/window_chat.py:196
+#, python-format
+msgid "%(user)s has left the conversation"
+msgstr "%(user)s a quitt la conversation"
+
+#: ../../pybridge/ui/window_chat.py:290
+msgid "Chat"
+msgstr "Chat"
+
+#: ../../pybridge/ui/window_gametable.py:37
+msgid "Unnamed Game"
+msgstr "Jeu sans Nom"
+
+#: ../../pybridge/ui/window_gametable.py:46
+msgid "Table"
+msgstr "Table"
+
+#: ../../pybridge/ui/window_gametable.py:78
+msgid "Take Seat"
+msgstr "Prendre Place"
+
+#: ../../pybridge/ui/window_gametable.py:84
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:336
+msgid "Leave Seat"
+msgstr "Quitter Place"
+
+#: ../../pybridge/ui/window_gametable.py:99
+#: ../../pybridge/ui/window_gametable.py:193
+msgid "Leave Table"
+msgstr "Quitter la Table"
+
+#: ../../pybridge/ui/window_gametable.py:135
+#, python-format
+msgid "%(tablename)s (%(gametype)s)"
+msgstr "%(tablename)s (%(gametype)s)"
+
+#: ../../pybridge/ui/window_gametable.py:191
+msgid "Leave table?"
+msgstr "Quitter la table ?"
+
+#: ../../pybridge/ui/window_gametable.py:194
+msgid "Are you sure you wish to leave this table?"
+msgstr "Etes vous sure de vouloir quitter cette table?"
+
+#: ../../pybridge/ui/window_gametable.py:195
+msgid ""
+"You are currently playing a game. Leaving may forfeit the game, or incur "
+"penalties."
+msgstr ""
+"Vous etes en train de jouer. Quiter peut faire forfait le jeu, ou provoquer "
+"de pnalits"
+
+#: ../../pybridge/ui/window_main.py:125
+msgid "Connection to server lost"
+msgstr "Connexion au serveur rompue"
+
+#: ../../pybridge/ui/window_main.py:126
+#, python-format
+msgid "The connection to %s was lost unexpectedly."
+msgstr "La connexion a %s a t perdue."
+
+#: ../../pybridge/ui/window_main.py:127
+msgid ""
+"Please check your computer's network connection status before reconnecting. "
+"If you cannot reconnect, the server may be offline."
+msgstr ""
+"Verifier votre connexion avant tenter une reconnexion.Si vous ne vous "
+"reconnectez pas, le serveur est peut tre hors ligne."
+
+#: ../../pybridge/ui/window_main.py:272
+msgid "Disconnect from server"
+msgstr "Deconnexion du serveur"
+
+#: ../../pybridge/ui/window_main.py:275
+msgid "Are you sure you wish to disconnect?"
+msgstr "Etes vous sur de vouloir vous deconnecter?"
+
+#: ../../pybridge/ui/window_main.py:276
+msgid ""
+"You are playing at a table. Disconnecting may forfeit the game, or incur "
+"penalties."
+msgstr ""
+"Vous etes en train de jouer. Quiter peut faire forfait le jeu, ou provoquer "
+"de pnalits"
+
+#: ../../pybridge/ui/window_main.py:305
+msgid "A free online bridge game."
+msgstr "Un jeu libre de brige en ligne"
+
+#: ../../pybridge/games/bridge/ui/scoresheet.py:42
+msgid "Board"
+msgstr ""
+
+#: ../../pybridge/games/bridge/ui/scoresheet.py:42
+msgid "Contract"
+msgstr "Contrat"
+
+#: ../../pybridge/games/bridge/ui/scoresheet.py:42
+msgid "Made"
+msgstr ""
+
+#: ../../pybridge/games/bridge/ui/scoresheet.py:55
+msgid "Passed out"
+msgstr ""
+
+#: ../../pybridge/games/bridge/ui/scoresheet.py:124
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:228
+msgid "Score Sheet"
+msgstr "Scores"
+
+#: ../../pybridge/games/bridge/ui/window_bidbox.py:41
+msgid "Bidding Box"
+msgstr "Enchre"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:103
+msgid "Declarer"
+msgstr "Dclarant"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:109
+msgid "Defence"
+msgstr ""
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:132
+msgid "No contract"
+msgstr "Pas de contrat"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:154
+msgid "Dealer"
+msgstr "Ouvreur"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:162
+msgid "Vuln"
+msgstr "Vulnrable"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:169
+msgid "Contract Bridge"
+msgstr "Contrat"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:208
+msgid "Bidding"
+msgstr "Ouverture"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:217
+msgid "Previous Trick"
+msgstr "Leve prcdente"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:297
+msgid "Game result"
+msgstr "Resultat de la Partie"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:311
+#, python-format
+msgid "Contract %(contract)s made by 1 trick."
+msgstr "Le Contrat %(contract)s raliser d'une leve."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:313
+#, python-format
+msgid "Contract %(contract)s made by %(offset)s tricks."
+msgstr "Le Contrat %(contract)s raliser avec %(offset)s leves."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:316
+#, python-format
+msgid "Contract %(contract)s failed by 1 trick."
+msgstr "Le contrat %(contract)s chute d'une leve"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:318
+#, python-format
+msgid "Contract %(contract)s failed by %(offset)s tricks."
+msgstr "Le contrat %(contract)s chute de %(offset)s leves"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:320
+#, python-format
+msgid "Contract %(contract)s made exactly."
+msgstr "Le contrat %(contract)s russit"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:326
+msgid "declarer"
+msgstr "dclare"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:326
+msgid "defence"
+msgstr "Intervention"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:327
+#, python-format
+msgid "Score %(points)s points for %(pair)s."
+msgstr "Score %(points)s points pour %(pair)s."
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:332
+msgid "Bidding passed out."
+msgstr "Enchere passe"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:333
+msgid "No score."
+msgstr "Pas de point"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:337
+msgid "Click OK to start next game."
+msgstr "Cliquer Ok pour dmarrer la prochaine partie"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:408
+msgid "Play a card from your hand."
+msgstr "Jouer une carte de votre main"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:410
+msgid "Play a card from dummy's hand."
+msgstr "Jouer une carte de la main du mort"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:412
+#, python-format
+msgid "It is %s's turn to play a card."
+msgstr "Ce n'est pas %s's de jouer une carte"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:416
+msgid "Make a call from the bidding box."
+msgstr "Faire un appel de l'enchre"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:418
+#, python-format
+msgid "It is %s's turn to make a call."
+msgstr "Ce n'est pas le tour de %s's de faire un appel"
+
+#: ../../pybridge/games/bridge/ui/window_bridgetable.py:421
+msgid "Waiting for next game to start."
+msgstr "Attender que la prochaine partie commence"
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-09-02 11:41:33
|
Revision: 501
http://pybridge.svn.sourceforge.net/pybridge/?rev=501&view=rev
Author: umgangee
Date: 2007-09-02 04:41:30 -0700 (Sun, 02 Sep 2007)
Log Message:
-----------
Register translation paths for Glade.
Modified Paths:
--------------
trunk/pybridge/pybridge/ui/__init__.py
Modified: trunk/pybridge/pybridge/ui/__init__.py
===================================================================
--- trunk/pybridge/pybridge/ui/__init__.py 2007-08-31 13:45:20 UTC (rev 500)
+++ trunk/pybridge/pybridge/ui/__init__.py 2007-09-02 11:41:30 UTC (rev 501)
@@ -18,18 +18,23 @@
from twisted.internet import gtk2reactor
gtk2reactor.install()
-import gtk
-from twisted.internet import reactor
+# Default settings based on the user's environment.
import locale
-import gettext
locale.setlocale(locale.LC_ALL, '')
+
+import gettext, gtk.glade as glade
import pybridge.environment as env
-gettext.bindtextdomain('pybridge', env.get_localedir())
-gettext.textdomain('pybridge')
-gettext.install('pybridge')
+for module in gettext, glade:
+ module.bindtextdomain('pybridge', env.get_localedir())
+ module.textdomain('pybridge')
+
+# Register the gettext function for the whole interpreter as "_"
+gettext.install('pybridge', env.get_localedir())
+
+
import config
config.load()
@@ -47,7 +52,9 @@
wm.open(WindowMain)
# Start the event loop.
+ from twisted.internet import reactor
reactor.run()
+ import gtk
gtk.main()
config.save() # Save config at exit.
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-08-31 13:45:22
|
Revision: 500
http://pybridge.svn.sourceforge.net/pybridge/?rev=500&view=rev
Author: umgangee
Date: 2007-08-31 06:45:20 -0700 (Fri, 31 Aug 2007)
Log Message:
-----------
Refactor rubber scoring, to facilitate rubber scoresheet display.
Modified Paths:
--------------
trunk/pybridge/pybridge/games/bridge/game.py
trunk/pybridge/pybridge/games/bridge/result.py
trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py
Added Paths:
-----------
trunk/pybridge/pybridge/games/bridge/ui/window_scoresheet.py
Modified: trunk/pybridge/pybridge/games/bridge/game.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/game.py 2007-08-03 18:42:14 UTC (rev 499)
+++ trunk/pybridge/pybridge/games/bridge/game.py 2007-08-31 13:45:20 UTC (rev 500)
@@ -97,14 +97,14 @@
if len(self.rubbers) == 0 or self.rubbers[-1].winner:
self.board['vuln'] = Vulnerable.None # First round, new rubber.
else:
- games = self.rubbers[-1].games
- if len(games[(Direction.North, Direction.South)]) > 0:
- if len(games[(Direction.East, Direction.West)]) > 0:
+ pairs = [pair for game, pair in self.rubbers[-1].games]
+ if pairs.count((Direction.North, Direction.South)) > 0:
+ if pairs.count((Direction.East, Direction.West)) > 0:
self.board['vuln'] = Vulnerable.All
else:
self.board['vuln'] = Vulnerable.NorthSouth
else:
- if len(games[(Direction.East, Direction.West)]) > 0:
+ if pairs.count((Direction.East, Direction.West)) > 0:
self.board['vuln'] = Vulnerable.EastWest
else:
self.board['vuln'] = Vulnerable.None
Modified: trunk/pybridge/pybridge/games/bridge/result.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/result.py 2007-08-03 18:42:14 UTC (rev 499)
+++ trunk/pybridge/pybridge/games/bridge/result.py 2007-08-31 13:45:20 UTC (rev 500)
@@ -233,40 +233,41 @@
def _getGames(self):
- """Returns, for each pair, a list of completed 'games' won by the pair
- in this rubber.
+ """Returns a list of completed (ie. won) 'games' in this rubber, in the
+ order of their completion.
- A game is represented as the list of consecutive results in this rubber,
- with below-the-line scores that count towards the game.
+ A game is represented as a list of consecutive results from this rubber,
+ coupled with the identifier of the scoring pair.
"""
- gamesNS, gamesEW = [], []
+ games = []
- game = []
- belowNS, belowEW = 0, 0 # Cumulative totals for results.
+ thisgame = []
+ belowNS, belowEW = 0, 0 # Cumulative totals for results in this game.
+
for result in self:
- game.append(result)
-
+ thisgame.append(result)
if result.contract.declarer in (Direction.North, Direction.South):
belowNS += result.score[1]
if belowNS >= 100:
- gamesNS.append(game)
+ games.append((thisgame, (Direction.North, Direction.South)))
else:
belowEW += result.score[1]
if belowEW >= 100:
- gamesEW.append(game)
+ games.append((thisgame, (Direction.East, Direction.West)))
- # If either accumulated total exceeds 100, proceed to next game.
- if belowNS >= 100 or belowEW >= 100:
- game = []
- belowNS, belowEW = 0, 0
+ # If either total for this game exceeds 100, proceed to next game.
+ if belowNS >= 100 or belowEW >= 100:
+ thisgame = []
+ belowNS, belowEW = 0, 0 # Reset accumulators.
- return {(Direction.North, Direction.South): gamesNS,
- (Direction.East, Direction.West): gamesEW}
+ return games
def _getWinner(self):
"""The rubber is won by the pair which have completed two games."""
- for pair, games in self.games.items():
- if len(games) >= 2:
+ pairs = [pair for game, pair in self.games]
+
+ for pair in ((Direction.North, Direction.South), (Direction.East, Direction.West)):
+ if pairs.count(pair) >= 2:
return pair
Modified: trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py 2007-08-03 18:42:14 UTC (rev 499)
+++ trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py 2007-08-31 13:45:20 UTC (rev 500)
@@ -29,6 +29,7 @@
from pybridge.ui.window_gametable import WindowGameTable
from window_bidbox import WindowBidbox
+from window_scoresheet import ScoreSheet
class BiddingView(gtk.TreeView):
@@ -83,41 +84,6 @@
-class ScoreView(gtk.TreeView):
- """A display of contracts bid, their results and their scores."""
-
-
- def __init__(self):
- gtk.TreeView.__init__(self)
- self.set_rules_hint(True)
-
- self.store = gtk.ListStore(str, str, str, str)
- self.set_model(self.store)
- self.clear = self.store.clear
- renderer = gtk.CellRendererText()
-
- for index, title in enumerate([_('Contract'), _('Made'), _('N/S'), _('E/W')]):
- column = gtk.TreeViewColumn(title, renderer, markup=index)
- self.append_column(column)
-
-
- def add_score(self, game):
- declarerWon, defenceWon = game.play.wonTrickCount()
- score = game.result.score
-
- 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:
- textNS, textEW = str(abs(score)), ''
- else:
- textNS, textEW = '', str(abs(score))
-
- self.store.prepend([textContract, textMade, textNS, textEW])
-
-
-
-
class BridgeDashboard(gtk.VBox):
"""An at-a-glance display of the state of a bridge game."""
@@ -242,7 +208,7 @@
exp = gtk.Expander(_('Bidding'))
exp.set_expanded(True)
exp.add(frame)
- self.sidebar.pack_start(exp)
+ self.sidebar.pack_start(exp, expand=True)
self.trickarea = TrickArea(positions=Direction)
self.trickarea.set_size_request(-1, 180)
@@ -253,10 +219,10 @@
exp.add(frame)
self.sidebar.pack_start(exp, expand=False)
- self.scoreview = ScoreView()
+ self.scoresheet = ScoreSheet()
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- sw.add(self.scoreview)
+ sw.add(self.scoresheet)
frame = gtk.Frame()
frame.add(sw)
exp = gtk.Expander(_('Score Sheet'))
@@ -265,11 +231,6 @@
self.sidebar.pack_start(exp, expand=False)
- def errback(self, failure):
- print "Error: %s" % failure.getErrorMessage()
- print failure.getBriefTraceback()
-
-
def setTable(self, table):
"""Changes display to match the table specified.
@@ -337,12 +298,11 @@
# Determine and display score in dialog box and score sheet.
if self.table.game.contract:
- self.scoreview.add_score(self.table.game)
+ self.scoresheet.add_result(self.table.game.result)
tricksMade = self.table.game.result.tricksMade
tricksRequired = self.table.game.contract.bid.level.index + 7
offset = tricksMade - tricksRequired
- score = self.table.game.result.score
fields = {'contract': render_contract(self.table.game.contract),
'offset': abs(offset)}
@@ -359,6 +319,10 @@
else:
resultText = _('Contract %(contract)s made exactly.') % fields
+ score = self.table.game.result.score
+ if isinstance(score, tuple): # Rubber scoring.
+ score = sum(score) # TODO: display above, below separately.
+
pair = (score >= 0 and _('declarer')) or _('defence')
scoreText = _('Score %(points)s points for %(pair)s.') % {'points': abs(score), 'pair': pair}
Added: trunk/pybridge/pybridge/games/bridge/ui/window_scoresheet.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/ui/window_scoresheet.py (rev 0)
+++ trunk/pybridge/pybridge/games/bridge/ui/window_scoresheet.py 2007-08-31 13:45:20 UTC (rev 500)
@@ -0,0 +1,140 @@
+# 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
+
+from pybridge.games.bridge.result import DuplicateResult, RubberResult
+from pybridge.games.bridge.symbols import Direction
+
+from pybridge.ui.eventhandler import SimpleEventHandler
+import pybridge.ui.vocabulary as voc
+
+
+class ScoreSheet(gtk.TreeView):
+ """A score sheet widget, which presents GameResult information."""
+
+ # TODO: display total scores for N/S and E/W.
+
+
+ def __init__(self):
+ gtk.TreeView.__init__(self)
+ self.set_rules_hint(True)
+
+ self.store = gtk.ListStore(int, str, str, str, str)
+ self.set_model(self.store)
+
+ renderer = gtk.CellRendererText()
+ for index, title in enumerate([_('Board'), _('Contract'), _('Made'), _('N/S'), _('E/W')]):
+ column = gtk.TreeViewColumn(title, renderer, markup=index)
+ self.append_column(column)
+
+
+ def add_result(self, result):
+ if isinstance(result, RubberResult):
+ # Rubber results are split into 'above' and 'below' scores.
+ score = sum(result.score)
+ else:
+ score = result.score
+
+ if result.contract is None: # Bidding passed out.
+ row = (result.board['num'], _('Passed out'), '-', '-', '', '')
+
+ else:
+ if result.contract.declarer in (Direction.North, Direction.South) and score > 0 \
+ or result.contract.declarer in (Direction.East, Direction.West) and score < 0:
+ scoreNS, scoreEW = str(abs(score)), ''
+ else:
+ scoreNS, scoreEW = '', str(abs(score))
+
+ row = (result.board['num'], voc.render_contract(result.contract),
+ #voc.DIRECTION_NAMES[result.contract.declarer],
+ str(result.tricksMade), scoreNS, scoreEW)
+
+ self.store.append(row)
+
+
+
+
+class RubberScoreSheet(gtk.TreeView):
+ """A score sheet widget, which presents a Rubber object."""
+
+
+ def __init__(self):
+ gtk.TreeView.__init__(self)
+ self.set_rules_hint(True)
+ self.set_row_separator_func(self._row_separator)
+
+ # Set bool field in a row to display as separator.
+ self.store = gtk.ListStore(str, str, bool)
+ self.set_model(self.store)
+
+ renderer = gtk.CellRendererText()
+ for index, title in enumerate([_('N/S'), _('E/W')]):
+ column = gtk.TreeViewColumn(title, renderer, markup=index)
+ self.append_column(column)
+
+
+ def set_rubber(self, rubber):
+ self.store.clear()
+ self.store.append(('', '', True)) # The initial dividing line.
+
+ for game, pair in rubber.games:
+ #aboveiters, belowiters = [], []
+ for result in rubber:
+ above, below = result.score
+ if result.contract.declarer in (Direction.North, Direction.South) and below > 0 \
+ or result.contract.declarer in (Direction.East, Direction.West) and score < 0:
+ self.store.prepend((str(above), '', False))
+ self.store.append((str(below), '', False))
+ else:
+ self.store.prepend(('', str(above), False))
+ self.store.append(('', str(below), False))
+
+
+ def _row_separator(self, model, iter, data):
+ print model, iter, data
+ return True
+
+
+
+
+class WindowScoreSheet(object):
+ """"""
+
+
+ def __init__(self, parent=None):
+ self.window = gtk.Window()
+ if parent:
+ self.window.set_transient_for(parent.window)
+ self.window.set_title(_('Score Sheet'))
+ self.window.connect('delete_event', self.on_delete_event)
+ #self.window.set_resizable(False)
+
+ self.eventHandler = SimpleEventHandler(self)
+ self.table = None
+
+
+ def tearDown(self):
+ pass
+
+
+
+ def on_delete_event(self, widget, *args):
+ # TODO: call wm.close(self)
+ 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-08-03 18:42:16
|
Revision: 499
http://pybridge.svn.sourceforge.net/pybridge/?rev=499&view=rev
Author: umgangee
Date: 2007-08-03 11:42:14 -0700 (Fri, 03 Aug 2007)
Log Message:
-----------
New Rubber class (for rubber bridge), move some logic from Board to BridgeGame. I think this implements rubber bridge scoring/vulnerability rules accurately, but some testing is still required.
Modified Paths:
--------------
trunk/pybridge/pybridge/games/bridge/board.py
trunk/pybridge/pybridge/games/bridge/game.py
trunk/pybridge/pybridge/games/bridge/result.py
Modified: trunk/pybridge/pybridge/games/bridge/board.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/board.py 2007-07-27 19:05:07 UTC (rev 498)
+++ trunk/pybridge/pybridge/games/bridge/board.py 2007-08-03 18:42:14 UTC (rev 499)
@@ -48,7 +48,7 @@
@classmethod
def first(cls, deal=None):
- """Build an initial board.
+ """Builds an initial board.
@deal: if provided, the deal to be wrapped by board.
Otherwise, a randomly-generated deal is wrapped.
@@ -58,27 +58,22 @@
board['num'] = 1
board['time'] = tuple(time.localtime())
- board['dealer'] = Direction.North # Arbitary.
+ # Convention for duplicate bridge.
+ board['dealer'] = Direction.North
board['vuln'] = Vulnerable.None
return board
- def next(self, results, deal=None):
- """Given the results for this board (and all previous boards),
- builds the next board.
+ def next(self, deal=None):
+ """Builds and returns a successor board to this board.
- The dealer and vulnerability of the next board are calculated
- from the results provided.
+ The dealer and vulnerability of the successor board are determined from
+ the board number, according to the rotation scheme for duplicate bridge.
- @param result: a list of all previous results, ordered from earliest
- to most recent, ie. this board's result is last in list.
@param deal: if provided, the deal to be wrapped by next board.
Otherwise, a randomly-generated deal is wrapped.
"""
- boardresult = results[-1]
- assert boardresult.board == self
-
board = Board(self.copy()) # copy() returns a dict.
board['deal'] = deal or Deal.fromRandom()
board['num'] = board.get('num', 0) + 1
@@ -87,33 +82,10 @@
# Dealer rotates clockwise.
board['dealer'] = Direction[(board['dealer'].index + 1) % 4]
- if isinstance(boardresult, DuplicateResult):
- # See http://www.d21acbl.com/References/Laws/node5.html#law2
- i = (board['num'] - 1) % 16
- # Map from duplicate board index range 1..16 to vulnerability.
- board['vuln'] = Vulnerable[(i%4 + i/4)%4]
+ # Map from duplicate board index range 1..16 to vulnerability.
+ # See http://www.d21acbl.com/References/Laws/node5.html#law2
+ i = (board['num'] - 1) % 16
+ board['vuln'] = Vulnerable[(i%4 + i/4)%4]
- elif isinstance(boardresult, RubberResult):
- belowNS, belowEW = 0, 0 # Running totals of below-the-line scores.
- board['vuln'] = Vulnerable.None
- # Only consider rounds which score below-the-line.
- for result in (r for r in results if r.score.below > 0):
- if result.contract.declarer in (Direction.North, Direction.South):
- belowNS += result.score.below
- pair = Vulnerable.NorthSouth
- else:
- belowEW += result.score.below
- pair = Vulnerable.EastWest
- # If either score exceeds 100, pair has made game.
- if belowNS >= 100 or belowEW >= 100:
- belowNS, belowEW = 0, 0 # Reset totals for next game.
- # Vulnerability transitions.
- if board['vuln'] == Vulnerable.None:
- board['vuln'] = pair
- elif board['vuln'] in (pair, Vulnerable.All):
- board['vuln'] = Vulnerable.None
- else: # Pair was not vulnerable, but other pair was.
- board['vuln'] = Vulnerable.All
-
return board
Modified: trunk/pybridge/pybridge/games/bridge/game.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/game.py 2007-07-27 19:05:07 UTC (rev 498)
+++ trunk/pybridge/pybridge/games/bridge/game.py 2007-08-03 18:42:14 UTC (rev 499)
@@ -25,8 +25,8 @@
from auction import Auction
from board import Board
-from play import Trick, TrickPlay
-from result import DuplicateResult, RubberResult
+from play import TrickPlay
+from result import DuplicateResult, Rubber, RubberResult
from call import Bid, Pass, Double, Redouble
from card import Card
@@ -56,7 +56,7 @@
Strain.NoTrump: None}
- def __init__(self):
+ def __init__(self, **options):
self.listeners = []
self.board = None
@@ -68,6 +68,11 @@
self.visibleHands = {} # A subset of deal, containing revealed hands.
self.players = {} # One-to-one mapping from BridgePlayer to Direction.
+ self.options = options
+ if self.options.get('RubberScoring'): # Use rubber scoring?
+ self.rubbers = [] # Group results into Rubber objects.
+
+
contract = property(lambda self: self.auction and self.auction.contract or None)
trumpSuit = property(lambda self: self.play and self.play.trumpSuit or None)
result = property(lambda self: not self.inProgress() and self.results[-1])
@@ -83,10 +88,27 @@
if board: # Use specified board.
self.board = board
elif self.board: # Advance to next round.
- self.board = self.board.next(self.results)
- else: # Create a board.
+ self.board = self.board.next()
+ else: # Create an initial board.
self.board = Board.first()
+ if self.options.get('RubberScoring'):
+ # Vulnerability determined by number of games won by each pair.
+ if len(self.rubbers) == 0 or self.rubbers[-1].winner:
+ self.board['vuln'] = Vulnerable.None # First round, new rubber.
+ else:
+ games = self.rubbers[-1].games
+ if len(games[(Direction.North, Direction.South)]) > 0:
+ if len(games[(Direction.East, Direction.West)]) > 0:
+ self.board['vuln'] = Vulnerable.All
+ else:
+ self.board['vuln'] = Vulnerable.NorthSouth
+ else:
+ if len(games[(Direction.East, Direction.West)]) > 0:
+ self.board['vuln'] = Vulnerable.EastWest
+ else:
+ self.board['vuln'] = Vulnerable.None
+
self.auction = Auction(self.board['dealer']) # Start auction.
self.play = None
self.visibleHands.clear()
@@ -246,7 +268,7 @@
# If bidding is passed out, game is complete.
if not self.inProgress() and self.board['deal']:
- self.results.append(DuplicateResult(self.board, contract=None))
+ self._addResult(self.board, contract=None)
self.notify('makeCall', call=call, position=position)
@@ -318,8 +340,7 @@
# If play is complete, game is complete.
if not self.inProgress() and self.board['deal']:
tricksMade, _ = self.play.wonTrickCount()
- result = DuplicateResult(self.board, self.contract, tricksMade)
- self.results.append(result)
+ self._addResult(self.board, self.contract, tricksMade)
self.notify('playCard', card=card, position=position)
@@ -329,9 +350,22 @@
hand = self.board['deal'].get(position)
if hand and position not in self.visibleHands:
self.revealHand(hand, position)
-
+ def _addResult(self, board, contract=None, tricksMade=None):
+ if self.options.get('RubberScoring'):
+ result = RubberResult(board, contract, tricksMade)
+ if len(self.rubbers) > 0 and self.rubbers[-1].winner is None:
+ rubber = self.rubbers[-1]
+ else: # Instantiate new rubber.
+ rubber = Rubber()
+ self.rubbers.append(rubber)
+ rubber.append(result)
+ else:
+ result = DuplicateResult(board, contract, tricksMade)
+ self.results.append(result)
+
+
def revealHand(self, hand, position):
"""Reveal hand to all observers.
Modified: trunk/pybridge/pybridge/games/bridge/result.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/result.py 2007-07-27 19:05:07 UTC (rev 498)
+++ trunk/pybridge/pybridge/games/bridge/result.py 2007-08-03 18:42:14 UTC (rev 499)
@@ -24,10 +24,10 @@
_getScore = NotImplemented # Expected to be implemented by subclasses.
- __vulnMapping = {Vulnerable.None: (),
- Vulnerable.NorthSouth: (Direction.North, Direction.South),
- Vulnerable.EastWest: (Direction.East, Direction.West),
- Vulnerable.All: tuple(Direction)}
+ __vulnMap = {Vulnerable.None: (),
+ Vulnerable.NorthSouth: (Direction.North, Direction.South),
+ Vulnerable.EastWest: (Direction.East, Direction.West),
+ Vulnerable.All: tuple(Direction)}
def __init__(self, board, contract, tricksMade=None):
@@ -42,7 +42,7 @@
if self.contract:
vuln = self.board.get('vuln', Vulnerable.None)
- self.isVulnerable = self.contract.declarer in self.__vulnMapping[vuln]
+ self.isVulnerable = self.contract.declarer in self.__vulnMap[vuln]
self.score = self._getScore()
@@ -218,3 +218,55 @@
below += value
return above, below
+
+
+
+class Rubber(list):
+ """A rubber set, in which pairs compete to make two consecutive games.
+
+ A game is made by accumulation of 100+ points from below-the-line scores
+ without interruption from an opponent's game.
+ """
+
+ games = property(lambda self: self._getGames())
+ winner = property(lambda self: self._getWinner())
+
+
+ def _getGames(self):
+ """Returns, for each pair, a list of completed 'games' won by the pair
+ in this rubber.
+
+ A game is represented as the list of consecutive results in this rubber,
+ with below-the-line scores that count towards the game.
+ """
+ gamesNS, gamesEW = [], []
+
+ game = []
+ belowNS, belowEW = 0, 0 # Cumulative totals for results.
+ for result in self:
+ game.append(result)
+
+ if result.contract.declarer in (Direction.North, Direction.South):
+ belowNS += result.score[1]
+ if belowNS >= 100:
+ gamesNS.append(game)
+ else:
+ belowEW += result.score[1]
+ if belowEW >= 100:
+ gamesEW.append(game)
+
+ # If either accumulated total exceeds 100, proceed to next game.
+ if belowNS >= 100 or belowEW >= 100:
+ game = []
+ belowNS, belowEW = 0, 0
+
+ return {(Direction.North, Direction.South): gamesNS,
+ (Direction.East, Direction.West): gamesEW}
+
+
+ def _getWinner(self):
+ """The rubber is won by the pair which have completed two games."""
+ for pair, games in self.games.items():
+ if len(games) >= 2:
+ return pair
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-07-27 19:05:05
|
Revision: 498
http://pybridge.svn.sourceforge.net/pybridge/?rev=498&view=rev
Author: umgangee
Date: 2007-07-27 12:05:07 -0700 (Fri, 27 Jul 2007)
Log Message:
-----------
Since determination of vulnerability in rubber bridge requires knowledge of previous results, pass list of results to board.next(), instead of just the most recent result.
Modified Paths:
--------------
trunk/pybridge/pybridge/games/bridge/board.py
trunk/pybridge/pybridge/games/bridge/game.py
Modified: trunk/pybridge/pybridge/games/bridge/board.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/board.py 2007-07-27 19:04:18 UTC (rev 497)
+++ trunk/pybridge/pybridge/games/bridge/board.py 2007-07-27 19:05:07 UTC (rev 498)
@@ -45,12 +45,7 @@
@type vuln: Vulnerable
"""
- __directionToVuln = {Direction.North: Vulnerable.NorthSouth,
- Direction.East: Vulnerable.EastWest,
- Direction.South: Vulnerable.NorthSouth,
- Direction.West: Vulnerable.EastWest}
-
@classmethod
def first(cls, deal=None):
"""Build an initial board.
@@ -69,17 +64,20 @@
return board
- def next(self, result, deal=None):
- """Given the result for this board, builds the next board.
+ def next(self, results, deal=None):
+ """Given the results for this board (and all previous boards),
+ builds the next board.
The dealer and vulnerability of the next board are calculated
- from the result provided.
+ from the results provided.
- @param result: the result of the this board.
+ @param result: a list of all previous results, ordered from earliest
+ to most recent, ie. this board's result is last in list.
@param deal: if provided, the deal to be wrapped by next board.
Otherwise, a randomly-generated deal is wrapped.
"""
- assert result.board == self
+ boardresult = results[-1]
+ assert boardresult.board == self
board = Board(self.copy()) # copy() returns a dict.
board['deal'] = deal or Deal.fromRandom()
@@ -89,24 +87,33 @@
# Dealer rotates clockwise.
board['dealer'] = Direction[(board['dealer'].index + 1) % 4]
- if isinstance(result, DuplicateResult):
+ if isinstance(boardresult, DuplicateResult):
# See http://www.d21acbl.com/References/Laws/node5.html#law2
i = (board['num'] - 1) % 16
# Map from duplicate board index range 1..16 to vulnerability.
board['vuln'] = Vulnerable[(i%4 + i/4)%4]
- elif isinstance(result, RubberResult):
- # Determine vulnerability of board from result of previous board.
- above, below = result.score
- if below >= 100: # Game contract successful.
- pair = __directionToVuln[result.contract.declarer]
- # Vulnerability transitions.
- if board['vuln'] == Vulnerable.None:
- board['vuln'] = pair
- elif board['vuln'] in (pair, Vulnerable.All): # Rubber won.
- board['vuln'] = Vulnerable.None
- else: # Pair not vulnerable, other pair are vulnerable.
- board['vuln'] = Vulnerable.All
+ elif isinstance(boardresult, RubberResult):
+ belowNS, belowEW = 0, 0 # Running totals of below-the-line scores.
+ board['vuln'] = Vulnerable.None
+ # Only consider rounds which score below-the-line.
+ for result in (r for r in results if r.score.below > 0):
+ if result.contract.declarer in (Direction.North, Direction.South):
+ belowNS += result.score.below
+ pair = Vulnerable.NorthSouth
+ else:
+ belowEW += result.score.below
+ pair = Vulnerable.EastWest
+ # If either score exceeds 100, pair has made game.
+ if belowNS >= 100 or belowEW >= 100:
+ belowNS, belowEW = 0, 0 # Reset totals for next game.
+ # Vulnerability transitions.
+ if board['vuln'] == Vulnerable.None:
+ board['vuln'] = pair
+ elif board['vuln'] in (pair, Vulnerable.All):
+ board['vuln'] = Vulnerable.None
+ else: # Pair was not vulnerable, but other pair was.
+ board['vuln'] = Vulnerable.All
return board
Modified: trunk/pybridge/pybridge/games/bridge/game.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/game.py 2007-07-27 19:04:18 UTC (rev 497)
+++ trunk/pybridge/pybridge/games/bridge/game.py 2007-07-27 19:05:07 UTC (rev 498)
@@ -82,10 +82,8 @@
if board: # Use specified board.
self.board = board
- elif self.board: # Advance to next deal.
- tricksMade, _ = self.play.wonTrickCount()
- result = DuplicateResult(self.board, self.contract, tricksMade)
- self.board = self.board.next(result)
+ elif self.board: # Advance to next round.
+ self.board = self.board.next(self.results)
else: # Create a board.
self.board = Board.first()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-07-27 19:04:16
|
Revision: 497
http://pybridge.svn.sourceforge.net/pybridge/?rev=497&view=rev
Author: umgangee
Date: 2007-07-27 12:04:18 -0700 (Fri, 27 Jul 2007)
Log Message:
-----------
Need to check whether a contract exists, just in case auction is passed out.
Modified Paths:
--------------
trunk/pybridge/pybridge/games/bridge/result.py
Modified: trunk/pybridge/pybridge/games/bridge/result.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/result.py 2007-07-26 19:03:38 UTC (rev 496)
+++ trunk/pybridge/pybridge/games/bridge/result.py 2007-07-27 19:04:18 UTC (rev 497)
@@ -40,8 +40,9 @@
self.contract = contract
self.tricksMade = tricksMade
- vuln = self.board.get('vuln', Vulnerable.None)
- self.isVulnerable = self.contract.declarer in self.__vulnMapping[vuln]
+ if self.contract:
+ vuln = self.board.get('vuln', Vulnerable.None)
+ self.isVulnerable = self.contract.declarer in self.__vulnMapping[vuln]
self.score = self._getScore()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-07-26 19:35:35
|
Revision: 496
http://pybridge.svn.sourceforge.net/pybridge/?rev=496&view=rev
Author: umgangee
Date: 2007-07-26 12:03:38 -0700 (Thu, 26 Jul 2007)
Log Message:
-----------
Incorporate support for Result objects in board, make appropriate tweaks to dependencies.
Modified Paths:
--------------
trunk/pybridge/pybridge/games/bridge/board.py
trunk/pybridge/pybridge/games/bridge/game.py
trunk/pybridge/pybridge/games/bridge/result.py
trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py
Modified: trunk/pybridge/pybridge/games/bridge/board.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/board.py 2007-07-25 21:04:25 UTC (rev 495)
+++ trunk/pybridge/pybridge/games/bridge/board.py 2007-07-26 19:03:38 UTC (rev 496)
@@ -18,7 +18,9 @@
import random
import time
+
from deal import Deal
+from result import DuplicateResult, RubberResult
from symbols import Direction, Vulnerable
@@ -43,32 +45,68 @@
@type vuln: Vulnerable
"""
+ __directionToVuln = {Direction.North: Vulnerable.NorthSouth,
+ Direction.East: Vulnerable.EastWest,
+ Direction.South: Vulnerable.NorthSouth,
+ Direction.West: Vulnerable.EastWest}
- def nextDeal(self, result=None):
- """Generates and stores a random deal for the board.
+
+ @classmethod
+ def first(cls, deal=None):
+ """Build an initial board.
- If result of a previous game is provided, the dealer and vulnerability
- are rotated according to the rules of bridge.
+ @deal: if provided, the deal to be wrapped by board.
+ Otherwise, a randomly-generated deal is wrapped.
+ """
+ board = cls()
+ board['deal'] = deal or Deal.fromRandom()
+ board['num'] = 1
+ board['time'] = tuple(time.localtime())
+
+ board['dealer'] = Direction.North # Arbitary.
+ board['vuln'] = Vulnerable.None
+
+ return board
+
+
+ def next(self, result, deal=None):
+ """Given the result for this board, builds the next board.
- @param result:
- @type result:
+ The dealer and vulnerability of the next board are calculated
+ from the result provided.
+
+ @param result: the result of the this board.
+ @param deal: if provided, the deal to be wrapped by next board.
+ Otherwise, a randomly-generated deal is wrapped.
"""
- self['deal'] = Deal.fromRandom()
+ assert result.board == self
- self['num'] = self.get('num', 0) + 1
- self['time'] = tuple(time.localtime())
+ board = Board(self.copy()) # copy() returns a dict.
+ board['deal'] = deal or Deal.fromRandom()
+ board['num'] = board.get('num', 0) + 1
+ board['time'] = tuple(time.localtime())
- if self.get('dealer'): # Rotate dealer.
- self['dealer'] = Direction[(self['dealer'].index + 1) % 4]
- else: # Select any player as the dealer.
- self['dealer'] = random.choice(Direction)
+ # Dealer rotates clockwise.
+ board['dealer'] = Direction[(board['dealer'].index + 1) % 4]
- if result:
- # TODO: proper GameResult object.
- # TODO: consider vulnerability rules for duplicate, rubber bridge.
- #if result.bidding.isPassedOut():
- # self['vuln'] = result.board['vuln']
- #elif result.getScore() >= 0
- self['vuln'] = Vulnerable[(result.board['vuln'].index + 1) % 4]
- else:
- self['vuln'] = Vulnerable.None # The default value.
+ if isinstance(result, DuplicateResult):
+ # See http://www.d21acbl.com/References/Laws/node5.html#law2
+ i = (board['num'] - 1) % 16
+ # Map from duplicate board index range 1..16 to vulnerability.
+ board['vuln'] = Vulnerable[(i%4 + i/4)%4]
+
+ elif isinstance(result, RubberResult):
+ # Determine vulnerability of board from result of previous board.
+ above, below = result.score
+ if below >= 100: # Game contract successful.
+ pair = __directionToVuln[result.contract.declarer]
+ # Vulnerability transitions.
+ if board['vuln'] == Vulnerable.None:
+ board['vuln'] = pair
+ elif board['vuln'] in (pair, Vulnerable.All): # Rubber won.
+ board['vuln'] = Vulnerable.None
+ else: # Pair not vulnerable, other pair are vulnerable.
+ board['vuln'] = Vulnerable.All
+
+ return board
+
Modified: trunk/pybridge/pybridge/games/bridge/game.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/game.py 2007-07-25 21:04:25 UTC (rev 495)
+++ trunk/pybridge/pybridge/games/bridge/game.py 2007-07-26 19:03:38 UTC (rev 496)
@@ -63,12 +63,14 @@
self.auction = None
self.play = None
- self.boardQueue = [] # Boards for successive games.
+ self.boardQueue = [] # Boards for successive rounds.
+ self.results = [] # Results of previous rounds.
self.visibleHands = {} # A subset of deal, containing revealed hands.
self.players = {} # One-to-one mapping from BridgePlayer to Direction.
contract = property(lambda self: self.auction and self.auction.contract or None)
trumpSuit = property(lambda self: self.play and self.play.trumpSuit or None)
+ result = property(lambda self: not self.inProgress() and self.results[-1])
# Implementation of ICardGame.
@@ -81,10 +83,12 @@
if board: # Use specified board.
self.board = board
elif self.board: # Advance to next deal.
- self.board.nextDeal(result=self) # TODO: proper GameResult object.
+ tricksMade, _ = self.play.wonTrickCount()
+ result = DuplicateResult(self.board, self.contract, tricksMade)
+ self.board = self.board.next(result)
else: # Create a board.
- self.board = Board()
- self.board.nextDeal()
+ self.board = Board.first()
+
self.auction = Auction(self.board['dealer']) # Start auction.
self.play = None
self.visibleHands.clear()
@@ -242,10 +246,14 @@
trumpSuit = self.__trumpMap[self.contract.bid.strain]
self.play = TrickPlay(declarer, trumpSuit)
+ # If bidding is passed out, game is complete.
+ if not self.inProgress() and self.board['deal']:
+ self.results.append(DuplicateResult(self.board, contract=None))
+
self.notify('makeCall', call=call, position=position)
- # If bidding is passed out, reveal all hands.
if not self.inProgress() and self.board['deal']:
+ # Reveal all unrevealed hands.
for position in Direction:
hand = self.board['deal'].get(position)
if hand and position not in self.visibleHands:
@@ -302,7 +310,6 @@
raise GameError, "Card cannot be played from hand"
self.play.playCard(card, playfrom)
- self.notify('playCard', card=card, position=position)
# Dummy's hand is revealed when the first card of first trick is played.
if len(self.play[0]) == 1:
@@ -310,12 +317,21 @@
if dummyhand: # Reveal hand only if known.
self.revealHand(dummyhand, self.play.dummy)
- # If play is complete, reveal all hands.
+ # If play is complete, game is complete.
if not self.inProgress() and self.board['deal']:
+ tricksMade, _ = self.play.wonTrickCount()
+ result = DuplicateResult(self.board, self.contract, tricksMade)
+ self.results.append(result)
+
+ self.notify('playCard', card=card, position=position)
+
+ if not self.inProgress() and self.board['deal']:
+ # Reveal all unrevealed hands.
for position in Direction:
hand = self.board['deal'].get(position)
if hand and position not in self.visibleHands:
self.revealHand(hand, position)
+
def revealHand(self, hand, position):
@@ -363,24 +379,8 @@
raise GameError, "No game in progress"
- def getScore(self):
- """Returns the integer score value for declarer/dummy if:
- - auction has been passed out, with no bids made.
- - trick play is complete.
- """
- if self.inProgress() or self.auction is None:
- raise GameError, "Game not complete"
- if self.auction.isPassedOut():
- return 0 # A passed out deal does not score.
- tricksMade, _ = self.play.wonTrickCount()
- result = DuplicateResult(self.contract, self.board['vuln'], tricksMade)
- return result.score
-
-
-
-
class BridgePlayer(pb.Referenceable):
"""Actor representing a player's view of a BridgeGame object."""
Modified: trunk/pybridge/pybridge/games/bridge/result.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/result.py 2007-07-25 21:04:25 UTC (rev 495)
+++ trunk/pybridge/pybridge/games/bridge/result.py 2007-07-26 19:03:38 UTC (rev 496)
@@ -30,14 +30,17 @@
Vulnerable.All: tuple(Direction)}
- def __init__(self, contract, vuln, tricksMade=None):
+ def __init__(self, board, contract, tricksMade=None):
"""
+ @type board: Board
@type contract: Contract
- @type vuln: Vulnerable
@type tricksMade: int or None
"""
+ self.board = board
self.contract = contract
self.tricksMade = tricksMade
+
+ vuln = self.board.get('vuln', Vulnerable.None)
self.isVulnerable = self.contract.declarer in self.__vulnMapping[vuln]
self.score = self._getScore()
Modified: trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py 2007-07-25 21:04:25 UTC (rev 495)
+++ trunk/pybridge/pybridge/games/bridge/ui/window_bridgetable.py 2007-07-26 19:03:38 UTC (rev 496)
@@ -103,7 +103,7 @@
def add_score(self, game):
declarerWon, defenceWon = game.play.wonTrickCount()
- score = game.getScore()
+ score = game.result.score
textContract = render_contract(game.contract)
textMade = str(declarerWon)
@@ -339,13 +339,13 @@
if self.table.game.contract:
self.scoreview.add_score(self.table.game)
- declarerWon, defenceWon = self.table.game.play.wonTrickCount()
- required = self.table.game.contract.bid.level.index + 7
- offset = declarerWon - required
- score = self.table.game.getScore()
+ tricksMade = self.table.game.result.tricksMade
+ tricksRequired = self.table.game.contract.bid.level.index + 7
+ offset = tricksMade - tricksRequired
+ score = self.table.game.result.score
fields = {'contract': render_contract(self.table.game.contract),
- 'offset': abs(offset) }
+ 'offset': abs(offset)}
if offset > 0:
if offset == 1:
resultText = _('Contract %(contract)s made by 1 trick.') % fields
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-07-25 21:04:31
|
Revision: 495
http://pybridge.svn.sourceforge.net/pybridge/?rev=495&view=rev
Author: umgangee
Date: 2007-07-25 14:04:25 -0700 (Wed, 25 Jul 2007)
Log Message:
-----------
Split scoring down into component parts, to provide support for both duplicate and rubber scoring schemes. Fix a couple of bugs in scoring code as well!
Modified Paths:
--------------
trunk/pybridge/pybridge/games/bridge/game.py
Added Paths:
-----------
trunk/pybridge/pybridge/games/bridge/result.py
Removed Paths:
-------------
trunk/pybridge/pybridge/games/bridge/scoring.py
Modified: trunk/pybridge/pybridge/games/bridge/game.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/game.py 2007-07-24 19:30:16 UTC (rev 494)
+++ trunk/pybridge/pybridge/games/bridge/game.py 2007-07-25 21:04:25 UTC (rev 495)
@@ -13,7 +13,7 @@
#
# 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.
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from twisted.spread import pb
@@ -26,7 +26,7 @@
from auction import Auction
from board import Board
from play import Trick, TrickPlay
-from scoring import scoreDuplicate
+from result import DuplicateResult, RubberResult
from call import Bid, Pass, Double, Redouble
from card import Card
@@ -47,13 +47,13 @@
implements(ICardGame, ISubject)
- # Valid positions.
+ # Valid positions (for Table).
positions = Direction
- # Mapping from Strain symbols (in bidding) to Suit symbols (in play).
- trumpMap = {Strain.Club: Suit.Club, Strain.Diamond: Suit.Diamond,
- Strain.Heart: Suit.Heart, Strain.Spade: Suit.Spade,
- Strain.NoTrump: None}
+ # Mapping from Strain symbols (in auction) to Suit symbols (in play).
+ __trumpMap = {Strain.Club: Suit.Club, Strain.Diamond: Suit.Diamond,
+ Strain.Heart: Suit.Heart, Strain.Spade: Suit.Spade,
+ Strain.NoTrump: None}
def __init__(self):
@@ -239,7 +239,7 @@
if self.auction.isComplete() and not self.auction.isPassedOut():
declarer = self.auction.contract.declarer
- trumpSuit = self.trumpMap[self.contract.bid.strain]
+ trumpSuit = self.__trumpMap[self.contract.bid.strain]
self.play = TrickPlay(declarer, trumpSuit)
self.notify('makeCall', call=call, position=position)
@@ -374,23 +374,13 @@
if self.auction.isPassedOut():
return 0 # A passed out deal does not score.
- declarer = self.contract.declarer
- dummy = Direction[(declarer.index + 2) % 4]
+ tricksMade, _ = self.play.wonTrickCount()
+ result = DuplicateResult(self.contract, self.board['vuln'], tricksMade)
+ return result.score
- if declarer in (Direction.North, Direction.South):
- vulnerable = (self.board['vuln'] in (Vulnerable.NorthSouth, Vulnerable.All))
- else: # East or West
- vulnerable = (self.board['vuln'] in (Vulnerable.EastWest, Vulnerable.All))
- declarerWon, defenceWon = self.play.wonTrickCount()
- result = {'contract': self.contract, 'tricksMade': declarerWon,
- 'vulnerable': vulnerable}
- return scoreDuplicate(result)
-
-
-
class BridgePlayer(pb.Referenceable):
"""Actor representing a player's view of a BridgeGame object."""
Copied: trunk/pybridge/pybridge/games/bridge/result.py (from rev 492, trunk/pybridge/pybridge/games/bridge/scoring.py)
===================================================================
--- trunk/pybridge/pybridge/games/bridge/result.py (rev 0)
+++ trunk/pybridge/pybridge/games/bridge/result.py 2007-07-25 21:04:25 UTC (rev 495)
@@ -0,0 +1,216 @@
+# 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 symbols import Direction, Strain, Vulnerable
+
+
+class GameResult(object):
+ """Represents the result of a completed round of bridge."""
+
+ _getScore = NotImplemented # Expected to be implemented by subclasses.
+
+ __vulnMapping = {Vulnerable.None: (),
+ Vulnerable.NorthSouth: (Direction.North, Direction.South),
+ Vulnerable.EastWest: (Direction.East, Direction.West),
+ Vulnerable.All: tuple(Direction)}
+
+
+ def __init__(self, contract, vuln, tricksMade=None):
+ """
+ @type contract: Contract
+ @type vuln: Vulnerable
+ @type tricksMade: int or None
+ """
+ self.contract = contract
+ self.tricksMade = tricksMade
+ self.isVulnerable = self.contract.declarer in self.__vulnMapping[vuln]
+
+ self.score = self._getScore()
+
+
+ def _getScoreComponents(self):
+ """Compute the component values which contribute to the score.
+ Note that particular scoring schemes may ignore some of the components.
+
+ Scoring values: http://en.wikipedia.org/wiki/Bridge_scoring
+
+ @return: a dict of component values.
+ @rtype: dict
+ """
+ components = {}
+
+ isDoubled = bool(self.contract.doubleBy)
+ isRedoubled = bool(self.contract.redoubleBy)
+ isVulnerable = self.isVulnerable
+ contractLevel = self.contract.bid.level.index + 1
+ tricksMade = self.tricksMade
+ tricksRequired = contractLevel + 6
+ trumpSuit = self.contract.bid.strain
+
+ if tricksMade >= tricksRequired: # Contract successful.
+
+ #### Contract tricks (bid and made) ####
+ if trumpSuit in (Strain.Club, Strain.Diamond):
+ # Clubs and Diamonds score 20 for each odd trick.
+ components['odd'] = contractLevel * 20
+ else: # Hearts, Spades and NT score 30 for each odd trick.
+ components['odd'] = contractLevel * 30
+ if trumpSuit == Strain.NoTrump:
+ components['odd'] += 10 # For NT, add a 10 point bonus.
+ if isRedoubled:
+ components['odd'] *= 4 # Double the doubled score.
+ elif isDoubled:
+ components['odd'] *= 2 # Double score.
+
+
+ #### Overtricks ####
+ overTricks = tricksMade - tricksRequired
+
+ if isRedoubled:
+ # 400 for each overtrick if vulnerable, 200 if not.
+ if isVulnerable:
+ components['over'] = overTricks * 400
+ else:
+ components['over'] = overTricks * 200
+
+ elif isDoubled:
+ # 200 for each overtrick if vulnerable, 100 if not.
+ if isVulnerable:
+ components['over'] = overTricks * 200
+ else:
+ components['over'] = overTricks * 100
+
+ else: # Undoubled contract.
+ if trumpSuit in (Strain.Club, Strain.Diamond):
+ # Clubs and Diamonds score 20 for each overtrick.
+ components['over'] = overTricks * 20
+ else:
+ # Hearts, Spades and NT score 30 for each overtrick.
+ components['over'] = overTricks * 30
+
+
+ #### Premium bonuses ####
+
+ if tricksRequired == 13:
+ # 1500 for grand slam if vulnerable, 1000 if not.
+ if isVulnerable:
+ components['slambonus'] = 1500
+ else:
+ components['slambonus'] = 1000
+
+ elif tricksRequired == 12:
+ # 750 for small slam if vulnerable, 500 if not.
+ if isVulnerable:
+ components['slambonus'] = 750
+ else:
+ components['slambonus'] = 500
+
+ elif components['odd'] >= 100: # Game contract (non-slam).
+ # 500 for game if vulnerable, 300 if not.
+ if isVulnerable:
+ components['gamebonus'] = 500
+ else:
+ components['gamebonus'] = 300
+
+ else: # Non-game contract.
+ components['partscore'] = 50
+
+
+ #### Insult bonus ####
+ if isRedoubled:
+ components['insultbonus'] = 100
+ elif isDoubled:
+ components['insultbonus'] = 50
+
+
+ else: # Contract not successful.
+
+ underTricks = tricksRequired - tricksMade
+
+ if isRedoubled:
+ if isVulnerable:
+ # -400 for first, then -600 each.
+ components['under'] = -400 + (underTricks - 1) * -600
+ else:
+ # -200 for first, -400 for second and third, then -600 each.
+ components['under'] = -200 + (underTricks - 1) * -400
+ if underTricks > 3:
+ components['under'] += (underTricks - 3) * -200
+
+ elif isDoubled:
+ if isVulnerable:
+ # -200 for first, then -300 each.
+ components['under'] = -200 + (underTricks - 1) * -300
+ else:
+ # -100 for first, -200 for second and third, then -300 each.
+ components['under'] = -100 + (underTricks - 1) * -200
+ if underTricks > 3:
+ components['under'] += (underTricks - 3) * -100
+ else:
+ if isVulnerable:
+ # -100 each.
+ components['under'] = underTricks * -100
+ else:
+ # -50 each.
+ components['under'] = underTricks * -50
+
+ return components
+
+
+
+
+class DuplicateResult(GameResult):
+ """Represents the result of a completed round of duplicate bridge."""
+
+
+ def _getScore(self):
+ """Duplicate bridge scoring scheme.
+
+ @return: score value: positive for declarer, negative for defenders.
+ """
+ score = 0
+ if self.contract and self.tricksMade:
+ for key, value in self._getScoreComponents().items():
+ if key in ('odd', 'over', 'under', 'slambonus', 'gamebonus',
+ 'partscore', 'insultbonus'):
+ score += value
+ return score
+
+
+
+
+class RubberResult(GameResult):
+ """Represents the result of a completed round of rubber bridge."""
+
+
+ def _getScore(self):
+ """Rubber bridge scoring scheme.
+
+ @return: 2-tuple of numeric scores (above the line, below the line):
+ positive for declarer, negative for defenders.
+ """
+ above, below = 0, 0
+ if self.contract and self.tricksMade:
+ for key, value in self._getScoreComponents().items():
+ # Note: gamebonus/partscore are not assigned in rubber bridge.
+ if key in ('over', 'under', 'slambonus', 'insultbonus'):
+ above += value
+ elif key == 'odd':
+ below += value
+ return above, below
+
Deleted: trunk/pybridge/pybridge/games/bridge/scoring.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/scoring.py 2007-07-24 19:30:16 UTC (rev 494)
+++ trunk/pybridge/pybridge/games/bridge/scoring.py 2007-07-25 21:04:25 UTC (rev 495)
@@ -1,145 +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 symbols import Strain
-
-
-# There are undoubtedly many minor variations of the score values.
-# In the future, score values may be stored in separate XML format files.
-
-
-def scoreDuplicate(result):
- """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 = bool(result['contract'].doubleBy)
- isRedoubled = bool(result['contract'].redoubleBy)
- isVulnerable = result['vulnerable']
- contractLevel = result['contract'].bid.level.index + 1
- tricksMade = result['tricksMade']
- tricksRequired = result['contract'].bid.level.index + 7
- trumpSuit = result['contract'].bid.strain
-
- if tricksMade >= tricksRequired:
- # Contract fulfilled.
-
- # Calculate scores for tricks bid and made.
- if trumpSuit in (Strain.Club, Strain.Diamond):
- # Clubs and Diamonds score 20 for each odd trick.
- score += contractLevel * 20
- else:
- # Hearts, Spades and NT score 30 for each odd trick.
- score += contractLevel * 30
- if trumpSuit is Strain.NoTrump:
- score += 10 # For NT, add a 10 point bonus.
-
- # Calculate scores for doubles.
- if isDoubled:
- score *= 2 # Multiply score by 2 for each isDoubled odd trick.
- elif isRedoubled:
- score *= 4 # Multiply score by 4 for each isRedoubled odd trick.
-
- # Calculate premium scores.
- if score >= 100:
- if isVulnerable:
- score += 500 # Game, vulnerable.
- else:
- # Game, not vulnerable.
- score += 300 # Game, not vulnerable.
- if tricksRequired == 13:
- if isVulnerable:
- score += 1500 # Grand slam, vulnerable.
- else:
- score += 1000 # Grand slam, not vulnerable.
- elif tricksRequired == 12:
- if isVulnerable:
- score += 750 # Small slam, vulnerable.
- else:
- score += 500 # Small slam, not vulnerable.
-
- else:
- score += 50 # Any part score.
-
- # Calculate "for the insult" bonuses.
- if isDoubled:
- score += 50
- elif isRedoubled:
- score += 100
-
- # Calculate scores for overtricks.
- overTricks = tricksMade - tricksRequired
- if isDoubled:
- if isVulnerable:
- # Score 200 for each doubled and vulnerable overtrick.
- score += overTricks * 200
- else:
- # Score 100 for each doubled and not vulnerable overtrick.
- score += overTricks * 100
- elif isRedoubled:
- if isVulnerable:
- # Score 400 for each redoubled and vulnerable overtrick.
- score += overTricks * 400
- else:
- score += overTricks * 200
- else:
- if trumpSuit in (Strain.Club, Strain.Diamond):
- # Clubs and Diamonds score 20 for each undoubled overtrick.
- score += overTricks * 20
- else:
- # Hearts, Spades and NT score 30 for each undoubled overtrick.
- score += overTricks * 30
-
- else:
- # Contract not fulfilled.
-
- underTricks = tricksRequired - tricksMade
- if isDoubled:
- if isVulnerable:
- # Score 200 for the first doubled and vulnerable undertrick.
- # Score 300 for all other undertricks.
- score -= 200 + (underTricks - 1) * 300
- else:
- # Score 100 for the first doubled and non-vulnerable undertrick.
- # Score 200 for all other undertricks.
- # Score 100 extra for third and greater undertricks.
- score -= 100 + (underTricks - 1) * 200
- if underTricks > 3:
- score -= (underTricks - 3) * 100
- elif isRedoubled:
- if isVulnerable:
- score -= 400 + (underTricks - 1) * 600
- else:
- score -= 200 + (underTricks - 1) * 400
- if underTricks > 3:
- score -= (underTricks - 3) * 200
- else:
- if isVulnerable:
- score -= 100 + (underTricks - 1) * 100
- else:
- score -= 50 + (underTricks - 1) * 50
-
- return score
-
-
-def scoreRubber(result):
- pass # TODO: implement.
-
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...> - 2007-07-24 17:22:20
|
Revision: 493
http://svn.sourceforge.net/pybridge/?rev=493&view=rev
Author: umgangee
Date: 2007-07-24 10:22:23 -0700 (Tue, 24 Jul 2007)
Log Message:
-----------
Open table window when it is created.
Modified Paths:
--------------
trunk/pybridge/pybridge/ui/dialog_newtable.py
Modified: trunk/pybridge/pybridge/ui/dialog_newtable.py
===================================================================
--- trunk/pybridge/pybridge/ui/dialog_newtable.py 2007-07-23 20:07:54 UTC (rev 492)
+++ trunk/pybridge/pybridge/ui/dialog_newtable.py 2007-07-24 17:22:23 UTC (rev 493)
@@ -23,7 +23,10 @@
from pybridge.games import SUPPORTED_GAMES
from manager import wm
+# TODO: import all Window*Table classes automatically.
+from pybridge.games.bridge.ui.window_bridgetable import WindowBridgeTable
+
class DialogNewtable(GladeWrapper):
glade_name = 'dialog_newtable'
@@ -45,6 +48,9 @@
def createSuccess(self, table):
wm.close(self)
+ # TODO: select correct table window class.
+ window = wm.open(WindowBridgeTable, id=table.id)
+ window.setTable(table)
def createFailure(self, reason):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-07-23 20:09:00
|
Revision: 492
http://svn.sourceforge.net/pybridge/?rev=492&view=rev
Author: umgangee
Date: 2007-07-23 13:07:54 -0700 (Mon, 23 Jul 2007)
Log Message:
-----------
Open table windows in response to successful joinTable() requests, instead of waiting for event_tableJoined(), so internal errors are reported to sys.excepthook instead of the errback attached to joinTable() deferred by caller.
Modified Paths:
--------------
trunk/pybridge/pybridge/ui/window_gametable.py
trunk/pybridge/pybridge/ui/window_main.py
Modified: trunk/pybridge/pybridge/ui/window_gametable.py
===================================================================
--- trunk/pybridge/pybridge/ui/window_gametable.py 2007-07-23 11:55:00 UTC (rev 491)
+++ trunk/pybridge/pybridge/ui/window_gametable.py 2007-07-23 20:07:54 UTC (rev 492)
@@ -50,7 +50,7 @@
def setUp(self):
- self.children = WindowManager()
+ self.children = WindowManager() # Private to this window.
self.eventHandler = SimpleEventHandler(self)
self.player = None
@@ -192,14 +192,14 @@
dialog.destroy()
if response_id == gtk.RESPONSE_OK:
d = client.leaveTable(self.table.id)
- #d.addErrback(self.errback)
+ d.addCallbacks(lambda _: wm.close(self), self.errback)
dialog.connect('response', dialog_response_cb)
dialog.show()
else:
d = client.leaveTable(self.table.id)
- #d.addErrback(self.errback)
+ d.addCallbacks(lambda _: wm.close(self), self.errback)
def on_fullscreen_clicked(self, widget, *args):
Modified: trunk/pybridge/pybridge/ui/window_main.py
===================================================================
--- trunk/pybridge/pybridge/ui/window_main.py 2007-07-23 11:55:00 UTC (rev 491)
+++ trunk/pybridge/pybridge/ui/window_main.py 2007-07-23 20:07:54 UTC (rev 492)
@@ -28,12 +28,13 @@
from pybridge.network.client import client
from eventhandler import SimpleEventHandler
-from manager import WindowManager, wm
+from manager import wm
from dialog_connection import DialogConnection
from dialog_newtable import DialogNewtable
from dialog_preferences import DialogPreferences
from dialog_userinfo import DialogUserInfo
+from window_gametable import WindowGameTable
# TODO: import all Window*Table classes automatically.
from pybridge.games.bridge.ui.window_bridgetable import WindowBridgeTable
@@ -51,9 +52,6 @@
def setUp(self):
- # Use a private WindowManager for table window instances.
- self.tables = WindowManager()
-
# Set up table model and icon view.
self.tableview.set_text_column(0)
self.tableview.set_pixbuf_column(1)
@@ -110,8 +108,9 @@
def event_loggedOut(self):
- for table in self.tables.values():
- self.tables.close(table)
+ for window in wm.values():
+ if isinstance(window, WindowGameTable):
+ wm.close(window)
self.notebook.set_property('sensitive', False)
self.menu_connect.set_property('visible', True)
@@ -119,7 +118,6 @@
self.menu_newtable.set_property('sensitive', False)
#self.newtable.set_property('sensitive', False)
- print self.tableview.get_model()
self.tableview.get_model().clear()
self.userview.get_model().clear()
@@ -157,15 +155,6 @@
pass # Ignore an unrecognised roster.
- def event_joinTable(self, tableid, table):
- window = self.tables.open(WindowBridgeTable, id=tableid)
- window.setTable(table)
-
-
- def event_leaveTable(self, tableid):
- self.tables.close(self.tables[tableid]) # Close window.
-
-
def event_openTable(self, tableid, info):
"""Adds a table to the table listing."""
# Only display table if it supported by client.
@@ -210,12 +199,18 @@
def on_tableview_item_activated(self, iconview, path, *args):
+
+ 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:
d = client.joinTable(tableid)
- d.addErrback(self.errback)
+ d.addCallbacks(joinedTable, self.errback)
self.jointable.set_property('sensitive', False)
@@ -285,7 +280,8 @@
def on_disconnect_activate(self, widget, *args):
do_disconnect = True
- if len([True for table in self.tables.values() if table.player]) > 0:
+ # TODO: avoid introspection of table windows.
+ if len([True for w in wm.values() if isinstance(w, WindowGameTable) and w.player]) > 0:
dialog = gtk.MessageDialog(parent=self.window,
flags=gtk.DIALOG_MODAL,
type=gtk.MESSAGE_QUESTION)
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:54:57
|
Revision: 491
http://svn.sourceforge.net/pybridge/?rev=491&view=rev
Author: umgangee
Date: 2007-07-23 04:55:00 -0700 (Mon, 23 Jul 2007)
Log Message:
-----------
Separate exception dialog from excepthook, so network errors etc. may be displayed.
Modified Paths:
--------------
trunk/pybridge/pybridge/ui/excepthook.py
Modified: trunk/pybridge/pybridge/ui/excepthook.py
===================================================================
--- trunk/pybridge/pybridge/ui/excepthook.py 2007-07-23 11:28:54 UTC (rev 490)
+++ trunk/pybridge/pybridge/ui/excepthook.py 2007-07-23 11:55:00 UTC (rev 491)
@@ -28,7 +28,7 @@
from StringIO import StringIO
-def excepthook(type, value, tb):
+def exceptdialog(errormessage):
dialog = gtk.MessageDialog(parent=None, flags=gtk.DIALOG_MODAL,
buttons=gtk.BUTTONS_CLOSE, type=gtk.MESSAGE_WARNING)
dialog.set_title(_('Program error'))
@@ -47,9 +47,7 @@
frame.set_border_width(6)
dialog.vbox.add(frame)
textbuffer = textview.get_buffer()
- trace = StringIO()
- traceback.print_exception(type, value, tb, None, trace)
- textbuffer.set_text(trace.getvalue())
+ textbuffer.set_text(errormessage)
textview.set_size_request(320, 240)
dialog.details = frame
@@ -61,3 +59,9 @@
dialog.connect('response', dialog_response_cb)
dialog.run()
+
+def excepthook(type, value, tb):
+ trace = StringIO()
+ traceback.print_exception(type, value, tb, None, trace)
+ exceptdialog(trace.getvalue())
+
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-22 18:02:39
|
Revision: 489
http://svn.sourceforge.net/pybridge/?rev=489&view=rev
Author: umgangee
Date: 2007-07-22 11:02:34 -0700 (Sun, 22 Jul 2007)
Log Message:
-----------
Do not provide server with Referenceable object, as it is unnecessary.
Modified Paths:
--------------
trunk/pybridge/pybridge/network/client.py
Modified: trunk/pybridge/pybridge/network/client.py
===================================================================
--- trunk/pybridge/pybridge/network/client.py 2007-07-22 15:52:02 UTC (rev 488)
+++ trunk/pybridge/pybridge/network/client.py 2007-07-22 18:02:34 UTC (rev 489)
@@ -35,7 +35,7 @@
-class NetworkClient(pb.Referenceable):
+class NetworkClient(object):
"""Provides the glue between the client code and the server."""
implements(ISubject)
@@ -145,7 +145,7 @@
hash = sha.new(password).hexdigest()
creds = credentials.UsernamePassword(username, hash)
- d = self.factory.login(creds, client=self)
+ d = self.factory.login(creds, client=None)
d.addCallback(connectedAsUser)
return d
@@ -208,5 +208,11 @@
return d
+ def getUserInformation(self, username):
+ # TODO: cache user information once retrieved.
+ d = self.avatar.callRemote('getUserInformation', username)
+ return d
+
+
client = NetworkClient()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-07-22 15:52:06
|
Revision: 488
http://svn.sourceforge.net/pybridge/?rev=488&view=rev
Author: umgangee
Date: 2007-07-22 08:52:02 -0700 (Sun, 22 Jul 2007)
Log Message:
-----------
Borrow an email address validator from Django.
Modified Paths:
--------------
trunk/pybridge/pybridge/server/database.py
Modified: trunk/pybridge/pybridge/server/database.py
===================================================================
--- trunk/pybridge/pybridge/server/database.py 2007-07-22 15:49:44 UTC (rev 487)
+++ trunk/pybridge/pybridge/server/database.py 2007-07-22 15:52:02 UTC (rev 488)
@@ -79,6 +79,13 @@
sqlhub.processConnection = connection # Set all SQLObjects to use connection.
+# Email address validator from Django: see django/core/validators.py
+email_re = re.compile(
+ r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
+ r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' # quoted-string
+ r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain
+
+
class UserAccount(SQLObject):
"""A store of user information.
@@ -89,6 +96,7 @@
password = StringCol(length=40, notNone=True) # Store SHA-1 hex hashes.
allowLogin = BoolCol(default=True) # If False, account login is disabled.
email = StringCol(default=None, length=320) # See RFC 2821 section 4.5.3.1.
+ # Don't split name field - see http://people.w3.org/rishida/blog/?p=100
realname = UnicodeCol(default=None, length=40)
profile = UnicodeCol(default=None)
created = DateTimeCol(default=datetime.now)
@@ -109,7 +117,7 @@
def _set_email(self, value):
# This regexp matches virtually all well-formatted email addresses.
- if value and not re.match("^[A-z0-9_.+-]+@([A-z0-9-]+\.)+[A-z]{2,6}$", value):
+ if value and not email_re.search(value):
raise ValueError, "Invalid or ill-formatted email address"
self._SO_set_email(value)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-07-22 15:49:47
|
Revision: 487
http://svn.sourceforge.net/pybridge/?rev=487&view=rev
Author: umgangee
Date: 2007-07-22 08:49:44 -0700 (Sun, 22 Jul 2007)
Log Message:
-----------
Simplify some remote-invokable methods.
Modified Paths:
--------------
trunk/pybridge/pybridge/network/client.py
trunk/pybridge/pybridge/server/server.py
trunk/pybridge/pybridge/server/user.py
Modified: trunk/pybridge/pybridge/network/client.py
===================================================================
--- trunk/pybridge/pybridge/network/client.py 2007-07-20 17:35:23 UTC (rev 486)
+++ trunk/pybridge/pybridge/network/client.py 2007-07-22 15:49:44 UTC (rev 487)
@@ -188,12 +188,11 @@
self.notify('joinTable', tableid=tableid, table=table)
return table
+ params = {}
if host:
- # TODO: why not just joinTable, host=True?
- gamename = gameclass.__name__
- d = self.avatar.callRemote('hostTable', tableid, gamename)
- else:
- d = self.avatar.callRemote('joinTable', tableid)
+ params['gamename'] = gameclass.__name__
+
+ d = self.avatar.callRemote('joinTable', tableid, host, **params)
d.addCallback(success)
return d
Modified: trunk/pybridge/pybridge/server/server.py
===================================================================
--- trunk/pybridge/pybridge/server/server.py 2007-07-20 17:35:23 UTC (rev 486)
+++ trunk/pybridge/pybridge/server/server.py 2007-07-22 15:49:44 UTC (rev 487)
@@ -33,10 +33,9 @@
onlineUsers = LocalUserManager()
-def getServerInfo():
- return {'compatibleVersions': (version, version), # minimum, maximum
- 'supportedGames': 'bridge', # TODO
- 'version': version}
+serverData = {'compatibleClients': (version, version), # minimum, maximum
+ 'supportedGames': SUPPORTED_GAMES.keys(),
+ 'version': version}
def registerUser(username, password):
@@ -54,8 +53,8 @@
log.msg("New user %s registered" % username)
-def changeUserPassword(username, password):
- """Sets the password of user's account.
+def setUserPassword(username, password):
+ """Changes the password of user's account.
@param username: the user identifier.
@param password: the new password for user.
@@ -67,11 +66,12 @@
raise DeniedRequest, "User account does not exist"
-def createTable(tableid, gamename):
+def createTable(tableid, gamename, **tableOptions):
"""Create a new table for the specified game type.
@param tableid: a unique identifier for the table.
- @param gametype: a game identifier.
+ @param gamename: a game class identifier.
+ @param tableOptions: optional parameters for table initialisation.
"""
# TODO: convert gametype string to corresponding class.
@@ -87,5 +87,6 @@
# Provide table instance with a means of closing itself.
table.close = lambda: availableTables.closeTable(table)
availableTables.openTable(table)
+
return table
Modified: trunk/pybridge/pybridge/server/user.py
===================================================================
--- trunk/pybridge/pybridge/server/user.py 2007-07-20 17:35:23 UTC (rev 486)
+++ trunk/pybridge/pybridge/server/user.py 2007-07-22 15:49:44 UTC (rev 487)
@@ -28,7 +28,8 @@
class RegisteredUser(pb.Avatar):
- info = property(lambda self: {}) # TODO: Send profile data?
+ # Static for duration of connection.
+ info = property(lambda self: {'registered': True})
def __init__(self, name):
@@ -56,11 +57,6 @@
# Perspective methods, accessible by client.
- def perspective_getServerInfo(self):
- """Provides a dict of information about the server."""
- return server.getServerInfo()
-
-
def perspective_getRoster(self, name):
"""Provides roster requested by client."""
if name == 'tables':
@@ -71,44 +67,59 @@
raise DeniedRequest, "Unknown roster name \'%s\'" % name
- def perspective_getUserProfile(self, username):
- """Provides profile information for user with specified username."""
- pass
+ def perspective_getServerData(self):
+ """Provides a dict of information about the server."""
+ return server.serverData
+ 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 None:
+ username = self.name
+
+ try:
+ user = db.UserAccount.selectBy(username=username)[0]
+ except IndexError:
+ raise DeniedRequest, "Specified user does not exist"
+
+ return {'realname': user.realname, 'email': user.email,
+ 'profile': user.profile}
+
+
+# def perspective_setProfile(self, **kwargs):
+# """Sets avatar's user account profile information to that specified."""
+# pass
+
+
def perspective_changePassword(self, password):
"""Sets avatar's user account password to that specified."""
if not isinstance(password, str):
raise IllegalRequest, "Invalid parameter for password"
- try:
- server.changeUserPassword(self.name, password)
+ try: # Validate password before it is changed.
+ server.setUserPassword(self.name, password)
except ValueError, err: # Password validation failed.
raise DeniedRequest, err
- def perspective_hostTable(self, tableid, gametype):
- """Creates a new table."""
+ def perspective_joinTable(self, tableid, host=False, **hostParams):
+ """Joins an existing table, or creates and joins a new table."""
if not isinstance(tableid, str):
raise IllegalRequest, "Invalid parameter for table identifier"
- if not isinstance(gametype, str):
- raise IllegalRequest, "Invalid parameter for game type"
-
- table = server.createTable(tableid, gametype)
- # Force client to join table.
- return self.perspective_joinTable(tableid)
+ elif tableid in self.joinedTables:
+ raise DeniedRequest, "Already joined table"
+ if host:
+ table = server.createTable(tableid, **hostParams)
+ else:
+ try:
+ table = server.availableTables[tableid]
+ except KeyError:
+ raise DeniedRequest, "No such table"
- def perspective_joinTable(self, tableid):
- """Joins an existing table."""
- if not isinstance(tableid, str):
- raise IllegalRequest, "Invalid parameter for table identifier"
- elif tableid not in server.availableTables:
- raise DeniedRequest, "No such table"
- elif tableid in self.joinedTables:
- raise DeniedRequest, "Already joined table"
-
- table = server.availableTables[tableid]
self.joinedTables[tableid] = table
return table
@@ -135,3 +146,4 @@
server.registerUser(username, password)
except ValueError, err: # Username/password validation failed.
raise DeniedRequest, err
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <umg...@us...> - 2007-07-20 17:35:27
|
Revision: 486
http://svn.sourceforge.net/pybridge/?rev=486&view=rev
Author: umgangee
Date: 2007-07-20 10:35:23 -0700 (Fri, 20 Jul 2007)
Log Message:
-----------
Implement toString() method.
Modified Paths:
--------------
trunk/pybridge/pybridge/games/bridge/deal.py
Modified: trunk/pybridge/pybridge/games/bridge/deal.py
===================================================================
--- trunk/pybridge/pybridge/games/bridge/deal.py 2007-07-20 14:32:16 UTC (rev 485)
+++ trunk/pybridge/pybridge/games/bridge/deal.py 2007-07-20 17:35:23 UTC (rev 486)
@@ -145,8 +145,8 @@
return long(num)
- __pbnDirection = dict(zip('NESW', Direction))
- __pbnRank = dict(zip('23456789TJQKA', Rank))
+ __pbnDirection = dict(zip('NESW', Direction) + zip(Direction, 'NESW'))
+ __pbnRank = dict(zip('23456789TJQKA', Rank) + zip(Rank, '23456789TJQKA'))
@classmethod
@@ -175,10 +175,25 @@
return cls(deal)
- def toString(self):
+ def toString(self, dealer=Direction.North):
"""Computes the PBN deal string which corresponds to this deal.
+ In PBN 'export format', the hands must be given in clockwise order,
+ starting from the dealer's position.
+
+ @param dealer: if specified, the dealer of this deal.
@return: a PBN deal string.
"""
- raise NotImplementedError
+ order = Direction[dealer.index:] + Direction[:dealer.index]
+ hs = {}
+ for position in order:
+ # Split hand into suits.
+ suits = dict((suit, '') for suit in Suit)
+ for card in sorted(self[position], reverse=True): # High to low.
+ suits[card.suit] += self.__pbnRank[card.rank]
+ hs[position] = '%s.%s.%s.%s' % tuple(suits[s] for s in reversed(Suit))
+
+ return self.__pbnDirection[dealer] + \
+ ':%s %s %s %s' % tuple(hs[position] for position in order)
+
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-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-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.
|