[gnome-games/sudoku-vala] sudoku: Add undo/redo functionality



commit e47dd9802fc8fb295992c51b34ff1203f7db6ebb
Author: LubomÃr SedlÃÅ <lubomir sedlar gmail com>
Date:   Mon Aug 8 21:13:56 2011 +0200

    sudoku: Add undo/redo functionality

 gnome-sudoku/src/sudoku-game.vala |   73 ++++++++++++++++++++++++++++++++++---
 1 files changed, 68 insertions(+), 5 deletions(-)
---
diff --git a/gnome-sudoku/src/sudoku-game.vala b/gnome-sudoku/src/sudoku-game.vala
index f8eb15b..fe4709d 100644
--- a/gnome-sudoku/src/sudoku-game.vala
+++ b/gnome-sudoku/src/sudoku-game.vala
@@ -31,6 +31,7 @@ public class SudokuCell
                 return;
             if (_value == value)
                 return;
+            before_value_changed ();
             _value = value;
             value_changed ();
         }
@@ -49,6 +50,7 @@ public class SudokuCell
     }
 
     public signal void value_changed ();
+    public signal void before_value_changed ();
     
     public SudokuCell (int row, int col)
     {
@@ -62,18 +64,31 @@ public class SudokuCell
 public class SudokuGame
 {
     public SudokuCell[,] cells;
+
+    private struct UndoItem
+    {
+        public int row;
+        public int col;
+        public int val;
+    }
+
+    private SList<UndoItem?> undostack;
+    private SList<UndoItem?> redostack;
     
     public signal void cell_changed (SudokuCell cell);
 
     public SudokuGame ()
     {
         cells = new SudokuCell[9,9];
+        undostack = null;
+        redostack = null;
         for (int row = 0; row < 9; row++)
             for (int col = 0; col < 9; col++)
             {
                 var cell = new SudokuCell (row, col);
                 cells[row, col] = cell;
                 cell.value_changed.connect (cell_changed_cb);
+                cell.before_value_changed.connect (update_undo);
             }
     }
 
@@ -104,27 +119,37 @@ public class SudokuGame
             cell.value = digit;
             cell.is_fixed = is_fixed;
         }
+
+        /* No undo for preset cells */
+        undostack = null;
+        redostack = null;
     }
 
     public void undo ()
     {
-        stdout.printf ("TODO: undo\n");    
+        apply_stack (ref undostack, ref redostack);
     }
 
     public void redo ()
     {
-        stdout.printf ("TODO: redo\n");    
+        apply_stack (ref redostack, ref undostack);
     }
 
     public void reset ()
     {
-        for (int i = 0; i < 9; i++) {
-            for (int j = 0; j < 9; j++) {
-                if ( ! cells[i,j].is_fixed) {
+        int num = 0;
+        for (int i = 0; i < 9; i++)
+        {
+            for (int j = 0; j < 9; j++)
+            {
+                if (!cells[i,j].is_fixed && cells[i,j].value != 0)
+                {
                     cells[i,j].value = 0;
+                    num++;
                 }
             }
         }
+        add_to_stack (ref undostack, -1, -1, num);
     }
 
     private void cell_changed_cb (SudokuCell cell)
@@ -150,4 +175,42 @@ public class SudokuGame
 
         cell_changed (cell);
     }
+
+    private void update_undo (SudokuCell cell)
+    {
+        add_to_stack (ref undostack, cell.row, cell.col, cell.value);
+        redostack = null;
+    }
+
+    private void add_to_stack (ref SList<UndoItem?> stack, int r, int c, int v)
+    {
+        UndoItem step = { r, c, v };
+        stack.prepend (step);
+    }
+
+    private void apply_stack (ref SList<UndoItem?> from, ref SList<UndoItem?> to)
+    {
+        if (from == null) return;
+
+        /* Undoing change of single cell */
+        if (from.data.row >= 0 && from.data.col >= 0)
+        {
+            var cell = cells[from.data.row, from.data.col];
+
+            cell.before_value_changed.disconnect (update_undo);
+            add_to_stack (ref to, from.data.row, from.data.col, cell.value);
+            cell.value = from.data.val;
+            from.remove (from.data);
+            cell.before_value_changed.connect (update_undo);
+        }
+        /* Undoing reset action */
+        else
+        {
+            int num = from.data.val;
+            from.remove (from.data);
+            for (int i = 0; i < num; i++)
+                apply_stack (ref from, ref to);
+            add_to_stack (ref to, -1, -1, num);
+        }
+    }
 }



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