[gnome-games/sudoku-tube] Make notes working



commit 237d8f50f5d9b05a2500bfd5efa4cf1dbfbf1dc5
Author: Zhang Sen <zh jesse gmail com>
Date:   Mon Jul 13 12:49:24 2009 +0800

    Make notes working
    
    * Use another class, NotesModel, to track notes. SudokuModel knows nothing
       about notes.

 gnome-sudoku/src/lib/gsudoku.py |  152 +++++++++++++++++++++++---------------
 gnome-sudoku/src/lib/main.py    |   10 +--
 2 files changed, 96 insertions(+), 66 deletions(-)
---
diff --git a/gnome-sudoku/src/lib/gsudoku.py b/gnome-sudoku/src/lib/gsudoku.py
index f50c428..2077be2 100644
--- a/gnome-sudoku/src/lib/gsudoku.py
+++ b/gnome-sudoku/src/lib/gsudoku.py
@@ -162,6 +162,7 @@ class SudokuView(SudokuNumberGrid, gobject.GObject):
 
         self._model = None
         self._do_highlight_cells = False
+        self._notes_model = None
 
         for e in self.__entries__.values():
             e.show()
@@ -182,6 +183,10 @@ class SudokuView(SudokuNumberGrid, gobject.GObject):
                     self.set_readonly_appearance(x, y, True)
                     self.set_value(x, y, val)
 
+    def connect_to_notes_model(self, model):
+        self._notes_model = model
+        self._notes_model.add_observer(self)
+
     def update(self, values):
         """Update the GUI, called by a Model
 
@@ -212,7 +217,7 @@ class SudokuView(SudokuNumberGrid, gobject.GObject):
         self._model.set_value(x, y, value)
 
     def _notes_changed_cb(self, widget, top_note, bottom_note):
-        self._model.set_notes(widget.x, widget.y, top_note, bottom_note)
+        self._notes_model.set_notes(widget.x, widget.y, top_note, bottom_note)
 
     def _focus_callback(self, widget, event):
         if self._do_highlight_cells:
@@ -308,11 +313,86 @@ class NumberBoxModel:
         self.conflict = conflict
 
 
+class NotesModel:
+    """Track notes for a SudokuModel
+
+    Act as a observer of SudokuModel, and a model/observable for SudokuView.
+    SudokuModel should know nothing about notes.
+    """
+
+    def __init__(self, sudoku_model, group_size):
+        self._notes = {}
+        self._observers = []
+        self._group_size = group_size
+        self._model = sudoku_model
+        self._model.add_observer(self)
+
+        self._always_show_hints = False
+
+    def toggle_auto_hint(self, flag):
+        if flag:
+            self._always_show_hints = True
+            self.update_all_hints()
+        else:
+            self._always_show_hints = False
+            self.clear_hints()
+
+    def add_observer(self, observer):
+        self._observers.append(observer)
+
+    def _signal_observers(self, changes):
+        for observer in self._observers:
+            observer.update(changes)
+
+    def set_notes(self, x, y, top_note=None, bottom_note=None):
+        if (x, y) not in self._notes:
+            self._notes[(x, y)] = [None, None]
+
+        if top_note is not None:
+            self._notes[(x, y)][0] = top_note
+        if bottom_note is not None:
+            self._notes[(x, y)][0] = bottom_note
+
+        change = NumberBoxModel(x, y,
+                top_note=top_note, bottom_note=bottom_note)
+        self._signal_observers([change])
+
+    def update(self, changes):
+        if not self._always_show_hints:
+            return
+
+        self.update_all_hints()
+
+    def update_all_hints(self):
+        for x in range(self._group_size):
+            for y in range(self._group_size):
+                self._update_hint_for_entry(x, y)
+
+    def _update_hint_for_entry(self, x, y):
+        # no need to show anything if it's already filled, being correct or not
+        if self._model.get_value(x, y):
+            self.set_notes(x, y, bottom_note="")
+            return
+
+        vals = self._model.grid.possible_values(x, y)
+        vals = list(vals)
+        vals.sort()
+        if vals:
+            txt = ''.join([str(v) for v in vals])
+            self.set_notes(x, y, bottom_note=txt)
+        else:
+            self.set_notes(x, y, bottom_note="X")
+
+    def clear_hints(self):
+        for x in range(self.group_size):
+            for y in range(self.group_size):
+                self.set_notes(x, y, bottom_note="")
+
+
 class SudokuModel:
 
     def __init__ (self, grid, group_size):
         self.hints = 0
-        self.always_show_hints = False
         self.auto_fills = 0
         self.show_impossible_implications = False
         self.impossible_hints = 0
@@ -341,27 +421,6 @@ class SudokuModel:
             else:
                 self._show_hint_for_entry(entry, interactive = True)
 
-    def _show_hint_for_entry(self, entry, interactive = False):
-        if interactive:
-            set_method = entry.set_note_text_interactive
-        else:
-            set_method = entry.set_note_text
-        vals = self.grid.possible_values(entry.x, entry.y)
-        vals = list(vals)
-        vals.sort()
-        if vals:
-            ''.join([str(v) for v in vals])
-            txt = ''.join([str(v) for v in vals])
-            if txt != entry.get_text():
-                set_method(bottom_text = txt)
-                self.hints += 1
-        elif not entry.get_text():
-            if entry.get_text() != 'X':
-                self.hints += 1
-                set_method(bottom_text = 'X')
-        else:
-            set_method(bottom_text = "")
-
     def reset_grid (self):
         """Reset grid to its original setup.
 
@@ -377,22 +436,6 @@ class SudokuModel:
                         self.remove(x, y, do_removal = True)
         return removed
 
-    def clear_notes (self, clear_args = {'top_text':'', 'bottom_text':''}):
-        """Remove all notes."""
-        self.removed = []
-        for x in range(self.group_size):
-            for y in range(self.group_size):
-                e = self.__entries__[(x, y)]
-                top, bottom = e.get_note_text()
-                if top or bottom:
-                    self.removed.append((x, y, (top, bottom)))
-                    e.set_note_text(**clear_args)
-                    e.queue_draw()
-        return self.removed
-
-    def clear_hints (self):
-        self.clear_notes(clear_args = {'bottom_text':''})
-
     def _blank_grid(self):
         for x in range(self.group_size):
             for y in range(self.group_size):
@@ -448,23 +491,6 @@ class SudokuModel:
         if self.always_show_hints:
             self.update_all_hints()
 
-    def update_all_hints (self):
-        for x in range(self.group_size):
-            for y in range(self.group_size):
-                e = self.__entries__[(x, y)]
-                if e.read_only:
-                    pass
-                elif e.get_text():
-                    e.set_note_text(bottom_text = '')
-                else:
-                    self._show_hint_for_entry(e)
-
-    def _entry_validate(self, widget, *args):
-        val = widget.get_value()
-        self.add_value(widget.x, widget.y, val)
-        if self.grid.check_for_completeness():
-            self.emit('puzzle-finished')
-
     def set_value(self, x, y, value):
         result = []
         # first remove conflicts; grid.add should return conflicts together
@@ -475,10 +501,13 @@ class SudokuModel:
             change = NumberBoxModel(x=entry[0], y=entry[1], conflict=False)
             result.append(change)
 
-        try:
-            self.grid.add(x, y, value) # force=True???
-        except sudoku.ConflictError, err:
-            new_conflicts = self.grid.find_conflicts(x, y, value)
+        if not value: # should use unified way to update the grid
+            self.grid.remove(x, y)
+        else:
+            try:
+                self.grid.add(x, y, value) # force=True???
+            except sudoku.ConflictError, err:
+                new_conflicts = self.grid.find_conflicts(x, y, value)
         has_conflict = True if new_conflicts else False
         result.append(NumberBoxModel(x, y, value, conflict=has_conflict))
         if new_conflicts:
@@ -491,6 +520,9 @@ class SudokuModel:
         if self.grid.check_for_completeness():
             self._signal_completeness()
 
+    def get_value(self, x, y):
+        return self.grid._get_(x, y)
+
     def set_notes(self, x, y, top_note, bottom_note):
         # should first add notes to model
         change = NumberBoxModel(x, y,
diff --git a/gnome-sudoku/src/lib/main.py b/gnome-sudoku/src/lib/main.py
index 99d721d..d522e77 100644
--- a/gnome-sudoku/src/lib/main.py
+++ b/gnome-sudoku/src/lib/main.py
@@ -119,7 +119,10 @@ class UI (gconf_wrapper.GConfWrapper):
         self._puzzle = puzzle
         if game_type == game_selector.NewOrSavedGameSelector.NEW_GAME:
             self._main_model = gsudoku.SudokuModel(puzzle, 9)
+            self._notes_model = gsudoku.NotesModel(self._main_model, group_size=9)
+
             self._main_grid_vew.connect_to_model(self._main_model)
+            self._main_grid_vew.connect_to_notes_model(self._notes_model)
         elif game_type == game_selector.NewOrSavedGameSelector.SAVED_GAME:
             saver.open_game(self, puzzle)
         self._post_open_setup()
@@ -479,12 +482,7 @@ class UI (gconf_wrapper.GConfWrapper):
         self.gsd.show_hint()
 
     def auto_hint_cb (self, action):
-        if action.get_active():
-            self.gsd.always_show_hints = True
-            self.gsd.update_all_hints()
-        else:
-            self.gsd.always_show_hints = False
-            self.gsd.clear_hints()
+        self._notes_model.toggle_auto_hint(action.get_active())
 
     def impossible_implication_cb (self, action):
         if action.get_active():



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