[gnome-games/sudoku-vala] New solver, Sudokuboard class, frontend connection
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games/sudoku-vala] New solver, Sudokuboard class, frontend connection
- Date: Tue, 31 Jan 2012 04:23:03 +0000 (UTC)
commit 888acf571ff7bd31f04063fb3adb4f8f634a6579
Author: PioneerAxon <arth svnit gmail com>
Date: Mon Jan 30 12:17:40 2012 +0530
New solver, Sudokuboard class, frontend connection
Some bug-fixes.
-Solved: showing pop-ups ( number picker & note ) even with fixed value cell.
-Solved: no update in actual Sudoku with selection of no from number-picker.
Additions
-SudokuSolver class to solve sudoku ( This will help in SudokuGenerator class )
-SudokuBoard class, a new and faster representation of the sudoku game with dynamic size capabilities.
-Signal raising from SudokuBoard and handling from all other required classes.
-Proper randomly distributed hint.
-Undo-Redo functionalities.
gnome-sudoku/src/gnome-sudoku.vala | 154 ++-------------
gnome-sudoku/src/sudoku-game.vala | 341 +++++++++++++++++++++-----------
gnome-sudoku/src/sudoku-generator.vala | 94 +++++++++
gnome-sudoku/src/sudoku-view.vala | 132 ++++++++++---
4 files changed, 438 insertions(+), 283 deletions(-)
---
diff --git a/gnome-sudoku/src/gnome-sudoku.vala b/gnome-sudoku/src/gnome-sudoku.vala
index 5d65c57..55f4b0b 100644
--- a/gnome-sudoku/src/gnome-sudoku.vala
+++ b/gnome-sudoku/src/gnome-sudoku.vala
@@ -30,19 +30,8 @@ public class Application
toolbar = (Gtk.Toolbar) builder.get_object ("sudoku_toolbar");
settings.bind ("show-toolbar", builder.get_object ("sudoku_toolbar"), "visible", SettingsBindFlags.DEFAULT);
settings.bind("show-toolbar", builder.get_object ("toggle_toolbar_imagemenuitem"), "active", SettingsBindFlags.GET);
-
- game = SudokuGenerator.generate ("easy");
game = new SudokuGame ();
- game.set_from_string ("---------" +
- "-----3-85" +
- "--1-2----" +
- "---5-7---" +
- "--4---1--" +
- "-9-------" +
- "5------73" +
- "--2-1----" +
- "----4---9");
- game.set_from_string ("1.......2.9.4...5...6...7...5.9.3.......7.......85..4.7.....6...3...9.8...2.....1");
+ game.set_from_string ("41593....8..5....7..7..41........36926.3.8.51534........67..2..7....2..3....91786");
view = new SudokuView (game);
view.show ();
main_vbox.pack_start (view);
@@ -106,6 +95,20 @@ public class Application
[CCode (cname = "G_MODULE_EXPORT quit_cb", instance_pos = -1)]
public void quit_cb (Gtk.Widget widget)
{
+/* FIXME: Every time the game exits with Segmentation fault.
+The stack trace is
+#0 0x00007ffff7267b70 in ?? () from /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
+#1 0x00007ffff726a315 in ?? () from /usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
+#2 0x00007ffff68799f0 in g_object_unref () from /usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
+#3 0x0000000000406b98 in application_finalize (obj=<optimized out>) at gnome-sudoku.c:832
+#4 0x0000000000406f26 in application_unref (instance=0x6ba980) at gnome-sudoku.c:869
+#5 application_unref (instance=0x6ba980) at gnome-sudoku.c:865
+#6 0x0000000000407322 in gnome_sudoku_main (args=0x7fffffffe108, args_length1=1) at gnome-sudoku.c:959
+#7 0x00007ffff5fd730d in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6
+#8 0x0000000000405b39 in _start ()
+
+Hope this helps.
+*/
Gtk.main_quit ();
}
@@ -159,135 +162,10 @@ public class Application
view.show_warnings = !view.show_warnings;
}
- private bool row_has_value (int row, int value)
- {
- for (var col = 0; col < 9; col++)
- {
- if (game.cells[row, col].value == value)
- return true;
- }
- return false;
- }
-
- private int row_count_possibilities (int row, int value, out int col_match)
- {
- int n = 0;
- for (var col = 0; col < 9; col++)
- {
- if (game.cells[row, col].value == 0 && game.cells[row, col].can_be (value))
- {
- col_match = col;
- n++;
- }
- }
- return n;
- }
-
- private bool col_has_value (int col, int value)
- {
- for (var row = 0; row < 9; row++)
- {
- if (game.cells[row, col].value == value)
- return true;
- }
- return false;
- }
-
- private int col_count_possibilities (int col, int value, out int row_match)
- {
- int n = 0;
- for (var row = 0; row < 9; row++)
- {
- if (game.cells[row, col].value == 0 && game.cells[row, col].can_be (value))
- {
- row_match = row;
- n++;
- }
- }
- return n;
- }
-
- private bool cell_has_value (int row, int col, int value)
- {
- for (var r = 0; r < 3; r++)
- for (var c = 0; c < 3; c++)
- {
- if (game.cells[row*3+r, col*3+c].value == value)
- return true;
- }
- return false;
- }
-
- private int cell_count_possibilities (int row, int col, int value, out int match_row, out int match_col)
- {
- int n = 0;
- for (var r = 0; r < 3; r++)
- for (var c = 0; c < 3; c++)
- {
- var cell = game.cells[row*3+r, col*3+c];
- if (cell.value == 0 && cell.can_be (value))
- {
- match_row = row*3+r;
- match_col = col*3+c;
- n++;
- }
- }
- return n;
- }
-
[CCode (cname = "G_MODULE_EXPORT hint_cb", instance_pos = -1)]
public void hint_cb (Gtk.Widget widget)
{
- stdout.printf ("TODO: Show hint\n");
-
- // TEMP: Fill any square with only one possible value
- for (int col = 0; col < 9; col++)
- for (int row = 0; row < 9; row++)
- {
- var cell = game.cells[row, col];
- if (cell.value != 0 || cell.n_possibilities != 1)
- continue;
- for (int value = 1; value <= 9; value++)
- if (cell.can_be (value))
- {
- cell.value = value;
- return;
- }
- }
-
- for (int value = 1; value < 9; value++)
- {
- for (int row = 0; row < 9; row++)
- {
- int col = 0;
- if (!row_has_value (row, value) && row_count_possibilities (row, value, out col) == 1)
- {
- game.cells[row, col].value = value;
- return;
- }
- }
- for (int col = 0; col < 9; col++)
- {
- int row = 0;
- if (!col_has_value (col, value) && col_count_possibilities (col, value, out row) == 1)
- {
- game.cells[row, col].value = value;
- return;
- }
- }
- for (int r = 0; r < 3; r++)
- {
- for (int c = 0; c < 3; c++)
- {
- int row = 0, col = 0;
- if (!cell_has_value (r, c, value) && cell_count_possibilities (r, c, value, out row, out col) == 1)
- {
- game.cells[row, col].value = value;
- return;
- }
- }
- }
- }
+ view.hint ();
}
[CCode (cname = "G_MODULE_EXPORT clear_top_notes_cb", instance_pos = -1)]
diff --git a/gnome-sudoku/src/sudoku-game.vala b/gnome-sudoku/src/sudoku-game.vala
index fe4709d..20f4cd0 100644
--- a/gnome-sudoku/src/sudoku-game.vala
+++ b/gnome-sudoku/src/sudoku-game.vala
@@ -1,70 +1,197 @@
-public class SudokuCell
+public class SudokuBoard
{
- public int row;
- public int col;
-
- public bool possible_values[9];
-
- public int n_possibilities
+ /* Implemented in such a way that it can be extended for other sizes ( like 2x3 sudoku or 4x4 sudoku ) instead of normal 3x3 sudoku. */
+
+ public int[,] cells; /* stores the value of cell */
+ public bool[,] is_fixed; /* if the value at location is fixed or not */
+ private bool[,] possible_in_row; /* if specific value is possible in specific row */
+ private bool[,] possible_in_col; /* if specific value is possible in specific col */
+ private bool[,,] possible_in_block; /* if specific value is possible in specific block */
+ private int _row; /* size of sudoku board */
+ private int _col; /* size of sudoku board */
+ private int block_row; /* size of sub-part ( block ) in board */
+ private int block_col; /* size of sub-part ( block ) in board */
+ private int _max_val; /* maximum possible val on board. 9 for 3x3 sudoku*/
+ private int _filled;
+
+ public signal void value_changed (int row, int col, int old_value, int new_value);
+ public signal void value_changing (int row, int col, int old_value, int new_value);
+
+ public int row
{
get
{
- int n = 0;
- for (int i = 1; i <= 9; i++)
- if (possible_values[i-1])
- n++;
- return n;
+ return _row;
}
}
-
- public bool can_be (int value)
+
+ public int col
{
- return possible_values[value-1];
+ get
+ {
+ return _col;
+ }
}
-
- private int _value = 0;
- public int value
+
+ public int max_val
{
- set
+ get
{
- if (is_fixed)
- return;
- if (_value == value)
- return;
- before_value_changed ();
- _value = value;
- value_changed ();
+ return _max_val;
}
- get { return _value; }
}
-
- public bool _is_fixed = false;
- public bool is_fixed
+
+ public int filled
{
- set
- {
- _is_fixed = value;
- value_changed ();
- }
- get { return _is_fixed; }
+ get
+ {
+ return _filled;
+ }
+ }
+
+ public SudokuBoard (int row = 9, int col = 9, int block_row = 3, int block_col = 3)
+ {
+ _row = row;
+ _col = col;
+ this.block_row = block_row;
+ this.block_col = block_col;
+ _max_val = block_row * block_col;
+ cells = new int[_row, _col] ;
+ is_fixed = new bool[_row, _col];
+ /* as any row would contain "col" different values */
+ possible_in_row = new bool[_row, _col];
+ /* as any col would contain "row" different values */
+ possible_in_col = new bool[_col, _row];
+ possible_in_block = new bool[block_row, block_col, block_row * block_col];
+
+ for (int l1 = 0; l1 < _row; l1++)
+ {
+ for (int l2 = 0; l2 < _col; l2++)
+ {
+ cells[l1, l2] = 0;
+ is_fixed[l1, l2] = false;
+ possible_in_row[l1, l2] = true;
+ possible_in_col[l2, l1] = true;
+ }
+ }
+ for (int l1 = 0; l1 < block_row; l1++)
+ {
+ for (int l2 = 0; l2 < block_col; l2++)
+ {
+ for (int l3 = 0; l3 < _max_val;l3++)
+ {
+ possible_in_block[l1, l2, l3] = true;
+ }
+ }
+ }
+ }
+
+ public void set_from_string (string s)
+ {
+ for (int l1 = 0; l1 < s.length; l1++)
+ {
+ /* TODO: extend for all size of sudoku. */
+ if (s[l1] >= '0' && s[l1] <= '9')
+ this.silent_insert (l1 / _col, l1 % _col, s[l1] - '0', true);
+ }
+ }
+
+ public bool is_possible (int row, int col, int val)
+ {
+ --val;
+ return (possible_in_row[row,val] && possible_in_col[col,val] && possible_in_block [ row / block_col, col / block_row, val]);
+ }
+
+ public int count_possible (int row, int col)
+ {
+ int count = 0;
+ if (cells [row, col] != 0)
+ return (0);
+ for (int l = 1; l <= this.max_val; l++)
+ {
+ if (is_possible (row, col, l))
+ count++;
+ }
+ return count;
+ }
+
+ public void silent_insert (int row, int col, int val, bool is_fixed = false)
+ /* This function should only be used by SudokuSolver to stop call to SudokuViewer. */
+ {
+ if (cells[row, col] != 0)
+ /* This should not happen when coded properly ;) */
+ return;
+ if (!is_possible (row, col, val))
+ /* This should not happen when coded properly ;) */
+ return;
+ cells[row, col] = val;
+ this.is_fixed[row, col] = is_fixed;
+ --val;
+ possible_in_row[row, val] = false;
+ possible_in_col[col, val] = false;
+ possible_in_block[row / block_col, col / block_row, val] = false;
+ _filled++;
+ }
+
+ public void insert (int row, int col, int val, bool is_fixed = false)
+ {
+ int old_val = cells[row, col];
+ value_changing (row, col, old_val, val);
+ if (cells [row, col] != 0)
+ silent_remove (row, col);
+ silent_insert (row, col, val, is_fixed);
+ value_changed (row, col, old_val, val);
+ }
+
+ public void silent_remove (int row, int col)
+ /* This function should only be used by SudokuSolver to stop call to SudokuViewer. */
+ {
+ if (is_fixed[row, col])
+ /* This should not happen when coded properly ;) */
+ return;
+ if (cells[row, col] == 0)
+ /* Empty cell, Just pretend everything is okay... */
+ return;
+ int val = cells[row, col];
+ --val;
+ cells[row, col] = 0;
+ possible_in_row[row, val] = true;
+ possible_in_col[col, val] = true;
+ possible_in_block[row / block_col, col / block_row, val] = true;
+ _filled--;
+ }
+
+ public void remove (int row, int col)
+ {
+ if (is_fixed[row, col])
+ /* This should not happen when coded properly ;) */
+ return;
+ if (cells[row, col] == 0)
+ /* Empty cell, Just pretend everything is okay... */
+ return;
+ int old_val = cells[row, col];
+ value_changing (row, col, old_val, 0);
+ silent_remove (row, col);
+ value_changed (row, col, old_val, 0);
}
-
- public signal void value_changed ();
- public signal void before_value_changed ();
- public SudokuCell (int row, int col)
+ public void to_initial_state ()
{
- this.row = row;
- this.col = col;
- for (var i = 0; i < 8; i++)
- possible_values[i] = true;
+ for (int l1 = 0; l1 < _row; l1++)
+ {
+ for (int l2 = 0; l2 < _col; l2++)
+ {
+ if (!is_fixed[l1, l2])
+ remove (l1, l2);
+ }
+ }
}
}
public class SudokuGame
{
- public SudokuCell[,] cells;
-
+ public SudokuBoard board;
+
private struct UndoItem
{
public int row;
@@ -75,56 +202,30 @@ public class SudokuGame
private SList<UndoItem?> undostack;
private SList<UndoItem?> redostack;
- public signal void cell_changed (SudokuCell cell);
+
+ public signal void cell_changed (int row, int col, int old_val, int new_val);
public SudokuGame ()
{
- cells = new SudokuCell[9,9];
+ board = new SudokuBoard ();
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);
- }
+ board.value_changing.connect (update_undo);
+ board.value_changed.connect (cell_changed_cb);
}
-
+
public SudokuGame.from_string (string game)
{
this ();
- set_from_string (game);
+ board.set_from_string (game);
}
-
+
public void set_from_string (string game)
{
- assert (game.length == 81);
- for (var i = 0; i < game.length; i++)
- {
- var col = i % 9;
- var row = i / 9;
- var digit = 0;
- var is_fixed = false;
-
- if (game[i] >= '1' && game[i] <= '9')
- {
- digit = (int) game[i] - '0';
- is_fixed = true;
- }
-
- var cell = cells[row, col];
- cell.is_fixed = false;
- cell.value = digit;
- cell.is_fixed = is_fixed;
- }
-
- /* No undo for preset cells */
+ board.set_from_string (game);
undostack = null;
redostack = null;
}
-
public void undo ()
{
apply_stack (ref undostack, ref redostack);
@@ -137,48 +238,59 @@ public class SudokuGame
public void reset ()
{
- int num = 0;
- for (int i = 0; i < 9; i++)
+ int count = board.filled;
+ board.to_initial_state ();
+ count -= board.filled;
+ add_to_stack (ref undostack, -1, -1, count);
+ }
+
+ public void hint (ref int row, ref int col)
+ {
+ int[,] total_pos = new int [board.row, board.col];
+ int min = board.max_val + 1;
+ int count = 0;
+ for (int l1 = 0; l1 < board.row; l1++)
{
- for (int j = 0; j < 9; j++)
+ for(int l2 = 0; l2 < board.col; l2++)
{
- if (!cells[i,j].is_fixed && cells[i,j].value != 0)
+ total_pos [l1, l2] = board.count_possible (l1, l2);
+ if (total_pos [l1, l2] < min && total_pos [l1, l2] > 0)
{
- cells[i,j].value = 0;
- num++;
+ min = total_pos [l1, l2];
+ count = 0;
}
+ if (total_pos [l1, l2] == min)
+ count++;
}
}
- add_to_stack (ref undostack, -1, -1, num);
- }
-
- private void cell_changed_cb (SudokuCell cell)
- {
- /* Blank out adjacent squares */
- if (cell.value > 0)
+ if (count == 0)
+ return;
+ count = Random.int_range (0, count);
+ for (int l1 = 0; l1 < board.row; l1++)
{
- for (int row = 0; row < 9; row++)
+ for (int l2 = 0; l2 < board.col; l2++)
{
- for (int col = 0; col < 9; col++)
+ if (total_pos[l1, l2] == min)
{
- if (row == cell.row && col == cell.col)
- continue;
- if (row == cell.row ||
- col == cell.col ||
- (row % 3 == cell.row % 3 && col % 3 == cell.col % 3))
+ if (count-- == 0)
{
- cells[row, col].possible_values[cell.value-1] = false;
+ row = l1;
+ col = l2;
+ return;
}
- }
+ }
}
}
-
- cell_changed (cell);
}
- private void update_undo (SudokuCell cell)
+ public void cell_changed_cb (SudokuBoard board, int row, int col, int old_val, int new_val)
{
- add_to_stack (ref undostack, cell.row, cell.col, cell.value);
+ cell_changed (row, col, old_val, new_val);
+ }
+
+ public void update_undo (SudokuBoard board, int row, int col, int old_val, int new_val)
+ {
+ add_to_stack (ref undostack, row, col, old_val);
redostack = null;
}
@@ -191,26 +303,25 @@ public class SudokuGame
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;
+ board.value_changing.disconnect (update_undo);
+ add_to_stack (ref to, from.data.row, from.data.col, board.cells [from.data.row, from.data.col] );
+ board.silent_remove (from.data.row, from.data.col);
+ board.insert (from.data.row, from.data.col, from.data.val);
from.remove (from.data);
- cell.before_value_changed.connect (update_undo);
+ board.value_changing.connect (update_undo);
}
/* Undoing reset action */
else
{
int num = from.data.val;
from.remove (from.data);
- for (int i = 0; i < num; i++)
+ for (int l = 0; l < num; l++)
apply_stack (ref from, ref to);
add_to_stack (ref to, -1, -1, num);
}
+
}
}
diff --git a/gnome-sudoku/src/sudoku-generator.vala b/gnome-sudoku/src/sudoku-generator.vala
index b47a240..109e9c6 100644
--- a/gnome-sudoku/src/sudoku-generator.vala
+++ b/gnome-sudoku/src/sudoku-generator.vala
@@ -18,3 +18,97 @@ public class SudokuGenerator
return new SudokuGame.from_string (x);
}
}
+
+public class SudokuSolver
+{
+ private SudokuBoard board;
+
+ public SudokuSolver (ref SudokuBoard board)
+ {
+ this.board = board;
+ }
+
+ public bool has_solution ()
+ /*Check if current SudokuBoard has at lesat one solution or not*/
+ {
+ int solutions = 0;
+ solve (-1, -1, -1, -1, ref solutions);
+ return (solutions > 0);
+ }
+
+ public bool has_unique_solution ()
+ /*Check if current SudokuBoard has unique solution or not*/
+ {
+ int solutions = 0;
+ solve (-1, -1, -1, -1, ref solutions);
+ return (solutions == 1);
+ }
+
+ public bool has_many_solution ()
+ /*Check if current SudokuBoard has more thatn one solution or not*/
+ {
+ int solutions = 0;
+ solve (-1, -1, -1, -1, ref solutions);
+ return (solutions > 1);
+ }
+
+ private void solve (int row, int col, int no, int filled, ref int solution)
+ {
+ if (filled == -1)
+ {
+ filled = board.filled;
+ }
+ if (filled == board.row * board.col)
+ {
+ solution++;
+ print_sol ();
+ return;
+ }
+ if (row == -1 || col == -1)
+ {
+ for (int l1 = 0; l1 < board.row; l1++)
+ {
+ for (int l2 = 0;l2 < board.col; l2++)
+ {
+ if (board.cells[l1, l2] == 0)
+ {
+ solve (l1, l2, no, filled, ref solution);
+ return;
+ }
+ }
+ }
+ }
+ if (no == -1)
+ {
+ for (int l1 = 1; l1 <= board.max_val; l1++)
+ {
+ if (board.is_possible (row, col, l1))
+ {
+ solve (row, col, l1, filled, ref solution);
+ if (solution > 1)
+ /*Break at solutions == 2 as we don't need exact count of possible solutions*/
+ return;
+ }
+ }
+ return;
+ }
+ board.silent_insert (row, col, no);
+ solve (-1, -1, -1, filled + 1, ref solution);
+ board.silent_remove (row, col);
+ }
+
+ private void print_sol ()
+ /* For checking purpose only. Should be removed from final release */
+ {
+ stdout.printf ("Solution found..\n");
+ for (int l1=0;l1<9;l1++)
+ {
+ for (int l2=0;l2<9;l2++)
+ {
+ stdout.printf ("%d ",board.cells[l1,l2]);
+ }
+ stdout.printf ("\n");
+ }
+ stdout.flush ();
+ }
+}
diff --git a/gnome-sudoku/src/sudoku-view.vala b/gnome-sudoku/src/sudoku-view.vala
index b0399a2..0410061 100644
--- a/gnome-sudoku/src/sudoku-view.vala
+++ b/gnome-sudoku/src/sudoku-view.vala
@@ -6,52 +6,107 @@ private class SudokuCellView : Gtk.DrawingArea
private Gtk.Window? popup = null;
- private SudokuCell _cell;
- public SudokuCell cell
+ private SudokuBoard board;
+ private int _row;
+ private int _col;
+
+ public int row
{
+ get
+ {
+ return _row;
+ }
set
{
- _cell = value;
- _cell.value_changed.connect (value_changed_cb);
- value_changed_cb (value);
+ _row = value;
}
- get { return _cell; }
}
- public string top_notes { set; get; default = ""; }
- public string bottom_notes { set; get; default = ""; }
-
- private string _text;
- public string text
+ public int col
{
+ get
+ {
+ return _col;
+ }
set
{
- _text = value;
- layout = create_pango_layout (_text);
- layout.set_font_description (style.font_desc);
- queue_draw ();
+ _col = value;
}
- get { return _text; }
}
public int value
{
+ get
+ {
+ return board.cells [_row, _col];
+ }
set
{
+ if (is_fixed)
+ {
+ text = "%d".printf (board.cells [_row, _col]);
+ return;
+ }
if (value == 0)
+ {
text = "";
- else
+ if (board.cells [_row, _col] != 0)
+ board.remove (_row, _col);
+ return;
+ }
+ if (value == board.cells [_row, _col])
+ {
text = "%d".printf (value);
+ return;
+ }
+ if (board.is_possible(_row, _col, value))
+ {
+ board.insert (_row, _col, value);
+ }
+ else
+ {
+ stdout.printf("TODO: Notification Invalid value.\n");
+ /* TODO: Notify user. Wrong value selected */
+ }
+ }
+ }
+
+ public bool is_fixed
+ {
+ get
+ {
+ return board.is_fixed[_row, _col];
}
}
- public SudokuCellView ()
+ public string top_notes { set; get; default = ""; }
+ public string bottom_notes { set; get; default = ""; }
+
+ private string _text;
+ public string text
{
+ set
+ {
+ _text = value;
+ layout = create_pango_layout (_text);
+ layout.set_font_description (style.font_desc);
+ queue_draw ();
+ }
+ get { return _text; }
+ }
+
+ public SudokuCellView (int row, int col, ref SudokuBoard board)
+ {
+ this.board = board;
+ this._row = row;
+ this._col = col;
can_focus = true;
style.font_desc.set_size (Pango.SCALE * 13);
text = "";
+ this.value = board.cells[_row, _col];
events = Gdk.EventMask.EXPOSURE_MASK | Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.KEY_PRESS_MASK;
focus_out_event.connect (focus_out_cb);
+ board.value_changed.connect (value_changed_cb);
}
public override void get_preferred_width (out int minimal_width, out int natural_width)
@@ -80,7 +135,6 @@ private class SudokuCellView : Gtk.DrawingArea
grab_focus ();
return true;
}
-
if (event.y / get_allocated_height () < 0.25)
show_note_editor (0);
else if (event.y / get_allocated_height () > 0.75)
@@ -95,7 +149,8 @@ private class SudokuCellView : Gtk.DrawingArea
{
if (popup != null)
return;
-
+ if (is_fixed)
+ return;
popup = new Gtk.Window (Gtk.WindowType.POPUP);
var table = new Gtk.Table (3, 3, false);
@@ -117,7 +172,7 @@ private class SudokuCellView : Gtk.DrawingArea
label.show ();
button.clicked.connect (() => {
- cell.value = n;
+ value = n;
hide_popup ();
});
@@ -161,6 +216,8 @@ private class SudokuCellView : Gtk.DrawingArea
{
if (popup != null)
return;
+ if (is_fixed)
+ return;
editing_notes = true;
popup = new Gtk.Window (Gtk.WindowType.TOPLEVEL);
@@ -192,6 +249,7 @@ private class SudokuCellView : Gtk.DrawingArea
popup.show_all ();
popup.get_size (null, out height);
popup.move (x, y + top * (get_allocated_height () - height));
+ /* FIXME: entry doesn't get keyboard focus when note editor is shown and does not hide if focus is lost before clicking in entry. */
}
private void hide_note_editor (Gtk.Entry entry, int top)
@@ -214,17 +272,17 @@ private class SudokuCellView : Gtk.DrawingArea
public override bool key_press_event (Gdk.EventKey event)
{
- // FIXME: Can't find vala bindings to Gdk keyvals...
+ /* FIXME: Can't find vala bindings to Gdk keyvals... */
if (event.keyval >= 49 /* 1 */ && event.keyval <= 58 /* 9 */)
{
- cell.value = (int)event.keyval - 48;
+ value = (int)event.keyval - 48;
return true;
}
if (event.keyval == 48 || event.keyval == 65288 /* backspace */ || event.keyval == 65535 /* delete */)
{
- cell.value = 0;
+ value = 0;
return true;
}
@@ -241,7 +299,7 @@ private class SudokuCellView : Gtk.DrawingArea
{
if (is_focus)
Gdk.cairo_set_source_color (c, style.base[Gtk.StateType.SELECTED]);
- else if (cell.is_fixed)
+ else if (is_fixed)
c.set_source_rgb (0.8, 0.8, 0.8);
else
c.set_source_rgb (1.0, 1.0, 1.0);
@@ -279,10 +337,18 @@ private class SudokuCellView : Gtk.DrawingArea
return false;
}
- private void value_changed_cb (SudokuCell cell)
+ public void value_changed_cb (SudokuBoard b, int row, int col, int old_val, int new_val)
{
- value = cell.value;
- can_focus = !cell.is_fixed;
+ if(row == this.row && col == this.col)
+ {
+ this.value = new_val;
+ }
+ }
+
+ public void hint()
+ {
+ /* TODO: Show hint properly. */
+ stdout.printf ("TODO: Show hint properly.\nHint at %d %d\n", _row + 1, _col + 1);
}
}
@@ -317,9 +383,8 @@ public class SudokuView : Gtk.AspectFrame
for (int row = 0; row < 9; row++)
for (int col = 0; col < 9; col++)
{
- var cell = new SudokuCellView ();
+ var cell = new SudokuCellView (row, col, ref game.board);
cells[row, col] = cell;
- cell.cell = game.cells[row, col];
cell.show ();
table.attach_defaults (cell, col, col+1, row, row+1);
}
@@ -347,6 +412,13 @@ public class SudokuView : Gtk.AspectFrame
get { return _show_warnings; }
set { _show_warnings = value; }
}
+
+ public void hint ()
+ {
+ int row=0, col=0;
+ game.hint (ref row, ref col);
+ cells [row, col].hint ();
+ }
public void clear_top_notes ()
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]