From: <umg...@us...> - 2007-03-27 15:11:41
|
Revision: 368 http://svn.sourceforge.net/pybridge/?rev=368&view=rev Author: umgangee Date: 2007-03-27 08:11:40 -0700 (Tue, 27 Mar 2007) Log Message: ----------- Move game-centric code out of Table classes and into Game classes. Modified Paths: -------------- trunk/pybridge/pybridge/network/localtable.py trunk/pybridge/pybridge/network/remotetable.py trunk/pybridge/pybridge/server/server.py Removed Paths: ------------- trunk/pybridge/pybridge/network/localbridge.py trunk/pybridge/pybridge/network/remotebridge.py Deleted: trunk/pybridge/pybridge/network/localbridge.py =================================================================== --- trunk/pybridge/pybridge/network/localbridge.py 2007-03-27 14:55:26 UTC (rev 367) +++ trunk/pybridge/pybridge/network/localbridge.py 2007-03-27 15:11:40 UTC (rev 368) @@ -1,220 +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 twisted.internet import reactor -from twisted.spread import pb -from zope.interface import implements - -from pybridge.interfaces.bridgetable import IBridgeTable -from pybridge.network.error import DeniedRequest, IllegalRequest -from pybridge.network.localtable import LocalTable, LocalTableViewable - -# Set up reconstruction of objects from clients. -from pybridge.bridge.call import Bid, Pass, Double, Redouble -from pybridge.bridge.card import Card -pb.setUnjellyableForClass(Bid, Bid) -pb.setUnjellyableForClass(Pass, Pass) -pb.setUnjellyableForClass(Double, Double) -pb.setUnjellyableForClass(Redouble, Redouble) -pb.setUnjellyableForClass(Card, Card) - -# Bridge game. -from pybridge.bridge.deck import Deck -from pybridge.bridge.game import Game, GameError -from pybridge.bridge.scoring import scoreDuplicate -from pybridge.bridge.symbols import Player - - -class LocalBridgeTable(LocalTable): - """A bridge table, implementing the IBridgeTable interface. - - """ - - implements(IBridgeTable) # Also ITable, from parent Table. - - - def __init__(self, id): - LocalTable.__init__(self, id) - self.view = LocalBridgeTableViewable(self) # For clients. - - self.dealer = None - self.deck = Deck() - self.game = None - self.players = dict.fromkeys(Player, None) - self.scoring = scoreDuplicate - - self.handsSeen = {} - for player in Player: - self.handsSeen[player] = [] - - self.pendingDeals = [] # Queue of deals for successive games. - - # A time delay between a finished game and starting the next game. - self.config['gameWaitInterval'] = 5 - - - def getState(self): - state = LocalTable.getState(self) - - if self.game: - state['game'] = {} - state['game']['dealer'] = self.dealer.key - state['game']['vulnNS'] = self.game.vulnNS - state['game']['vulnEW'] = self.game.vulnEW - if self.game.bidding: - state['game']['calls'] = self.game.bidding.calls - if self.game.playing: - state['game']['declarer'] = self.game.playing.declarer.key - state['game']['played'] = {} - for player, played in self.game.playing.played.items(): - state['game']['played'][player.key] = played - # Add visible hands. - state['game']['deal'] = {} - for player, hand in self.game.deal.items(): - if self.game.isHandVisible(player, viewer=None): - state['game']['deal'][player.key] = hand - else: - state['game'] = None - - return state - - - def addPlayer(self, position, player): - # Overrides LocalTable, to provision revealHands() and testStartGame(). - LocalTable.addPlayer(self, position, player) - - self.handsSeen[position] = [] # Clear list of hands seen by player. - if self.game: # If game in progress... - self.revealHands() # ... provide player with visible hands. - # Test if game is ready to start. - self.testStartGame() - - - -# Methods implementing IBridgeTable. - - - def gameMakeCall(self, call, position): - if self.game is None or self.game.isComplete(): - raise DeniedRequest, 'Game not running' - elif position is None: - raise DeniedRequest, 'Not a player' - - try: - self.game.makeCall(call=call, player=position) - except GameError, error: - raise DeniedRequest, error - - self.updateObservers('gameCallMade', call=call, position=position.key) - self.testEndGame() - - - def gamePlayCard(self, card, position): - if self.game is None or self.game.isComplete(): - raise DeniedRequest, 'Game not running' - elif position is None: - raise DeniedRequest, 'Not a player' - elif self.game.playing is None: - raise DeniedRequest, 'Play not running' - - # Declarer can play dummy's cards, dummy cannot play own cards. - if self.game.whoseTurn() == self.game.playing.dummy: - if position == self.game.playing.declarer: # Declarer commands dummy. - position = self.game.playing.dummy - elif position == self.game.playing.dummy: - raise DeniedRequest, 'Dummy cannot play cards' - - try: - self.game.playCard(card=card, player=position) - except GameError, error: - raise DeniedRequest, error - - self.updateObservers('gameCardPlayed', card=card, position=position.key) - self.revealHands() - self.testEndGame() - - - def requestNextGame(self, player, ready=True): - self.observers[player]['ready'] = (ready == True) - self.testStartGame() # Check to start game. - - -# Utility methods. - - - def testStartGame(self, dealer=None, deal=None): - """If no game is active and all players are ready, start a game.""" - if (self.game is None or self.game.isComplete()) \ - and len([p for p in self.players.values() if p is None]) == 0: - - deal = deal or self.deck.randomDeal() - vulnNS, vulnEW = False, False - self.dealer = dealer or (self.dealer and Player[(self.dealer.index + 1) % 4]) or Player.North - self.game = Game(self.dealer, deal, self.scoring, vulnNS, vulnEW) - self.updateObservers('gameStarted', dealer=self.dealer.key, vulnNS=vulnNS, vulnEW=vulnEW) - - for position in self.handsSeen: - self.handsSeen[position] = [] # Clear lists of hands seen. - self.revealHands() # Provide players with their hands. - return True - return False - - - def testEndGame(self): - """If game is finished, end game.""" - if self.game and self.game.isComplete(): - self.updateObservers('gameFinished') - self.revealHands() # Make all hands visible. - - # Set up time delay before next game starts. - wait = self.config.get('gameWaitInterval', 0) - reactor.callLater(wait, self.testStartGame) - - return True - return False - - - def revealHands(self): - """ - - Each hand is transmitted only once to each player. - """ - # TODO: what about observers? - for viewer, player in self.players.items(): - for seat in Player: - if seat not in self.handsSeen[viewer] and self.game.isHandVisible(seat, viewer): - self.handsSeen[viewer].append(seat) - hand = self.game.deal[seat] - self.informObserver(self.observers[player], 'gameHandRevealed', - hand=hand, position=seat.key) - - - - -class LocalBridgeTableViewable(LocalTableViewable): - - - def view_gameMakeCall(self, user, call, position=None): - position = self.table.getPositionOfPlayer(user) - self.table.gameMakeCall(call, position) - - - def view_gamePlayCard(self, user, card, position=None): - position = self.table.getPositionOfPlayer(user) - self.table.gamePlayCard(card, position) - Modified: trunk/pybridge/pybridge/network/localtable.py =================================================================== --- trunk/pybridge/pybridge/network/localtable.py 2007-03-27 14:55:26 UTC (rev 367) +++ trunk/pybridge/pybridge/network/localtable.py 2007-03-27 15:11:40 UTC (rev 368) @@ -21,22 +21,33 @@ from twisted.spread import pb from zope.interface import implements +from pybridge.interfaces.observer import ISubject, IListener from pybridge.interfaces.table import ITable from pybridge.network.error import DeniedRequest, IllegalRequest -from pybridge.bridge.symbols import Player # XX TODO: Try to avoid this. class LocalTable(pb.Cacheable): - """""" + """An implementation of ITable suitable for server-side table instances. + + A LocalTable maintains the "master" game object and provides synchronisation + services for remote tables to mirror the game state. + """ - implements(ITable) + implements(ITable, ISubject, IListener) - def __init__(self, id): + def __init__(self, id, gametype): + self.listeners = [] + self.id = id + self.gametype = gametype + self.game = gametype() # Initialise game. + self.game.attach(self) # Listen for game events. + self.config = {} - self.observers = {} # For each perspective, a remote ITableEvents observer. - self.players = {} # For each position, the player's perspective. + self.observers = {} # For each user perspective, a remote ITableEvents. + self.players = {} # Positions mapped to perspectives of game players. + self.view = LocalTableViewable(self) # For remote clients. # Configuration variables. self.config['closeWhenEmpty'] = True @@ -44,65 +55,112 @@ def getStateToCacheAndObserveFor(self, perspective, observer): - self.updateObservers('observerAdded', observer=perspective.name) + # Inform existing observers that a new user has joined. + self.notify('addObserver', observer=perspective.name) self.observers[perspective] = observer - - return self.getState() # For observer. - - def getState(self): - """Build a dict of public information about the table.""" + # Build a dict of public information about the table. state = {} - state['id'] = self.id state['observers'] = [p.name for p in self.observers.keys()] - state['players'] = {} - for position, perspective in self.players.items(): - state['players'][position.key] = getattr(perspective, 'name', None) -# state['timeCreated'] = self.config['timeCreated'] - - return state + state['players'] = dict([(pos, p.name) + for pos, p in self.players.items()]) + state['gametype'] = self.gametype.__name__ + state['gamestate'] = self.game.getState() + return state # To observer. + def stoppedObserving(self, perspective, observer): + # If user was playing, then remove their player(s) from game. + for position, user in self.players.items(): + if perspective == user: + self.leaveGame(perspective, position) + del self.observers[perspective] - - # If user was a player, then remove player. - if self.getPositionOfPlayer(perspective): - self.removePlayer(perspective) - - self.updateObservers('observerRemoved', observer=perspective.name) - + self.notify('removeObserver', observer=perspective.name) + # If there are no remaining observers, close table. - if self.config.get('closeWhenEmpty') and len(self.observers) == 0: + if self.config.get('closeWhenEmpty') and not self.observers: self.server.tables.closeTable(self) -# Methods implementing ITable. +# Implementation of ISubject. - def addPlayer(self, position, player): - # Check that player is not already playing at table. - if self.getPositionOfPlayer(player): - raise DeniedRequest('already playing at table') - # Check that position is not occupied by another player. - if self.players.get(position) is not None: - raise DeniedRequest('position occupied by another player') - - self.players[position] = player - self.updateObservers('playerAdded', player=player.name, position=position.key) + def attach(self, listener): + self.listeners.append(listener) - def removePlayer(self, player): - position = self.getPositionOfPlayer(player) - # Check that player is playing at table: - if not position: - raise DeniedRequest('not playing at table') + def detach(self, listener): + self.listeners.remove(listener) + + + def notify(self, event, *args, **kwargs): + for listener in self.listeners: + listener.update(event, *args, **kwargs) + # For all observers, calls event handler with provided arguments. + for observer in self.observers.values(): + self.notifyObserver(observer, event, *args, **kwargs) + + + def notifyObserver(self, obs, event, *args, **kwargs): + """Calls observer's event handler with provided arguments. - self.players[position] = None - self.updateObservers('playerRemoved', player=player.name, position=position.key) + @param obs: an observer object. + @type obs: RemoteCacheObserver + @param event: the name of the event. + @type event: str + """ + # Event handlers are called on the next iteration of the reactor, + # to allow the caller of this method to return a result. + reactor.callLater(0, obs.callRemote, event, *args, **kwargs) +# Implementation of IListener. + + + def update(self, event, *args, **kwargs): + # Expected to be called only by methods of self.game. + for observer in self.observers.values(): + self.notifyObserver(observer, 'gameUpdate', event, *args, **kwargs) + + +# Implementation of ITable. + + + def joinGame(self, user, position): + if position not in self.game.positions: + raise IllegalRequest, "Invalid position type" + # Check that user is not already playing at table. + if not self.config.get('allowUserMultiplePlayers'): + if user in self.players.values(): + raise DeniedRequest, "Already playing in game" + + player = self.game.addPlayer(position) # May raise GameError. + self.players[position] = user + self.notify('joinGame', player=user.name, position=position) + + # If no game is active and all players are ready, start game. + if not self.game.inProgress(): + if len(self.players) == len(self.game.positions): + self.game.start() + + return player + + + def leaveGame(self, user, position): + if position not in self.game.positions: + raise IllegalRequest, "Invalid position type" + # Ensure that user is playing at specified position. + if self.players.get(position) != user: + raise DeniedRequest, "Not playing at position" + + self.game.removePlayer(position) # May raise GameError. + del self.players[position] + self.notify('leaveGame', player=user.name, position=position) + + def sendMessage(self, message, sender, recipients): names = [perspective.name for perspective in self.observers.keys()] if recipients: # Translate user names to their observer objects. @@ -112,49 +170,19 @@ else: # Broadcast message to all observers. recipients = names sendTo = self.observers.values() - + for observer in sendTo: - observer.callRemote('messageReceived', message, sender.name, recipients) + self.notifyObserver(observer, 'sendMessage', message=message, + sender=sender.name, recipients=recipients) -# Utility methods. - def getPositionOfPlayer(self, user): - """If observer is playing, returns position of player. - Otherwise, returns False. - - @param user: observer identifier. - @return: position of player, or False. - """ - for position, player in self.players.items(): - if player == user: - return position - return False - - - def informObserver(self, obs, event, *args, **kwargs): - """Calls observer's event handler with provided args and kwargs. - - Event handlers are called on the next iteration of the reactor, - to allow the caller of this method to return a result. - """ - reactor.callLater(0, obs.callRemote, event, *args, **kwargs) - - - def updateObservers(self, event, *args, **kwargs): - """For each observer, calls event handler with provided kwargs.""" - for observer in self.observers.values(): - self.informObserver(observer, event, *args, **kwargs) - - - - class LocalTableViewable(pb.Viewable): - """ + """Provides a public front-end to an instantiated LocalTable. Serialization flavors are mutually exclusive and cannot be mixed, - so this class provides a pb.Viewable front-end to LocalTable. + so this class is a subclass of pb.Viewable. """ @@ -166,15 +194,14 @@ self.table = table - def view_addPlayer(self, user, position, player=None): - position = getattr(Player, position) # XX - self.table.addPlayer(position, user) + def view_joinGame(self, user, position): + return self.table.joinGame(user, position) - def view_removePlayer(self, user, player=None): - self.table.removePlayer(user) + def view_leaveGame(self, user, position): + return self.table.leaveGame(user, position) def view_sendMessage(self, user, message, sender=None, recipients=[]): - self.table.sendMessage(message, user, recipients) + return self.table.sendMessage(message, sender=user, recipients=recipients) Deleted: trunk/pybridge/pybridge/network/remotebridge.py =================================================================== --- trunk/pybridge/pybridge/network/remotebridge.py 2007-03-27 14:55:26 UTC (rev 367) +++ trunk/pybridge/pybridge/network/remotebridge.py 2007-03-27 15:11:40 UTC (rev 368) @@ -1,140 +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 twisted.spread import pb -from zope.interface import implements - -from pybridge.interfaces.bridgetable import IBridgeTable -from pybridge.network.remotetable import RemoteTable -from pybridge.network.error import DeniedRequest, IllegalRequest - -# Set up reconstruction of objects from server. -from pybridge.bridge.call import Bid, Pass, Double, Redouble -from pybridge.bridge.card import Card -pb.setUnjellyableForClass(Bid, Bid) -pb.setUnjellyableForClass(Pass, Pass) -pb.setUnjellyableForClass(Double, Double) -pb.setUnjellyableForClass(Redouble, Redouble) -pb.setUnjellyableForClass(Card, Card) - -# Bridge game. -from pybridge.bridge.game import Game, GameError -from pybridge.bridge.scoring import scoreDuplicate -from pybridge.bridge.symbols import Player - - -class RemoteBridgeTable(RemoteTable): - """A bridge table, implementing the IBridgeTable interface. - - This is a cache of a remote MasterBridgeTable. - """ - - implements(IBridgeTable) - - - def __init__(self): - RemoteTable.__init__(self) - - self.dealer = None - self.game = None - self.players = dict.fromkeys(Player, None) - self.scoring = scoreDuplicate - - - def setCopyableState(self, state): - RemoteTable.setCopyableState(self, state) - - # Convert seat strings to Player enumeration values. - players = {} - for seat, player in self.players.items(): - players[getattr(Player, seat)] = player - self.players = players - - if state.get('game'): - self.dealer = getattr(Player, state['game']['dealer']) # XX - deal = {} - for player in Player: - deal[player] = state['game']['deal'].get(player, []) - vulnNS, vulnEW = state['game']['vulnNS'], state['game']['vulnEW'] - self.game = Game(self.dealer, deal, self.scoring, vulnNS, vulnEW) - if state['game'].get('calls'): - for call in state['game']['calls']: - player = self.game.whoseTurn() - self.game.makeCall(call=call, player=player) - if state['game'].get('played'): - played = state['game']['played'] - while sum([len(cards) for cards in played.values()]) > 0: - player = self.game.whoseTurn() - card = played[player.key].pop(0) - self.game.playCard(card=card, player=player) - - - def gameMakeCall(self, call, position=None): - d = self.master.callRemote('gameMakeCall', call) - return d - -# # Check that game is running and we are playing. -# if self.game and self.game.whoseTurn() == self.position \ -# and self.game.bidding.validCall(call): -# # TODO: bidding.isValidCall() should check turn to bid. -# d = self.master.callRemote('gameMakeCall', call) -# return d - - - def gamePlayCard(self, card, position): - d = self.master.callRemote('gamePlayCard', card) - return d - - - def requestNextGame(self, ready=True, player=None): - d = self.master.callRemote('requestNextGame', ready) - return d - - -# Remote update methods. - - - def observe_gameStarted(self, dealer, vulnNS, vulnEW): - dealer = getattr(Player, dealer) # XX - self.dealer = dealer - deal = dict.fromkeys(Player, []) # Unknown hands. - self.game = Game(dealer, deal, self.scoring, vulnNS, vulnEW) - self.eventHandler.gameStarted(self, dealer, vulnNS, vulnEW) - - - def observe_gameFinished(self): - self.eventHandler.gameFinished(self) - - - def observe_gameCallMade(self, call, position): - position = getattr(Player, position) # XX - self.game.makeCall(call=call, player=position) - self.eventHandler.gameCallMade(self, call, position) - - - def observe_gameCardPlayed(self, card, position): - position = getattr(Player, position) # XX - self.game.playCard(card=card, player=position) - self.eventHandler.gameCardPlayed(self, card, position) - - - def observe_gameHandRevealed(self, hand, position): - position = getattr(Player, position) # XX - self.game.deal[position] = hand - self.eventHandler.gameHandRevealed(self, hand, position) - Modified: trunk/pybridge/pybridge/network/remotetable.py =================================================================== --- trunk/pybridge/pybridge/network/remotetable.py 2007-03-27 14:55:26 UTC (rev 367) +++ trunk/pybridge/pybridge/network/remotetable.py 2007-03-27 15:11:40 UTC (rev 368) @@ -19,27 +19,31 @@ from twisted.spread import pb from zope.interface import implements +from pybridge.interfaces.observer import ISubject from pybridge.interfaces.table import ITable from pybridge.network.error import DeniedRequest, IllegalRequest -from pybridge.bridge.symbols import Player # XX TODO: Try to avoid this. class RemoteTable(pb.RemoteCache): - """ + """A client-side implementation of ITable providing a "front-end" to a + remote server-side LocalTable. + RemoteTable mirrors the state of LocalTable as a local cache. External code + may, therefore, read the table state without network communication. Actions + which change the table state are forwarded to the LocalTable. """ - implements(ITable) + implements(ITable, ISubject) def __init__(self): self.master = None # Server-side ITable object. - self.eventHandler = None # Expected to be set. - + self.listeners = [] + self.id = None - self.observers = [] - self.players = {} - self.seated = None # If user is playing at table. + self.game = None + self.observers = [] # Observers of master table. + self.players = {} # Positions mapped to player identifiers. def setCopyableState(self, state): @@ -47,23 +51,31 @@ self.observers = state['observers'] self.players = state['players'] + # TODO: do this by magic. + if state['gametype'] in ['BridgeGame']: + from pybridge.bridge.game import BridgeGame + self.gametype = BridgeGame + else: + raise NameError, "Unknown game type %s" % state['gametype'] - def setEventHandler(self, handler): - self.eventHandler = handler + self.game = self.gametype() + self.game.setState(state['gamestate']) -# Methods implementing ITable. +# Implementation of ITable. - def addPlayer(self, position, player=None): - d = self.master.callRemote('addPlayer', position.key) - d.addCallback(lambda _: setattr(self, 'seated', position)) + def setEventHandler(self, e): + print "called event handler - remove this!" + + + def joinGame(self, position, user=None): + d = self.master.callRemote('joinGame', position.key) return d - def removePlayer(self, player=None): - d = self.master.callRemote('removePlayer') - d.addCallback(lambda _: setattr(self, 'seated', None)) + def leaveGame(self, position, user=None): + d = self.master.callRemote('leaveGame', position.key) return d @@ -72,46 +84,52 @@ return d +# Implementation of ISubject. + + + def attach(self, listener): + self.listeners.append(listener) + + + def detach(self, listener): + self.listeners.remove(listener) + + + def notify(self, event, *args, **kwargs): + for listener in self.listeners: + listener.update(event, *args, **kwargs) + + # Remote update methods. - def observe_observerAdded(self, observer): + def observe_addObserver(self, observer): self.observers.append(observer) - self.eventHandler.observerAdded(self, observer) + self.notify('addObserver', observer) - def observe_observerRemoved(self, observer): + def observe_removeObserver(self, observer): self.observers.remove(observer) - self.eventHandler.observerRemoved(self, observer) + self.notify('removeObserver', observer) - def observe_playerAdded(self, player, position): - position = getattr(Player, position) # XX + def observe_joinGame(self, player, position): + position = getattr(self.game.positions, position) self.players[position] = player - self.eventHandler.playerAdded(self, player, position) + self.notify('joinGame', player, position) - def observe_playerRemoved(self, player, position): - position = getattr(Player, position) # XX - self.players[position] = None - self.eventHandler.playerRemoved(self, player, position) + def observe_leaveGame(self, player, position): + position = getattr(self.game.positions, position) + del self.players[position] + self.notify('leaveGame', player, position) - def observe_messageReceived(self, message, sender, recipients): - self.eventHandler.messageReceived(self, message, sender, recipients) + def observe_sendMessage(self, message, sender, recipients): + # TODO: add to message log? + self.notify('sendMessage', message, sender, recipients) -# Utility methods. + def observe_gameUpdate(self, event, *args, **kwargs): + self.game.updateState(event, *args, **kwargs) - - def getPositionOfPlayer(self, user=None): - """If user is playing, returns position of player, otherwise False. - - @param user: observer identifier. - @return: position of player, or False. - """ - for position, player in self.players.items(): - if player == user: - return position - return False - Modified: trunk/pybridge/pybridge/server/server.py =================================================================== --- trunk/pybridge/pybridge/server/server.py 2007-03-27 14:55:26 UTC (rev 367) +++ trunk/pybridge/pybridge/server/server.py 2007-03-27 15:11:40 UTC (rev 368) @@ -26,7 +26,8 @@ from pybridge.network.tablemanager import LocalTableManager from pybridge.network.usermanager import LocalUserManager -from pybridge.network.localbridge import LocalBridgeTable +from pybridge.network.localtable import LocalTable +from pybridge.bridge.game import BridgeGame class Server: @@ -80,7 +81,7 @@ def createTable(self, tableid, tabletype): # Ignore specified tabletype, for now. if tableid not in self.tables: - table = LocalBridgeTable(tableid) + table = LocalTable(tableid, BridgeGame) table.id = tableid table.server = self self.tables.openTable(table) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |