Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Schampijer <simon@schampijer.de>2007-07-04 20:24:56 (GMT)
committer Simon Schampijer <simon@schampijer.de>2007-07-04 20:24:56 (GMT)
commitb148f9923dd40e35c972c93ef1ac03e431a4b65c (patch)
tree9085ef41472a16601b77206594c82256ba1b4cfd
parente749983674604effe0a304dc4c91a7719a11074c (diff)
- Moved things in a cleaner MVC.
- switched in the collaboration code to elect a leader and do total ordering - Added the NEWS file
-rw-r--r--NEWS0
-rw-r--r--controller.py206
-rw-r--r--game.py217
-rw-r--r--gamestate.py13
-rwxr-xr-xmemosonoactivity.py18
-rw-r--r--model.py7
6 files changed, 231 insertions, 230 deletions
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/controller.py b/controller.py
new file mode 100644
index 0000000..dc446aa
--- /dev/null
+++ b/controller.py
@@ -0,0 +1,206 @@
+import logging
+
+import gobject
+import gtk
+import os
+
+from dbus import Interface
+from dbus.service import method, signal
+from dbus.gobject_service import ExportedGObject
+
+from model import Model
+from gamestate import GameState
+
+# XXX: I'm not convinced this is in the right namespace
+SERVICE = "org.freedesktop.Telepathy.Tube.Memosono"
+IFACE = SERVICE
+PATH = "/org/freedesktop/Telepathy/Tube/Memosono"
+
+
+
+GAME_PATH = os.path.join(os.path.dirname(__file__),'games/drumgit')
+
+_logger = logging.getLogger('memosono-activity.game')
+
+
+class Controller(ExportedGObject):
+ ''' Networked Controller which is the core component of the activity. It
+ handles the communication with the components (model, view) and with the
+ other players over the network.
+ '''
+ def __init__(self, tube, playview, is_initiator, buddies_panel, info_panel,
+ owner, get_buddy, activity):
+ super(Controller, self).__init__(tube, PATH)
+ self.tube = tube
+ self.pv = playview
+ self.is_initiator = is_initiator
+ self.entered = False
+ self.buddies_panel = buddies_panel
+ self.info_panel = info_panel
+ self.owner = owner
+ self._get_buddy = get_buddy
+ self.activity = activity
+
+ self.model = None
+ self.playerid = None
+ self.turn = 0
+ # index 0 is the master
+ self.players = []
+ self.started = 0
+ self.count = 0
+ if self.is_initiator:
+ self.gs = GameState()
+ for tile in self.pv.tiles:
+ tile.connect('button-press-event', self._button_press_cb, self.pv.tiles.index(tile))
+
+ self.tube.watch_participants(self.participant_change_cb)
+
+ def participant_change_cb(self, added, removed):
+ # Initiator is player 0, other player is player 1.
+
+ _logger.debug('adding participants: %r', added)
+ _logger.debug('removing participants: %r', removed)
+
+ for handle, bus_name in added:
+ buddy = self._get_buddy(handle)
+ _logger.debug('Buddy %r was added', buddy)
+ if buddy is not None:
+ if len(self.players) < 2:
+ self.buddies_panel.add_player(buddy)
+ self.players.append(self.tube.participants[handle])
+ if self.is_initiator:
+ self.gs.points[self.tube.participants[handle]] = 0
+ _logger.debug('MA: points of players: %s', self.gs.points)
+ _logger.debug('MA: list of players: %s', self.players)
+ else:
+ self.buddies_panel.add_watcher(buddy)
+
+ for handle in removed:
+ buddy = self._get_buddy(handle)
+ _logger.debug('Buddy %r was removed', buddy)
+ if buddy is not None:
+ self.buddies_panel.remove_watcher(buddy)
+ try:
+ self.players.remove(self.tube.participants[handle])
+ except ValueError:
+ # already absent
+ pass
+
+ if not self.entered:
+ if self.is_initiator:
+ _logger.debug('I am the initiator, so making myself the leader of the game.')
+ self.init_game()
+ self.playerid = self.tube.get_unique_name()
+ self.tube.add_signal_receiver(self.info_cb, 'Info', IFACE,
+ path=PATH, sender_keyword='sender')
+ self.tube.add_signal_receiver(self.turn_cb, 'Turn', IFACE,
+ path=PATH, sender_keyword='sender')
+ self.tube.add_signal_receiver(self.flip_cb, 'Flip', IFACE,
+ path=PATH, sender_keyword='sender')
+ self.tube.add_signal_receiver(self.points_cb, 'Points', IFACE,
+ path=PATH, sender_keyword='sender')
+ self.entered = True
+
+ if self.is_initiator:
+ if len(self.players) == 2 and self.started == 0:
+ _logger.debug('Start the game.')
+ self.Info('Start the game')
+ self.started = 1
+ self.Turn(self.players[self.gs.player_active])
+
+ def init_game(self):
+ self.model = Model(GAME_PATH, os.path.dirname(__file__))
+ self.model.read('drumgit.mson')
+ self.model.def_grid()
+
+ self.tube.add_signal_receiver(self.selected_cb, 'Selected', IFACE,
+ path=PATH, sender_keyword='sender')
+
+ @signal(dbus_interface=IFACE, signature='n')
+ def Selected(self, tilenum):
+ """Signal that a tile has been selected"""
+
+ def selected_cb(self, tilenum, sender=None):
+ _logger.debug('MA: %s flipped tile %d', sender, tilenum)
+ obj, color = self.model.gettile(tilenum)
+ self.Flip(tilenum, obj, color)
+
+ self.count+=1
+ if self.count == 1:
+ self.gs.selected = tilenum
+ if self.count == 2:
+ self.count = 0
+ # evaluate
+ if( self.model.same(tilenum, self.gs.selected) == 1):
+ _logger.debug('MA: Tile(%d) and (%d) are the same', tilenum, self.gs.selected)
+ self.gs.points[sender]+=1
+ self.Points(sender, self.gs.points[sender])
+ self.info_panel.show('Open another one')
+ else:
+ gobject.timeout_add(2000, self._turn_back, tilenum, self.gs.selected)
+ _logger.debug('Tile(%d) and (%d) are NOT the same', tilenum, self.gs.selected)
+ # next player
+ self.change_turn()
+
+ def _turn_back(self, tilenuma, tilenumb):
+ self.Flip(tilenuma, 'images/black.png', 100)
+ self.Flip(tilenumb, 'images/black.png', 100)
+ return False
+
+ def change_turn(self):
+ if self.gs.player_active == 0:
+ self.gs.player_active = 1
+ else:
+ self.gs.player_active = 0
+
+ self.Turn(self.players[self.gs.player_active])
+
+
+ @signal(dbus_interface=IFACE, signature='nsn')
+ def Flip(self, tilenum, obj, color):
+ """Signal that a tile will be flipped"""
+
+ def flip_cb(self, tilenum, obj, color, sender=None):
+ handle = self.tube.bus_name_to_handle[sender]
+ _logger.debug('Flipped tile(%d) from %s', tilenum, sender)
+ self.pv.flip(tilenum, os.path.join(os.path.dirname(__file__), obj), color)
+
+
+ @signal(dbus_interface=IFACE, signature='s')
+ def Turn(self, playerid):
+ """Signal that it is the players turn"""
+
+ def turn_cb(self, playerid, sender=None):
+ if self.playerid == playerid:
+ self.turn = 1
+ self.info_panel.show('It is my turn')
+ else:
+ self.turn = 0
+
+
+ @signal(dbus_interface=IFACE, signature='sn')
+ def Points(self, player, points):
+ """Signal to update the points"""
+
+ def points_cb(self, player, points, sender=None):
+ handle = self.tube.bus_name_to_handle[player]
+ buddy = self._get_buddy(handle)
+ self.buddies_panel.set_count(buddy, points)
+
+
+ @signal(dbus_interface=IFACE, signature='s')
+ def Info(self, msg):
+ """Signal that there is some game information"""
+
+ def info_cb(self, msg, sender=None):
+ self.info_panel.show(msg)
+
+
+ def _button_press_cb(self, tile, event, tilenum=None):
+ if self.turn == 1:
+ self.Selected(tilenum)
+ else:
+ _logger.debug('Not my turn')
+ self.info_panel.show('Not my turn')
+
+
diff --git a/game.py b/game.py
deleted file mode 100644
index 236b908..0000000
--- a/game.py
+++ /dev/null
@@ -1,217 +0,0 @@
-import logging
-
-import gobject
-import gtk
-import os
-
-from dbus import Interface
-from dbus.service import method, signal
-from dbus.gobject_service import ExportedGObject
-
-
-# XXX: I'm not convinced this is in the right namespace
-SERVICE = "org.freedesktop.Telepathy.Tube.Memosono"
-IFACE = SERVICE
-PATH = "/org/freedesktop/Telepathy/Tube/Memosono"
-
-
-_logger = logging.getLogger('memosono-activity.game')
-
-
-class ConnectGame(ExportedGObject):
-
- def __init__(self, tube, playview, model, is_initiator, buddies_panel, info_panel,
- owner, get_buddy, activity):
- super(ConnectGame, self).__init__(tube, PATH)
- self.tube = tube
- self.pv = playview
- self.model = model
- self.is_initiator = is_initiator
- self.entered = False
- self.player_id = None
- self.buddies_panel = buddies_panel
- self.info_panel = info_panel
- self.owner = owner
- self._get_buddy = get_buddy
- self.activity = activity
-
- self.active_player = 1
- self.count = 0
- self.points = {}
-
- # list indexed by player ID
- # 0, 1 are players 0, 1
- # 2+ are the spectator queue, 2 is to play next
- self.ordered_bus_names = []
-
- for tile in self.pv.tiles:
- tile.connect('button-press-event', self._button_press_cb, self.pv.tiles.index(tile))
-
- self.tube.watch_participants(self.participant_change_cb)
-
- def participant_change_cb(self, added, removed):
- # Initiator is player 0, other player is player 1.
-
- _logger.debug('adding participants: %r', added)
- _logger.debug('removing participants: %r', removed)
-
- for handle, bus_name in added:
- buddy = self._get_buddy(handle)
- _logger.debug('Buddy %r was added', buddy)
- if buddy is not None:
- self.buddies_panel.add_watcher(buddy)
-
- for handle in removed:
- buddy = self._get_buddy(handle)
- _logger.debug('Buddy %r was removed', buddy)
- if buddy is not None:
- self.buddies_panel.remove_watcher(buddy)
- try:
- self.ordered_bus_names.remove(self.tube.participants[handle])
- except ValueError:
- # already absent
- pass
-
- if not self.entered:
- self.tube.add_signal_receiver(self.flip_cb, 'Flip', IFACE,
- path=PATH, sender_keyword='sender')
- if self.is_initiator:
- _logger.debug('I am the initiator, so making myself player 0')
- self.add_hello_handler()
- self.ordered_bus_names = [self.tube.get_unique_name()]
- self.player_id = 0
- self.points[self.player_id] = 0
- self.buddies_panel.add_player(self.owner)
- else:
- _logger.debug('Hello, everyone! What did I miss?')
- self.Hello()
- self.entered = True
-
- @signal(dbus_interface=IFACE, signature='')
- def Hello(self):
- """Request that this player's Welcome method is called to bring it
- up to date with the game state.
- """
-
- @method(dbus_interface=IFACE, in_signature='aanas', out_signature='')
- def Welcome(self, grid, bus_names):
- """To be called on the incoming player by the other players to
- inform them of the game state.
-
- FIXME: nominate a "referee" (initially the initiator) responsible
- for saying Welcome, elect a new referee when the current referee
- leaves? This could also be used to make the protocol robust against
- cheating/bugs
- """
- if self.player_id is None:
- _logger.debug('Welcomed to the game. Player bus names are %r',
- bus_names)
- _logger.debug('Received the grid: %s', str(grid))
- self.model.grid = grid
-
- self.ordered_bus_names = bus_names
- self.player_id = bus_names.index(self.tube.get_unique_name())
- self.points[self.player_id] = 0
- # OK, now I'm synched with the game, I can welcome others
- self.add_hello_handler()
-
- buddy = self._get_buddy(self.tube.bus_name_to_handle[bus_names[0]])
- self.buddies_panel.add_player(buddy)
- buddy = self._get_buddy(self.tube.bus_name_to_handle[bus_names[1]])
- self.buddies_panel.add_player(buddy)
-
- if self.active_player == self.player_id:
- _logger.debug("It's my turn already!")
- self.change_turn()
- else:
- _logger.debug("I've already been welcomed, doing nothing")
-
- def add_hello_handler(self):
- self.tube.add_signal_receiver(self.hello_cb, 'Hello', IFACE,
- path=PATH, sender_keyword='sender')
-
- @signal(dbus_interface=IFACE, signature='nsn')
- def Flip(self, tilenum, obj, color):
- """Signal that the local player has flipped a tile."""
-
- def hello_cb(self, sender=None):
- """Tell the newcomer what's going on."""
- _logger.debug('Newcomer %s has joined', sender)
- self.ordered_bus_names.append(sender)
- if len(self.ordered_bus_names) == 2:
- buddy = self._get_buddy(self.tube.bus_name_to_handle[sender])
- self.buddies_panel.add_player(buddy)
- _logger.debug('Bus names are now: %r', self.ordered_bus_names)
- _logger.debug('Welcoming newcomer and sending them the game state')
- grid = 0
- self.tube.get_object(sender, PATH).Welcome(self.model.grid,
- self.ordered_bus_names,
- dbus_interface=IFACE)
- _logger.debug('--- After welcome')
- if (self.player_id == 0 and len(self.ordered_bus_names) == 2):
- _logger.debug("This is my game and an opponent has joined. "
- "I go first")
- self.change_turn()
-
- def flip_cb(self, tilenum, obj, color, sender=None):
- handle = self.tube.bus_name_to_handle[sender]
- _logger.debug('Flipped tile(%d) from %s', tilenum, sender)
-
- self.pv.flip(tilenum, obj, color)
-
- self.count+=1
- if self.count == 1:
- self.comp = tilenum
- if self.count == 2:
- self.count = 0
- # evaluate
- if( self.model.same(tilenum, self.comp) == 1):
- _logger.debug('Tile(%d) and (%d) are the same', tilenum, self.comp)
- buddy = self._get_buddy(handle)
- self.points[self.active_player]+=1
- self.buddies_panel.set_count(buddy, self.points[self.active_player])
- self.info_panel.show('Open another one')
- else:
- gobject.timeout_add(2000, self._turn_back, tilenum, self.comp)
- _logger.debug('Tile(%d) and (%d) are NOT the same', tilenum, self.comp)
- # next player
- self.change_turn()
-
- def _turn_back(self, tilenuma, tilenumb):
- self.pv.flip(tilenuma, os.path.join(os.path.dirname(__file__), 'images/black.png'), 100)
- self.pv.flip(tilenumb, os.path.join(os.path.dirname(__file__), 'images/black.png'), 100)
- return False
-
- def change_turn(self):
- self.set_active_player()
- try:
- bus_name = self.ordered_bus_names[self.active_player]
- buddy = self._get_buddy(self.tube.bus_name_to_handle[bus_name])
- self.buddies_panel.set_is_playing(buddy)
- except:
- _logger.error('argh!', exc_info=1)
- raise
-
- if self.active_player == self.player_id:
- _logger.debug('It\'s my turn now')
- self.info_panel.show('Your turn')
- self.activity.grab_focus()
- else:
- _logger.debug('It\'s not my turn')
- self.info_panel.show('Other player\'s turn')
-
-
- def set_active_player(self):
- if self.active_player == 0:
- self.active_player = 1
- else:
- self.active_player = 0
-
- def _button_press_cb(self, tile, event, tilenum=None):
- if self.active_player != self.player_id:
- _logger.debug('Ignoring flip - not my turn')
- else:
- _logger.debug('selected tile=%s'%str(tilenum))
- obj, color = self.model.gettile(tilenum)
- self.Flip(tilenum, obj, color)
-
diff --git a/gamestate.py b/gamestate.py
new file mode 100644
index 0000000..a3e40c9
--- /dev/null
+++ b/gamestate.py
@@ -0,0 +1,13 @@
+
+
+class GameState(object):
+ ''' Used by the leader of the game to keep track of the game state
+ '''
+
+ def __init__(self):
+ self.player_active = 0
+ self.points = {}
+ self.turn = 0
+ self.selected = 0
+
+
diff --git a/memosonoactivity.py b/memosonoactivity.py
index 416c3aa..3bdc63f 100755
--- a/memosonoactivity.py
+++ b/memosonoactivity.py
@@ -36,11 +36,9 @@ from tubeconn import TubeConnection
from playview import PlayView
from buddiespanel import BuddiesPanel
from infopanel import InfoPanel
-from model import Model
-from game import ConnectGame
+from controller import Controller
-GAME_PATH = os.path.join(os.path.dirname(__file__),'games/drumgit')
class MemosonoActivity(Activity):
def __init__(self, handle):
@@ -49,12 +47,8 @@ class MemosonoActivity(Activity):
logging.debug('Starting Memosono activity...')
self.set_title(_('Memsosono Activity'))
-
- self.model = Model(GAME_PATH, os.path.dirname(__file__))
- self.model.read('drumgit.mson')
- self.model.def_grid()
- self.pv = PlayView( len(self.model.grid) )
+ self.pv = PlayView( 6 )
self.buddies_panel = BuddiesPanel()
@@ -90,7 +84,7 @@ class MemosonoActivity(Activity):
self.conn = telepathy.client.Connection(name, path)
self.initiating = None
- self.game = None
+ self.ctrl = None
toolbox = ActivityToolbox(self)
self.set_toolbox(toolbox)
@@ -214,7 +208,7 @@ class MemosonoActivity(Activity):
logging.error('ListTubes() failed: %s', e)
def _joined_cb(self, activity):
- if self.game is not None:
+ if self.ctrl is not None:
return
if not self._shared_activity:
@@ -238,7 +232,7 @@ class MemosonoActivity(Activity):
'params=%r state=%d', id, initiator, type, service,
params, state)
- if (self.game is None and type == telepathy.TUBE_TYPE_DBUS and
+ if (self.ctrl is None and type == telepathy.TUBE_TYPE_DBUS and
service == 'org.fredektop.Telepathy.Tube.Memosono'):
if state == telepathy.TUBE_STATE_LOCAL_PENDING:
self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptTube(id)
@@ -246,7 +240,7 @@ class MemosonoActivity(Activity):
tube_conn = TubeConnection(self.conn,
self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES],
id, group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
- self.game = ConnectGame(tube_conn, self.pv, self.model, self.initiating,
+ self.ctrl = Controller(tube_conn, self.pv, self.initiating,
self.buddies_panel, self.info_panel, self.owner,
self._get_buddy, self)
diff --git a/model.py b/model.py
index 510c9c4..581be15 100644
--- a/model.py
+++ b/model.py
@@ -3,9 +3,13 @@ import os
import logging
import random
-IMAGES_PATH = os.path.join(os.path.dirname(__file__),'games/drumgit/images')
+IMAGES_PATH = 'games/drumgit/images'
class Model(object):
+ ''' The model of the activity. Contains methods to read and save
+ the configuration for a game from xml. Stores the pairs and grid
+ information.
+ '''
def __init__(self, gamepath, dtdpath, name='noname'):
self.name = name
self.pairs = {}
@@ -95,6 +99,7 @@ class Model(object):
pairkeya, moch = self.grid[a]
pairkeyb, moch = self.grid[b]
return (pairkeya == pairkeyb)
+
if __name__ == '__main__':