Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWalter Bender <walter.bender@gmail.com>2011-03-15 01:35:40 (GMT)
committer Walter Bender <walter.bender@gmail.com>2011-03-15 01:35:40 (GMT)
commitf84386784d4f447fb20b00bceb5f2f731e45c65b (patch)
treee4395390c5ccc9510eeae089135129987e6ee2d1
parent0279518276390439777a351a770c9e98b23d6ab3 (diff)
on the path to sharing
-rw-r--r--PathsActivity.py182
-rw-r--r--game.py40
-rw-r--r--hand.py6
-rw-r--r--utils.py8
4 files changed, 200 insertions, 36 deletions
diff --git a/PathsActivity.py b/PathsActivity.py
index 9f2f1da..68f8e1e 100644
--- a/PathsActivity.py
+++ b/PathsActivity.py
@@ -33,12 +33,23 @@ from sugar.graphics.menuitem import MenuItem
from sugar.graphics.icon import Icon
from sugar.datastore import datastore
+import telepathy
+from dbus.service import signal
+from dbus.gobject_service import ExportedGObject
+from sugar.presence import presenceservice
+from sugar.presence.tubeconn import TubeConnection
+
from gettext import gettext as _
import locale
import os.path
from game import Game, CARDS
from hand import Hand
+from utils import data_from_string, data_to_string
+
+ROW = 8
+COL = 8
+MAX_HANDS = 4
SERVICE = 'org.sugarlabs.PathsActivity'
IFACE = SERVICE
@@ -92,7 +103,11 @@ class PathsActivity(activity.Activity):
def __init__(self, handle):
""" Initialize the toolbars and the game board """
super(PathsActivity,self).__init__(handle)
-
+ self.nick = profile.get_nick_name()
+ if profile.get_color() is not None:
+ self.colors = profile.get_color().to_string().split(',')
+ else:
+ self.colors = ['#A0FFA0', '#FF8080']
self._setup_toolbars(_have_toolbox)
# Create a canvas
@@ -103,9 +118,7 @@ class PathsActivity(activity.Activity):
canvas.show()
self.show_all()
- self._game = Game(canvas,
- parent=self,
- colors= profile.get_color().to_string().split(','))
+ self._game = Game(canvas, parent=self, colors=self.colors)
# Restore game state from Journal or start new game
if 'deck0' in self.metadata:
@@ -208,23 +221,172 @@ class PathsActivity(activity.Activity):
self._game.grid.restore(self.metadata['grid'], self._game.deck)
self._game.show_connected_tiles()
- for i in range(2):
+ for i in range(MAX_HANDS):
if 'hand-' + str(i) in self.metadata:
- if len(self._game.hands) < i + 1: # Add robot hand?
+ if len(self._game.hands) < i + 1: # Add robot or shared hand?
self._game.hands.append(
Hand(self._game.card_width, self._game.card_height,
- robot=True))
+ remote=True))
self._game.hands[i].restore(self.metadata['hand-' + str(i)],
self._game.deck)
- self._game.deck.index = 64 - self._game.grid.cards_in_grid()
+ self._game.deck.index = ROW * COL - self._game.grid.cards_in_grid()
for h in self._game.hands:
- self._game.deck.index += (8 - h.cards_in_hand())
+ self._game.deck.index += (COL - h.cards_in_hand())
self._game.last_spr_moved = None
if 'last' in self.metadata:
j = int(self.metadata['last'])
- for k in range(64):
+ for k in range(ROW * COL):
if self._game.deck.cards[k].number == j:
self._game.last_spr_moved = self._game.deck.cards[k].spr
return
+
+ # Collaboration-related methods
+
+ def _setup_presence_service(self):
+ """ Setup the Presence Service. """
+ self.pservice = presenceservice.get_instance()
+ self.initiating = None # sharing (True) or joining (False)
+
+ owner = self.pservice.get_owner()
+ self.owner = owner
+ self._game.buddies.append(self.owner)
+ self._share = ""
+ self.connect('shared', self._shared_cb)
+ self.connect('joined', self._joined_cb)
+
+ def _shared_cb(self, activity):
+ """ Either set up initial share..."""
+ if self._shared_activity is None:
+ _logger.error("Failed to share or join activity ... \
+ _shared_activity is null in _shared_cb()")
+ return
+
+ self.initiating = True
+ self.waiting_for_hand = False
+ _logger.debug('I am sharing...')
+
+ self.conn = self._shared_activity.telepathy_conn
+ self.tubes_chan = self._shared_activity.telepathy_tubes_chan
+ self.text_chan = self._shared_activity.telepathy_text_chan
+
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal\
+ ('NewTube', self._new_tube_cb)
+
+ _logger.debug('This is my activity: making a tube...')
+ id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube(
+ SERVICE, {})
+
+ def _joined_cb(self, activity):
+ """ ...or join an exisiting share. """
+ if self._shared_activity is None:
+ _logger.error("Failed to share or join activity ... \
+ _shared_activity is null in _shared_cb()")
+ return
+
+ self.initiating = False
+ _logger.debug('I joined a shared activity.')
+
+ self.conn = self._shared_activity.telepathy_conn
+ self.tubes_chan = self._shared_activity.telepathy_tubes_chan
+ self.text_chan = self._shared_activity.telepathy_text_chan
+
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal(\
+ 'NewTube', self._new_tube_cb)
+
+ _logger.debug('I am joining an activity: waiting for a tube...')
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes(
+ reply_handler=self._list_tubes_reply_cb,
+ error_handler=self._list_tubes_error_cb)
+
+ self.waiting_for_hand = True
+
+ def _list_tubes_reply_cb(self, tubes):
+ """ Reply to a list request. """
+ for tube_info in tubes:
+ self._new_tube_cb(*tube_info)
+
+ def _list_tubes_error_cb(self, e):
+ """ Log errors. """
+ _logger.error('ListTubes() failed: %s', e)
+
+ def _new_tube_cb(self, id, initiator, type, service, params, state):
+ """ Create a new tube. """
+ _logger.debug('New tube: ID=%d initator=%d type=%d service=%s '
+ 'params=%r state=%d', id, initiator, type, service,
+ params, state)
+
+ if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE):
+ if state == telepathy.TUBE_STATE_LOCAL_PENDING:
+ self.tubes_chan[ \
+ telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id)
+
+ tube_conn = TubeConnection(self.conn,
+ self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES], id, \
+ group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP])
+
+ self.chattube = ChatTube(tube_conn, self.initiating, \
+ self.event_received_cb)
+
+ # Let the sharer know joiner is waiting for a hand.
+ if self.waiting_for_hand:
+ self._send_event('j|[%s]' % (data_to_string(self.nick)))
+
+ def _setup_dispatch_table(self):
+ self._processing_methods = {
+ 'j': self._new_joiner,
+ 'b': self._buddy_list
+ }
+
+ def event_received_cb(self, event_message):
+ if len(event_message) == 0:
+ return
+ try:
+ command, payload = event_message.split('|', 2)
+ self._processing_methods[command](payload)
+ except ValueError:
+ _logger.debug('Could not split event message %s' % (event_message))
+
+ def _new_joiner(self, payload):
+ nick = data_from_string(payload)
+ _logger.debug("%s has joined" % (nick))
+ if not nick in self._game.buddies:
+ self._game.buddies.append(nick)
+ if self.initiating:
+ self._send_event('b|%s' % (data_to_string(self._game.buddies)))
+
+ def _buddy_list(self, payload):
+ buddies = data_from_string(payload)
+ for nick in buddies:
+ if not nick in self._game.buddies:
+ self._game.buddies.append(nick)
+
+ def _send_event(self, entry):
+ """ Send event through the tube. """
+ if hasattr(self, 'chattube') and self.chattube is not None:
+ self.chattube.SendText(entry)
+
+
+class ChatTube(ExportedGObject):
+ """ Class for setting up tube for sharing """
+
+ def __init__(self, tube, is_initiator, stack_received_cb):
+ super(ChatTube, self).__init__(tube, PATH)
+ self.tube = tube
+ self.is_initiator = is_initiator # Are we sharing or joining activity?
+ self.stack_received_cb = stack_received_cb
+ self.stack = ''
+
+ self.tube.add_signal_receiver(self.send_stack_cb, 'SendText', IFACE,
+ path=PATH, sender_keyword='sender')
+
+ def send_stack_cb(self, text, sender=None):
+ if sender == self.tube.get_unique_name():
+ return
+ self.stack = text
+ self.stack_received_cb(text)
+
+ @signal(dbus_interface=IFACE, signature='s')
+ def SendText(self, text):
+ self.stack = text
diff --git a/game.py b/game.py
index a3c3ec4..d578b46 100644
--- a/game.py
+++ b/game.py
@@ -101,6 +101,8 @@ class Game():
self.playing_with_robot = False
self.placed_a_tile = False
+ self.buddies = []
+
def new_game(self, saved_state=None, deck_index=0):
''' Start a new game. '''
@@ -109,12 +111,6 @@ class Game():
self.deck.hide()
# Shuffle the deck and deal a hand of tiles.
- '''
- if self.playing_with_robot:
- self.grid.set_robot_status(True)
- else:
- self.grid.set_robot_status(False)
- '''
self.grid.clear()
self.deck.clear()
self.show_connected_tiles()
@@ -125,7 +121,7 @@ class Game():
if self.playing_with_robot:
if len(self.hands) < ROBOT_HAND + 1:
self.hands.append(Hand(self.card_width, self.card_height,
- robot=True))
+ remote=True))
self.hands[ROBOT_HAND].deal(self.deck)
self.press = None
self.release = None
@@ -143,7 +139,7 @@ class Game():
self.press = None
self.release = None
- # Ignore clicks on background
+ # Ignore clicks on background.
if spr is None or \
spr in self.grid.blanks or \
spr == self.deck.board:
@@ -160,7 +156,6 @@ class Game():
return True
# Are we clicking on a tile in the hand?
- # if self.grid.spr_to_hand(spr) is not None and \
if self.hands[MY_HAND].spr_to_hand(spr) is not None and \
not self.there_are_errors:
self.last_spr_moved = spr
@@ -246,10 +241,6 @@ class Game():
self.release = None
self.show_connected_tiles()
- '''
- if self.grid.cards_in_hand() == 0 and not self.playing_with_robot:
- self.grid.redeal(self.deck)
- '''
if self.hands[MY_HAND].cards_in_hand() == 0 and \
not self.playing_with_robot:
self.hands[MY_HAND].deal(self.deck)
@@ -261,8 +252,9 @@ class Game():
self.activity.robot_button.set_icon('robot-off')
def show_connected_tiles(self):
- ''' Highlight the tiles that surround the tiles on the grid '''
- for i in range(64):
+ ''' Highlight the squares that surround the tiles already on the grid.
+ '''
+ for i in range(ROW * COL):
if self._connected(i):
self.grid.blanks[i].set_layer(GRID)
else:
@@ -274,8 +266,7 @@ class Game():
return True
if self.grid.grid[tile] is not None: # already has a tile
return False
- if tile > COL and \
- self.grid.grid[tile + OFFSETS[0]] is not None:
+ if tile > COL and self.grid.grid[tile + OFFSETS[0]] is not None:
return True
if tile % ROW < ROW - 1 and \
self.grid.grid[tile + OFFSETS[1]] is not None:
@@ -283,26 +274,28 @@ class Game():
if tile < (ROW - 1) * COL and \
self.grid.grid[tile + OFFSETS[2]] is not None:
return True
- if tile % ROW > 0 and \
- self.grid.grid[tile + OFFSETS[3]] is not None:
+ if tile % ROW > 0 and self.grid.grid[tile + OFFSETS[3]] is not None:
return True
def _robot_play(self):
- ''' robot tries random cards in random locations '''
+ ''' The robot tries random cards in random locations. '''
+ # TODO: try to complete paths
order = self.deck.random_order(ROW * COL)
for i in range(ROW * COL):
if self._connected(order[i]):
for tile in self.hands[ROBOT_HAND].hand:
if self._try_placement(tile, order[i]):
- # Success, so remove tile from hand
+ # Success, so remove tile from hand.
self.hands[ROBOT_HAND].hand[
self.hands[ROBOT_HAND].hand.index(tile)] = None
tile.spr.move(self.grid.grid_to_xy(order[i]))
tile.spr.set_layer(CARDS)
return
+
+ # If we didn't return above, we were unable to play a tile.
if self.sugar:
self.activity.set_robot_status(False, 'robot-off')
- # Show any tiles remaining in the robot's hand
+ # At the end of the game, show any tiles remaining in the robot's hand.
for i in range(COL):
if self.hands[ROBOT_HAND].hand[i] is not None:
x, y = self.hands[ROBOT_HAND].hand_to_xy(i)
@@ -419,7 +412,7 @@ class Game():
return True
def _test_for_bad_paths(self, tile):
- ''' Is there a path to no where? '''
+ ''' Is there a path to nowhere? '''
self._hide_errormsgs()
self.there_are_errors = False
if tile is not None:
@@ -430,6 +423,7 @@ class Game():
self._check_card(tile, [tile % ROW, 0], W, tile + OFFSETS[3])
def _check_card(self, i, edge_check, direction, neighbor):
+ ''' Can a card be placed at position i? '''
if edge_check[0] == edge_check[1]:
for path in self.grid.grid[i].paths:
if path[direction] == 1:
diff --git a/hand.py b/hand.py
index 7b99b26..8264be9 100644
--- a/hand.py
+++ b/hand.py
@@ -22,17 +22,17 @@ CARDS = 3
class Hand:
''' Class for managing COL matrix of cards '''
- def __init__(self, card_width, card_height, robot=False):
+ def __init__(self, card_width, card_height, remote=False):
# the tiles in your hand
self.hand = []
- self.robot = robot # Does this hand belong to the robot?
+ self.remote = remote # Does this hand belong to someone remote?
for i in range(COL):
self.hand.append(None)
# card spacing
self.xinc = int(card_width)
- if self.robot:
+ if self.remote:
self.left = -self.xinc
else:
self.left = int(card_width / 2)
diff --git a/utils.py b/utils.py
index 39298e3..ae689d7 100644
--- a/utils.py
+++ b/utils.py
@@ -54,3 +54,11 @@ def json_dump(data):
jdump(data, _io)
return _io.getvalue()
+def data_from_string(text):
+ """ JSON load data from a string. """
+ return json_load(text.replace(']],\n', ']], '))
+
+def data_to_string(data):
+ """ JSON dump a string. """
+ return json_dump(data).replace(']], ', ']],\n')
+