From 3625cb38049472a876ba4d65364989938e4e764d Mon Sep 17 00:00:00 2001
From: Anna Wiggins <annabunches@gmail.com>
Date: Wed, 25 Apr 2012 12:15:41 -0400
Subject: [PATCH] Cleaned up some of the sgf code and refactored it to make
 move navigation easier when we get to it

---
 lib/goban.py      | 65 +++++++++++++++++++++++++++++++++++++----------
 widgets/gogame.py |  2 ++
 2 files changed, 53 insertions(+), 14 deletions(-)

diff --git a/lib/goban.py b/lib/goban.py
index 90d9ac0..54a3e25 100644
--- a/lib/goban.py
+++ b/lib/goban.py
@@ -1,5 +1,6 @@
 from gomill import sgf
 
+# leftoffat: implementing navigation forwards and backward through the game.
 
 class Goban:
     """Represents the go board. Handles stone placement, captures, etc"""
@@ -52,6 +53,17 @@ class Goban:
             print 'There was a problem loading the SGF file.' 
         
         # Do initial layout
+        self._place_initial_stones()
+
+        for node in self.sgf_game.get_main_sequence():
+            self._play_node(node)
+
+        if self.sgf_game.get_winner() is not None:
+            self.winner = self.sgf_game.get_winner()
+            self.to_move = None
+
+
+    def _place_initial_stones(self):
         root = self.sgf_game.get_root()
         if root.has_setup_stones():
             black, white, empty = root.get_setup_stones()
@@ -59,18 +71,37 @@ class Goban:
                 self.board[self._real_pos(self._sgf_to_move(point))] = Goban.BLACK
             for point in white:
                 self.board[self._real_pos(self._sgf_to_move(point))] = Goban.WHITE
+            for point in empty:
+                self.board[self._real_pos(self._sgf_to_move(point))] = Goban.EMPTY
 
-        for node in self.sgf_game.get_main_sequence():
-            color, pos = node.get_move()
-            if color is not None:
-                if pos == 'pass':
-                    self.pass_move(color)
-                else:
-                    self.play_move(self._sgf_to_move(pos), color, add_sgf=False)
 
-        if self.sgf_game.get_winner() is not None:
-            self.winner = self.sgf_game.get_winner()
-            self.to_move = None
+    # Play a single node from an sgf tree. Useful for warking the tree.
+    def _play_node(self, node):
+        color, pos = node.get_move()
+        if color is not None:
+            if pos == 'pass':
+                self.pass_move(color)
+            else:
+                self.play_move(self._sgf_to_move(pos), color, add_sgf=False)
+        # fixme - add resignation detection
+
+
+    # Play all moves up to and including node, which should be
+    # an sgf.Tree_node
+    def _play_to_node(self, node):
+        self.soft_reset()
+        for n in self.sgf_game.get_main_sequence():
+            self._sgf_play_node(self, n)
+            if n == node:
+                return
+
+    
+    # Play to the nth move
+    def _play_to_move_n(self, n):
+        self.soft_reset()
+        portion = self.sgf_game.get_main_sequence()[:n]
+        for node in portion:
+            self._play_node(node)
 
 
     def save_sgf(self, file_name=None):
@@ -101,8 +132,9 @@ class Goban:
         self.hover = rpos
 
     
-    def reset(self):
-        """Reset the board to a pre-game state"""
+    def soft_reset(self):
+        """Reset the board to a pre-game state, but preserves move history.
+        In other words, goes back to before move #1"""
         # Clear the board by setting it to the same size it currently is at
         self.set_board_size(self.board_size)
         self.to_move = Goban.BLACK
@@ -114,7 +146,12 @@ class Goban:
         self.hover = None
         self.elapsed_time = 0
         self.winner = Goban.EMPTY
+
+
+    def reset(self):
+        '''Fully resets the game. The only thing preserved is the SGF filename, if it is set '''
         self.sgf_game = sgf.Sgf_game(self.board_size)
+        self.soft_reset()
 
 
     def set_board_size(self, new_size):
@@ -351,7 +388,7 @@ class Goban:
 
     def _delete_group_r(self, pos, who):
         if not self._on_board(pos):
-            return
+            return 0
 
         if self.board[pos] != who:
             return 0
@@ -477,7 +514,7 @@ class Goban:
 
 
     def _on_board(self, pos):
-        return pos >= 0 or pos < self.board_size * self.board_size
+        return pos >= 0 and pos < self.board_size * self.board_size
 
 
     def _other_color(self, color):
diff --git a/widgets/gogame.py b/widgets/gogame.py
index 5a24af6..3f06ec8 100644
--- a/widgets/gogame.py
+++ b/widgets/gogame.py
@@ -169,6 +169,8 @@ class GoGame(gtk.HBox):
                     code = 'bH'
                 elif self.goban.to_move == goban.Goban.WHITE:
                     code = 'wH'
+                else:
+                    continue
 
                 base_img = GoGame.img_res[code]
                 img = base_img.scale_simple(inc, inc, gtk.gdk.INTERP_BILINEAR)