[gnome-games/sudoku-tube] Properly notify each other when puzzle finished



commit ba033fc668b1ae180455c2a2a3f349359644c1e8
Author: Zhang Sen <zh jesse gmail com>
Date:   Fri Aug 7 19:50:02 2009 +0800

    Properly notify each other when puzzle finished
    
    Still many glitches

 gnome-sudoku/src/lib/main.py       |  110 +++++++++++++++++++++++++++---------
 gnome-sudoku/src/lib/networking.py |   27 ++++++---
 gnome-sudoku/src/lib/view.py       |    1 +
 3 files changed, 102 insertions(+), 36 deletions(-)
---
diff --git a/gnome-sudoku/src/lib/main.py b/gnome-sudoku/src/lib/main.py
index a10d91b..8d330f8 100644
--- a/gnome-sudoku/src/lib/main.py
+++ b/gnome-sudoku/src/lib/main.py
@@ -56,7 +56,8 @@ class UI (gconf_wrapper.GConfWrapper):
                      }
     _tube_service = 'org.gnome.Sudoku'
     _view_obj_path = "/SideView"
-    _virgin_puzzle_obj_path = "/virgin_puzzle"
+    _initiator_obj_path = "/Initiator"
+    _receiver_obj_path = "/Receiver"
 
     def __init__ (self):
         gconf_wrapper.GConfWrapper.__init__(self,
@@ -68,6 +69,7 @@ class UI (gconf_wrapper.GConfWrapper):
         self._main_grid_vew = None
         self._history_manager = None
         self._tube = None
+        self._is_initiator = None
         self._is_waiting_for_response = None # this should be extraced out
 
         self.setup_gui()
@@ -95,7 +97,6 @@ class UI (gconf_wrapper.GConfWrapper):
 
         if game:
             self._open_game(*game)
-            self._post_open_setup()
         else:
             logger.error("can't open game")
             self.quit_cb()
@@ -139,7 +140,7 @@ class UI (gconf_wrapper.GConfWrapper):
         else:
             logger.fatal("shouldn't be here")
 
-        self._main_grid_vew.connect_to_notes_model(self._notes_model)
+        self._post_open_setup()
 
     def _open_saved_game(self, jar):
         virgin, in_prog = jar["game"].split('\n')
@@ -176,6 +177,7 @@ class UI (gconf_wrapper.GConfWrapper):
         """Properly do the setup after entering game
 
         Like show highlight, update hints, start timer, etc."""
+        self._main_grid_vew.connect_to_notes_model(self._notes_model)
         self._main_model.connect('puzzle-finished', self.you_win_callback)
         self._calc_difficulty()
         self.setup_toggles()
@@ -394,8 +396,52 @@ class UI (gconf_wrapper.GConfWrapper):
         self.sudoku_tracker.finish_game(self._jar_game())
         self.dancer = dancer.GridDancer(self._main_grid_vew, self._main_model)
         self.dancer.start_dancing()
+
+        if not self._tube: # local game
+            label = self._build_report_label()
+        else:
+            if self._negotiate_result():
+                label = "You WIN"
+            else:
+                return
+
         dialog_extras.show_message(_("You win!"), label = _("You win!"),
-                                   sublabel=self._build_report_label())
+                                   sublabel=label)
+
+    def _negotiate_result(self):
+        def reply_handler(self, *args):
+            print 'acknowledge reply', args
+        def error_handler(self, error):
+            print 'acknowledge error:', error
+
+        if self._is_initiator:
+            i_win = True
+            logger.info('signal receiver that they fail')
+            self._peer.acknowledge_win(
+                    reply_handler=reply_handler,
+                    error_handler=error_handler)
+        else:
+            assert self._peer is not None
+            if not self._peer.has_won():
+                i_win = True
+                logger.info('signal initiator that they fail')
+                self._peer.acknowledge_win(
+                        reply_handler=reply_handler,
+                        error_handler=error_handler)
+            # else do nothing; wait for initatior to tell us that we fail
+        return i_win
+
+    def fail_network_game(self):
+        dialog = gtk.Dialog("You fail",
+                self.w,
+                gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
+                (gtk.STOCK_OK, gtk.RESPONSE_OK))
+        label = gtk.Label("you fail")
+        label.show()
+        dialog.vbox.pack_start(label)
+        dialog.connect("response", self._stop_network_game)
+        dialog.run()
+        dialog.destroy()
 
     def new_cb (self, *args):
         if self._close_current_game():
@@ -407,6 +453,8 @@ class UI (gconf_wrapper.GConfWrapper):
                 self._open_game(choice[0], choice[1])
 
     def _new_with_contact_cb(self, action):
+        assert self._is_initiator is None
+        self._is_initiator = True
         choice = contact_selector.contact_selector_run(self.w)
         if choice:
             conn, handle, contact = choice
@@ -442,6 +490,7 @@ class UI (gconf_wrapper.GConfWrapper):
 
     def _offer_fail_cb(self, offer, reason):
         self._is_waiting_for_response = False
+        self._is_initiator = None
         # clear label and button
         vbox = self._wait_dialog.vbox
         vbox.remove(vbox.get_children()[0])
@@ -459,15 +508,23 @@ class UI (gconf_wrapper.GConfWrapper):
 
     def _tube_received_cb(self, bus, tube):
         """Called when we receive a tube"""
+
+        def error_cb(exception):
+            print 'get puzzle error:', exception
+
+        assert self._is_initiator is None
+        self._is_initiator = False
         self._bus = bus
         self._tube = tube
         self._tube[tp_tube.CHANNEL_INTERFACE].connect_to_signal(
                 'Closed', self._tube_closed_cb)
-        virgin_puzzle = bus.get_object(object_path=self._virgin_puzzle_obj_path)
-        virgin_puzzle.get_puzzle(
+
+        myself = networking.Peer(bus, self._receiver_obj_path, self)
+        self._peer = bus.get_object(object_path=self._initiator_obj_path)
+        self._peer.get_puzzle(
                 dbus_interface="org.gnome.Sudoku.view",
                 reply_handler=self._got_remote_puzzle_cb,
-                error_handler=self._error_cb)
+                error_handler=error_cb)
 
     def _got_remote_puzzle_cb(self, puzzle):
         logger.info("got puzzle: %s; type: %s" % (puzzle, type(puzzle)))
@@ -475,11 +532,8 @@ class UI (gconf_wrapper.GConfWrapper):
         assert len(puzzle) == 81
         self._close_current_game()
         self._open_game(game_selector.NewOrSavedGameSelector.NEW_GAME, puzzle)
-        self._init_side_view_display(puzzle)
-        self._tube_open_cb(self._bus, is_initiator=False)
-
-    def _error_cb(self, exception):
-        print 'error', exception
+        self._init_side_view_display()
+        self._negotiate_sideview(self._bus)
 
     def _tube_offered_cb(self, offer, bus, tube):
         """Called when the peer accepts our tube"""
@@ -492,24 +546,27 @@ class UI (gconf_wrapper.GConfWrapper):
         # string. FIXME
         self._auto_open_game(check_saved=False)
 
-        puzzle = self._puzzle.replace(" ", "") # delete all spaces
-        print 'exporting', puzzle
-        virgin_puzzle = networking.VirginGameString(bus,
-                self._virgin_puzzle_obj_path, puzzle)
-        self._init_side_view_display(puzzle)
-        self._tube_open_cb(bus, is_initiator=True)
+        myself = networking.Peer(bus, self._initiator_obj_path, self)
+        self._peer = bus.get_object(object_path=self._receiver_obj_path)
+
+        self._init_side_view_display()
+        self._negotiate_sideview(bus)
 
-    def _init_side_view_display(self, puzzle):
+    def get_puzzle(self):
+        return self._puzzle.replace(" ", "") # delete all spaces
+
+    def _init_side_view_display(self):
+        puzzle = self.get_puzzle()
         for x in range(9):
             for y in range(9):
                 val = int(puzzle[9 * y + x])
                 if val:
                     self._side_grid_vew.set_value(x, y, val)
 
-    def _tube_open_cb(self, bus, is_initiator):
+    def _negotiate_sideview(self, bus):
         receiver_view = self._view_obj_path + "/receiver"
         initiator_view = self._view_obj_path + "/initiator"
-        if is_initiator:
+        if self._is_initiator:
             our_obj_path, peer_obj_path = initiator_view, receiver_view
         else:
             our_obj_path, peer_obj_path = receiver_view, initiator_view
@@ -520,12 +577,12 @@ class UI (gconf_wrapper.GConfWrapper):
         logger.info("exported side-view on dbus")
 
         # Then fetch our peer's side-grid-view
-        remote_view_proxy = bus.get_object(object_path=peer_obj_path)
+        _remote_view_proxy = bus.get_object(object_path=peer_obj_path)
         logger.info("got a remote view which we can manipulate")
         # we issue command on remote_view_handler, which will communicate with
         # remote_view
-        view_handler = networking.RemoteViewHandler(remote_view_proxy)
-        view_handler.connect_to_model(self._main_model)
+        view_handler = networking.RemoteViewHandler(_remote_view_proxy)
+        self._main_model.add_observer(view_handler)
 
         self._side_grid_vew.show()
 
@@ -562,12 +619,13 @@ class UI (gconf_wrapper.GConfWrapper):
         self.gconf['height'] = event.height
 
     def _tube_closed_cb(self):
-        logger.info("tube has been closed")
+        self._is_initiator = None
         self._side_grid_vew.reset()
         self._side_grid_vew.hide()
         self._tube = None
+        logger.info("tube has been closed")
 
-    def _stop_network_game(self):
+    def _stop_network_game(self, *args):
         logger.info("close tube-channel")
         self._tube[tp_tube.CHANNEL_INTERFACE].Close()
         self._side_grid_vew.reset()
diff --git a/gnome-sudoku/src/lib/networking.py b/gnome-sudoku/src/lib/networking.py
index 7e19f78..0074d89 100644
--- a/gnome-sudoku/src/lib/networking.py
+++ b/gnome-sudoku/src/lib/networking.py
@@ -8,20 +8,30 @@ logger = logging.getLogger("main.network")
 
 view_interface = "org.gnome.Sudoku.view"
 
-class VirginGameString(dbus.service.Object):
-    """Receiver use this to get the game
-    """
+class Peer(dbus.service.Object):
 
-    def __init__(self, bus, obj_path, puzzle):
-        """puzzle should be a string
+    def __init__(self, bus, obj_path, game):
+        """game is the UI in main.py, for which we should get a better name
         """
         dbus.service.Object.__init__(self, bus, obj_path)
-        self._puzzle = puzzle
+        self._game = game
 
     @dbus.service.method(dbus_interface=view_interface,
             in_signature="", out_signature="s")
     def get_puzzle(self):
-        return self._puzzle
+        return self._game.get_puzzle()
+
+    @dbus.service.method(dbus_interface=view_interface,
+            in_signature="", out_signature="b")
+    def has_won(self):
+        return self._game.won
+
+    @dbus.service.method(dbus_interface=view_interface,
+            in_signature="", out_signature="")
+    def acknowledge_win(self):
+        """Used by the peer to tell us that we fail"""
+        logger.info('our peer says we fail')
+        self._game.fail_network_game()
 
 class SideViewProxy(dbus.service.Object):
     """A dbus object, which exports a sudoku game's side-view on dbus
@@ -77,9 +87,6 @@ class RemoteViewHandler:
     def puzzle_finished_cb(self):
         self._remote_proxy.puzzle_finished_cb()
 
-    def connect_to_model(self, model):
-        model.add_observer(self)
-
     def _handle_reply(self):
         pass
 
diff --git a/gnome-sudoku/src/lib/view.py b/gnome-sudoku/src/lib/view.py
index 8003b4f..de6e669 100644
--- a/gnome-sudoku/src/lib/view.py
+++ b/gnome-sudoku/src/lib/view.py
@@ -428,3 +428,4 @@ class SudokuSideView(SudokuNumberGrid):
         for x in range(self.group_size):
             for y in range(self.group_size):
                 self.set_value(x, y, 0)
+                self.set_color(x, y, None)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]