[gnome-sudoku/manual-puzzle-creator] Create the basic puzzle creation feature
- From: Parin Porecha <parinporecha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-sudoku/manual-puzzle-creator] Create the basic puzzle creation feature
- Date: Sat, 4 Apr 2015 18:59:52 +0000 (UTC)
commit 0fdc430d1132a22f0b0c06ac7cd1e67c3000d366
Author: Parin Porecha <parinporecha gmail com>
Date: Sun Apr 5 00:26:36 2015 +0530
Create the basic puzzle creation feature
https://bugzilla.gnome.org/show_bug.cgi?id=559298
data/gnome-sudoku.ui | 33 ++++++++++++++++-
lib/sudoku-board.vala | 22 ++++++++++-
lib/sudoku-game.vala | 65 ++++++++++++++++++++++++++-----
lib/sudoku-generator.vala | 4 +-
lib/sudoku-saver.vala | 6 ++-
src/gnome-sudoku.vala | 91 ++++++++++++++++++++++++++++++++++++--------
src/sudoku-view.vala | 38 ++++++++++++-------
7 files changed, 213 insertions(+), 46 deletions(-)
---
diff --git a/data/gnome-sudoku.ui b/data/gnome-sudoku.ui
index 094d139..bdf0e2e 100644
--- a/data/gnome-sudoku.ui
+++ b/data/gnome-sudoku.ui
@@ -122,7 +122,6 @@
<property name="visible">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
- <property name="homogeneous">True</property>
<property name="margin">0</property>
<property name="width-request">350</property>
<property name="height-request">350</property>
@@ -182,6 +181,20 @@
<property name="position">3</property>
</packing>
</child>
+ <child>
+ <object class="GtkButton" id="create_game_button">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="margin_top">30</property>
+ <property name="label" translatable="yes">_Create your own
puzzle</property>
+ <property name="action-name">app.create-game</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
</object> <!-- End of start_box -->
<packing>
<property name="name">start_box</property>
@@ -267,6 +280,24 @@
<property name="position">2</property>
</packing>
</child>
+ <child>
+ <object class="GtkButton" id="play_custom_game_button">
+ <property name="visible">False</property>
+ <property name="use_underline">True</property>
+ <property name="label" translatable="yes">_Start
Playing</property>
+ <property name="halign">fill</property>
+ <property name="valign">center</property>
+ <property
name="action-name">app.play-custom-game</property>
+ <property name="tooltip-text"
translatable="yes">Start playing the custom puzzle you have created</property>
+ <property name="width-request">120</property>
+ <property name="height-request">60</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
</object> <!-- End of controls_box -->
<packing>
<property name="expand">False</property>
diff --git a/lib/sudoku-board.vala b/lib/sudoku-board.vala
index 500ceea..4507ac8 100644
--- a/lib/sudoku-board.vala
+++ b/lib/sudoku-board.vala
@@ -67,6 +67,11 @@ public class SudokuBoard : Object
/* the number of fixed squares on the board */
public int fixed { get; private set; }
+ public int size
+ {
+ get { return rows * cols; }
+ }
+
public bool complete
{
get { return filled == cols * rows && !broken; }
@@ -77,6 +82,11 @@ public class SudokuBoard : Object
return filled == fixed && n_earmarks == 0;
}
+ public bool is_fully_filled ()
+ {
+ return filled == cols * rows;
+ }
+
public signal void completed ();
/* The set of coordinates on the board which are invalid */
@@ -377,6 +387,9 @@ public class SudokuBoard : Object
}
filled--;
+
+ if (is_fixed)
+ fixed--;
}
public Set<Coord?> get_occurances(Gee.List<Coord?> coords, int val)
@@ -587,7 +600,8 @@ public enum DifficultyCategory {
EASY,
MEDIUM,
HARD,
- VERY_HARD;
+ VERY_HARD,
+ CUSTOM;
public string to_string ()
{
@@ -603,6 +617,8 @@ public enum DifficultyCategory {
return _("Hard Difficulty");
case VERY_HARD:
return _("Very Hard Difficulty");
+ case CUSTOM:
+ return _("Custom Puzzle");
default:
assert_not_reached ();
}
@@ -622,6 +638,8 @@ public enum DifficultyCategory {
return "Hard Difficulty";
case VERY_HARD:
return "Very Hard Difficulty";
+ case CUSTOM:
+ return "Custom Puzzle";
default:
assert_not_reached ();
}
@@ -641,6 +659,8 @@ public enum DifficultyCategory {
return HARD;
case "Very Hard Difficulty":
return VERY_HARD;
+ case "Custom Puzzle":
+ return CUSTOM;
default:
warning ("Could not parse difficulty level. Falling back to Easy difficulty");
return EASY;
diff --git a/lib/sudoku-game.vala b/lib/sudoku-game.vala
index 82df700..1e6ce4c 100644
--- a/lib/sudoku-game.vala
+++ b/lib/sudoku-game.vala
@@ -24,6 +24,7 @@ using Gee;
public class SudokuGame : Object
{
public SudokuBoard board;
+ public GameMode mode;
public GLib.Timer timer;
private uint clock_timeout;
@@ -66,17 +67,24 @@ public class SudokuGame : Object
public SudokuGame (SudokuBoard board)
{
this.board = board;
+ this.mode = GameMode.PLAY;
timer = new Timer();
undostack = new ArrayList<UndoItem?> ();
redostack = new ArrayList<UndoItem?> ();
- board.completed.connect (() => stop_clock ());
}
public void insert (int row, int col, int val)
{
var old_val = board[row, col];
update_undo (row, col, old_val, val);
- board.insert (row, col, val);
+
+ if (mode == GameMode.CREATE) {
+ board.insert (row, col, val, true);
+ board.is_fixed[row, col] = true;
+ }
+ else
+ board.insert (row, col, val);
+
cell_changed (row, col, old_val, val);
}
@@ -84,10 +92,25 @@ public class SudokuGame : Object
{
int old_val = board[row, col];
update_undo (row, col, old_val, 0);
- board.remove (row, col);
+
+ if (mode == GameMode.CREATE) {
+ board.remove (row, col, true);
+ board.is_fixed[row, col] = false;
+ }
+ else
+ board.remove (row, col);
+
cell_changed (row, col, old_val, 0);
}
+ public bool is_empty ()
+ {
+ if (mode == GameMode.CREATE)
+ return board.filled == 0;
+ else
+ return board.is_empty ();
+ }
+
public void undo ()
{
apply_stack (undostack, redostack);
@@ -108,11 +131,12 @@ public class SudokuGame : Object
{
for (var l2 = 0; l2 < board.cols; l2++)
{
- if (!board.is_fixed[l1, l2])
- {
- board.remove (l1, l2);
- cell_changed (l1, l2, board.get (l1, l2), 0);
- }
+ if (mode == GameMode.PLAY && board.is_fixed[l1, l2])
+ continue;
+
+ board.remove (l1, l2, board.is_fixed[l1, l2]);
+ board.is_fixed[l1, l2] = false;
+ cell_changed (l1, l2, board.get (l1, l2), 0);
}
}
board.broken_coords.clear ();
@@ -143,9 +167,23 @@ public class SudokuGame : Object
var top = from.remove_at (from.size - 1);
int old_val = board [top.row, top.col];
add_to_stack (to, top.row, top.col, old_val);
- board.remove (top.row, top.col);
- if (top.val != 0)
- board.insert (top.row, top.col, top.val);
+
+ if (mode == GameMode.CREATE) {
+ board.remove (top.row, top.col, board.is_fixed[top.row, top.col]);
+ board.is_fixed[top.row, top.col] = false;
+ }
+ else
+ board.remove (top.row, top.col);
+
+ if (top.val != 0) {
+ if (mode == GameMode.CREATE) {
+ board.insert (top.row, top.col, top.val, board.is_fixed[top.row, top.col]);
+ board.is_fixed[top.row, top.col] = true;
+ }
+ else
+ board.insert (top.row, top.col, top.val);
+ }
+
cell_changed (top.row, top.col, old_val, top.val);
}
@@ -189,3 +227,8 @@ public class SudokuGame : Object
timeout_cb ();
}
}
+
+public enum GameMode {
+ PLAY,
+ CREATE;
+}
diff --git a/lib/sudoku-generator.vala b/lib/sudoku-generator.vala
index 65f30c8..1c1db49 100644
--- a/lib/sudoku-generator.vala
+++ b/lib/sudoku-generator.vala
@@ -66,7 +66,9 @@ public class SudokuGenerator : Object
private static SudokuBoard generate_board (DifficultyCategory category)
{
var board = new SudokuBoard ();
- int[] puzzle = QQwing.generate_puzzle ((int) category);
+ int[] puzzle = new int[board.rows * board.cols];
+ if (category != DifficultyCategory.CUSTOM)
+ puzzle = QQwing.generate_puzzle ((int) category);
for (var row = 0; row < board.rows; row++)
for (var col = 0; col < board.cols; col++)
diff --git a/lib/sudoku-saver.vala b/lib/sudoku-saver.vala
index 22cca26..31f78df 100644
--- a/lib/sudoku-saver.vala
+++ b/lib/sudoku-saver.vala
@@ -106,8 +106,12 @@ public class SudokuSaver : Object
builder.begin_object ();
builder.set_member_name ("difficulty_category");
builder.add_string_value (board.difficulty_category.to_untranslated_string ());
+
builder.set_member_name ("time_elapsed");
- builder.add_double_value (game.get_total_time_played ());
+ if (game.mode == GameMode.CREATE)
+ builder.add_double_value (0);
+ else
+ builder.add_double_value (game.get_total_time_played ());
builder.set_member_name ("cells");
builder.begin_array ();
diff --git a/src/gnome-sudoku.vala b/src/gnome-sudoku.vala
index 48c6bcb..1ec9ed8 100644
--- a/src/gnome-sudoku.vala
+++ b/src/gnome-sudoku.vala
@@ -28,6 +28,7 @@ public class Sudoku : Gtk.Application
private bool is_tiled;
private int window_width;
private int window_height;
+ private Gtk.Button play_custom_game_button;
private Gtk.Button play_pause_button;
private Gtk.Label play_pause_label;
private Gtk.Label clock_label;
@@ -53,19 +54,23 @@ public class Sudoku : Gtk.Application
private SimpleAction print_action;
private SimpleAction print_multiple_action;
private SimpleAction pause_action;
+ private SimpleAction play_custom_game_action;
private SimpleAction new_game_action;
private bool show_possibilities = false;
+ private GameMode current_game_mode = GameMode.PLAY;
private const GLib.ActionEntry action_entries[] =
{
{"new-game", new_game_cb },
{"start-game", start_game_cb, "i" },
+ {"create-game", create_game_cb },
{"reset", reset_cb },
{"back", back_cb },
{"undo", undo_cb },
{"redo", redo_cb },
{"print", print_cb },
+ {"play-custom-game", play_custom_game_cb },
{"pause", toggle_pause_cb },
{"print-multiple", print_multiple_cb },
{"help", help_cb },
@@ -134,7 +139,7 @@ public class Sudoku : Gtk.Application
settings = new GLib.Settings ("org.gnome.sudoku");
var action = settings.create_action ("show-warnings");
action.notify["state"].connect (() => {
- if (view != null)
+ if (view != null && current_game_mode == GameMode.PLAY)
view.show_warnings = settings.get_boolean ("show-warnings");
});
add_action (action);
@@ -178,6 +183,7 @@ public class Sudoku : Gtk.Application
back_button = (Button) builder.get_object ("back_button");
clock_label = (Gtk.Label) builder.get_object ("clock_label");
clock_image = (Gtk.Image) builder.get_object ("clock_image");
+ play_custom_game_button = (Gtk.Button) builder.get_object ("play_custom_game_button");
play_pause_button = (Gtk.Button) builder.get_object ("play_pause_button");
play_pause_label = (Gtk.Label) builder.get_object ("play_pause_label");
@@ -188,6 +194,7 @@ public class Sudoku : Gtk.Application
print_action = (SimpleAction) lookup_action ("print");
print_multiple_action = (SimpleAction) lookup_action ("print-multiple");
pause_action = (SimpleAction) lookup_action ("pause");
+ play_custom_game_action = (SimpleAction) lookup_action ("play-custom-game");
if (!is_desktop ("Unity"))
{
@@ -202,8 +209,11 @@ public class Sudoku : Gtk.Application
saver = new SudokuSaver ();
var savegame = saver.get_savedgame ();
- if (savegame != null)
+ if (savegame != null) {
+ if (savegame.board.difficulty_category == DifficultyCategory.CUSTOM)
+ current_game_mode = savegame.board.filled == savegame.board.fixed ? GameMode.CREATE :
GameMode.PLAY;
start_game (savegame.board);
+ }
else
show_new_game_screen ();
}
@@ -217,10 +227,10 @@ public class Sudoku : Gtk.Application
{
if (game != null)
{
- if (!game.board.is_empty () && !game.board.complete)
+ if (!game.is_empty () && !game.board.complete)
saver.save_game (game);
- if (game.board.is_empty () && saver.get_savedgame () != null)
+ if (game.is_empty () && saver.get_savedgame () != null)
{
var file = File.new_for_path (SudokuSaver.savegame_file);
@@ -274,13 +284,20 @@ public class Sudoku : Gtk.Application
else if (game.get_total_time_played () > 0)
{
display_pause_button ();
- clear_action.set_enabled (!game.board.is_empty ());
+ clear_action.set_enabled (!game.is_empty ());
undo_action.set_enabled (!game.is_undostack_null ());
redo_action.set_enabled (!game.is_redostack_null ());
new_game_action.set_enabled (true);
}
}
+ private void play_custom_game_cb ()
+ {
+ current_game_mode = GameMode.PLAY;
+ game.stop_clock ();
+ start_game (game.board);
+ }
+
private void toggle_pause_cb ()
{
if (game.paused)
@@ -315,27 +332,31 @@ public class Sudoku : Gtk.Application
private void start_game (SudokuBoard board)
{
- undo_action.set_enabled (false);
- redo_action.set_enabled (false);
-
if (view != null)
game_box.remove (view);
show_game_view ();
game = new SudokuGame (board);
+ game.mode = current_game_mode;
- headerbar.title = board.difficulty_category.to_string ();
+ undo_action.set_enabled (false);
+ redo_action.set_enabled (false);
+ set_headerbar_title ();
+ clear_action.set_enabled (!game.is_empty ());
+ play_custom_game_action.set_enabled (!game.is_empty ());
game.tick.connect (tick_cb);
game.paused_changed.connect (paused_changed_cb);
-
game.start_clock ();
view = new SudokuView (game);
view.set_size_request (480, 480);
view.show_possibilities = show_possibilities;
- view.show_warnings = settings.get_boolean ("show-warnings");
+ if (current_game_mode == GameMode.CREATE)
+ view.show_warnings = true;
+ else
+ view.show_warnings = settings.get_boolean ("show-warnings");
view.highlighter = settings.get_boolean ("highlighter");
view.show ();
@@ -344,10 +365,17 @@ public class Sudoku : Gtk.Application
game.cell_changed.connect (() => {
undo_action.set_enabled (!game.is_undostack_null ());
redo_action.set_enabled (!game.is_redostack_null ());
- clear_action.set_enabled (!game.board.is_empty ());
+ clear_action.set_enabled (!game.is_empty ());
+ play_custom_game_action.set_enabled (!game.is_empty () && !game.board.is_fully_filled ());
});
+ if (current_game_mode == GameMode.CREATE)
+ return;
+
game.board.completed.connect (() => {
+ play_custom_game_button.visible = false;
+ game.stop_clock ();
+
for (var i = 0; i < game.board.rows; i++)
for (var j = 0; j < game.board.cols; j++)
view.can_focus = false;
@@ -379,7 +407,6 @@ public class Sudoku : Gtk.Application
private void show_new_game_screen ()
{
main_stack.set_visible_child_name ("start_box");
- clear_action.set_enabled (false);
back_button.visible = game != null;
undo_redo_box.visible = false;
headerbar.title = _("Select Difficulty");
@@ -395,6 +422,19 @@ public class Sudoku : Gtk.Application
show_new_game_screen ();
}
+ private void create_game_cb ()
+ {
+ current_game_mode = GameMode.CREATE;
+ SudokuGenerator.generate_boards_async.begin (1, DifficultyCategory.CUSTOM, null, (obj, res) => {
+ try {
+ var gen_boards = SudokuGenerator.generate_boards_async.end (res);
+ start_game (gen_boards[0]);
+ } catch (Error e) {
+ error ("Error: %s", e.message);
+ }
+ });
+ }
+
private void start_game_cb (SimpleAction action, Variant? difficulty)
{
// Since we cannot have enums in .ui file, the 'action-target' property
@@ -404,6 +444,7 @@ public class Sudoku : Gtk.Application
var selected_difficulty = (DifficultyCategory) difficulty.get_int32 ();
back_button.sensitive = false;
+ current_game_mode = GameMode.PLAY;
SudokuGenerator.generate_boards_async.begin (1, selected_difficulty, null, (obj, res) => {
try {
@@ -423,8 +464,8 @@ public class Sudoku : Gtk.Application
dialog.response.connect ((response_id) => {
if (response_id == ResponseType.OK)
{
- view.clear ();
game.reset ();
+ view.clear ();
undo_action.set_enabled (false);
redo_action.set_enabled (false);
}
@@ -444,16 +485,32 @@ public class Sudoku : Gtk.Application
clock_image.show ();
if (game != null)
- {
game.resume_clock ();
- clear_action.set_enabled (!game.board.is_empty ());
- headerbar.title = game.board.difficulty_category.to_string ();
+
+ if (current_game_mode == GameMode.PLAY) {
+ play_custom_game_button.visible = false;
+ play_pause_button.visible = true;
}
+ else {
+ clock_label.hide ();
+ clock_image.hide ();
+ play_custom_game_button.visible = true;
+ play_pause_button.visible = false;
+ }
+ }
+
+ private void set_headerbar_title ()
+ {
+ if (current_game_mode == GameMode.PLAY)
+ headerbar.title = game.board.difficulty_category.to_string ();
+ else
+ headerbar.title = _("Create Puzzle");
}
private void back_cb ()
{
show_game_view ();
+ set_headerbar_title ();
}
private void undo_cb ()
diff --git a/src/sudoku-view.vala b/src/sudoku-view.vala
index 1b7ec1b..c4b161e 100644
--- a/src/sudoku-view.vala
+++ b/src/sudoku-view.vala
@@ -46,7 +46,8 @@ private class SudokuCellView : Gtk.DrawingArea
string text = "%d".printf (game.board [row, col]);
layout = create_pango_layout (text);
layout.set_font_description (style.font_desc);
- return;
+ if (game.mode == GameMode.PLAY)
+ return;
}
if (value == 0)
{
@@ -55,7 +56,8 @@ private class SudokuCellView : Gtk.DrawingArea
layout.set_font_description (style.font_desc);
if (game.board [row, col] != 0)
game.remove (row, col);
- return;
+ if (game.mode == GameMode.PLAY)
+ return;
}
if (value == game.board [row, col])
{
@@ -115,7 +117,7 @@ private class SudokuCellView : Gtk.DrawingArea
can_focus = true;
events = EventMask.EXPOSURE_MASK | EventMask.BUTTON_PRESS_MASK | EventMask.KEY_PRESS_MASK;
- if (is_fixed)
+ if (is_fixed && game.mode == GameMode.PLAY)
return;
focus_out_event.connect (focus_out_cb);
@@ -129,7 +131,7 @@ private class SudokuCellView : Gtk.DrawingArea
if (!is_focus)
grab_focus ();
- if (is_fixed || game.paused)
+ if (game.mode == GameMode.PLAY && (is_fixed || game.paused))
return false;
if (popover != null || earmark_popover != null)
@@ -140,12 +142,12 @@ private class SudokuCellView : Gtk.DrawingArea
if (event.button == 1) // Left-Click
{
- if (!_show_possibilities && (event.state & ModifierType.CONTROL_MASK) > 0)
+ if (!_show_possibilities && (event.state & ModifierType.CONTROL_MASK) > 0 && game.mode ==
GameMode.PLAY)
show_earmark_picker ();
else
show_number_picker ();
}
- else if (!_show_possibilities && event.button == 3) // Right-Click
+ else if (!_show_possibilities && event.button == 3 && game.mode == GameMode.PLAY) //
Right-Click
show_earmark_picker ();
return false;
@@ -272,7 +274,7 @@ private class SudokuCellView : Gtk.DrawingArea
public override bool key_press_event (Gdk.EventKey event)
{
- if (is_fixed || game.paused)
+ if (game.mode == GameMode.PLAY && (is_fixed || game.paused))
return false;
string k_name = Gdk.keyval_name (event.keyval);
int k_no = int.parse (k_name);
@@ -281,7 +283,7 @@ private class SudokuCellView : Gtk.DrawingArea
k_no = key_map_keypad (k_name);
if (k_no >= 1 && k_no <= 9)
{
- if ((event.state & ModifierType.CONTROL_MASK) > 0)
+ if ((event.state & ModifierType.CONTROL_MASK) > 0 && game.mode == GameMode.PLAY)
{
var new_state = !game.board.is_earmark_enabled (row, col, k_no);
if (earmark_picker == null)
@@ -357,7 +359,7 @@ private class SudokuCellView : Gtk.DrawingArea
c.restore ();
}
- if (is_fixed)
+ if (is_fixed && game.mode == GameMode.PLAY)
return false;
if (!_show_possibilities)
@@ -417,6 +419,14 @@ private class SudokuCellView : Gtk.DrawingArea
if (row == this.row && col == this.col)
{
this.value = new_val;
+
+ if (game.mode == GameMode.CREATE) {
+ if (_selected)
+ background_color = selected_bg_color;
+ else
+ background_color = is_fixed ? fixed_cell_color : free_cell_color;
+ }
+
notify_property ("value");
}
}
@@ -427,6 +437,11 @@ private class SudokuCellView : Gtk.DrawingArea
}
}
+public const RGBA fixed_cell_color = {0.8, 0.8, 0.8, 0};
+public const RGBA free_cell_color = {1.0, 1.0, 1.0, 1.0};
+public const RGBA highlight_color = {0.93, 0.93, 0.93, 0};
+public const RGBA selected_bg_color = {0.7, 0.8, 0.9};
+
public class SudokuView : Gtk.AspectFrame
{
public SudokuGame game;
@@ -438,11 +453,6 @@ public class SudokuView : Gtk.AspectFrame
private Gtk.DrawingArea drawing;
private Gtk.Grid grid;
- private const RGBA fixed_cell_color = {0.8, 0.8, 0.8, 0};
- private const RGBA free_cell_color = {1.0, 1.0, 1.0, 1.0};
- private const RGBA highlight_color = {0.93, 0.93, 0.93, 0};
- private const RGBA selected_bg_color = {0.7, 0.8, 0.9};
-
private int selected_row = 0;
private int selected_col = 0;
private void set_selected (int cell_row, int cell_col)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]