[gnome-sudoku/vala-port] Implemented printing multiple sudokus feature
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-sudoku/vala-port] Implemented printing multiple sudokus feature
- Date: Sun, 24 Nov 2013 22:24:18 +0000 (UTC)
commit 19ad23c31ae565a923fe05dba91e836d742b54f8
Author: Parin Porecha <parinporecha gmail com>
Date: Sun Nov 24 18:35:00 2013 +0000
Implemented printing multiple sudokus feature
https://bugzilla.gnome.org/show_bug.cgi?id=633464
TODO | 11 +-
data/print-games.ui | 367 +++++++++++++++++++++++++++++++++++++
src/gnome-sudoku.gresource.xml.in | 1 +
src/gnome-sudoku.vala | 5 +-
src/sudoku-board.vala | 28 +++-
src/sudoku-printer.vala | 233 ++++++++++++++++++++----
src/sudoku-solver.vala | 19 ++-
src/sudoku-store.vala | 36 +++-
8 files changed, 651 insertions(+), 49 deletions(-)
---
diff --git a/TODO b/TODO
index e768429..05842d8 100644
--- a/TODO
+++ b/TODO
@@ -6,8 +6,6 @@ about dialog: artwork has "placeholder"
"show possible numbers" results in critical warning. No result
"warn about unfillable squares" results in critical warning. No result
-Print multiple: just writes TODO to terminal
-
Undo/redo are clickable, even before starting a game
"Saved game" shown in start screen, even if none exist
@@ -19,6 +17,13 @@ The "Back" back seems to function like undo. Is that the case?
The ingame Help: (I like it!)
Should maybe have different name. Help is the common word for opening the help manual.
Left align the text
- Perhaps start with a general description of the method, instead of repeating the same sentance for each
line.
+ Perhaps start with a general description of the method, instead of repeating the same sentence for each
line.
No way to save a game
+
+No way to know if a game has already been played or not:
+ For this SudokuTracker class needs to be ported. Once it is complete, enable the corresponding options -
+ 'MarkAsPlayedToggle' and 'includeOldGamesToggle' in data/print_games.ui (for multiple print dialog)
+
+Currently we only read sudokus from data files:
+ We need to complete the port of SudokuGenerator class to be able to generate sudokus as desired.
diff --git a/data/print-games.ui b/data/print-games.ui
new file mode 100644
index 0000000..5c4e415
--- /dev/null
+++ b/data/print-games.ui
@@ -0,0 +1,367 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.0"/>
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkAdjustment" id="adjustment1">
+ <property name="lower">1</property>
+ <property name="upper">100</property>
+ <property name="value">4</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkAdjustment" id="adjustment2">
+ <property name="lower">1</property>
+ <property name="upper">9</property>
+ <property name="value">1</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ </object>
+ <object class="GtkDialog" id="dialog">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="title" translatable="yes">Print Sudokus</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child internal-child="action_area">
+ <object class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancelbutton1">
+ <property name="label">gtk-cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="okbutton1">
+ <property name="label">gtk-print</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">12</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Print Games</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ <attribute name="scale" value="1.2"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="left_padding">24</property>
+ <child>
+ <object class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <child>
+ <object class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Number of sudoku to print: </property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">sudokusToPrintSpinButton</property>
+ </object>
+ <packing>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Sudokus per page: </property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">sudokusPerPageSpinButton</property>
+ </object>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="sudokusToPrintSpinButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <property name="adjustment">adjustment1</property>
+ <property name="climb_rate">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="y_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinButton" id="sudokusPerPageSpinButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
+ <property name="adjustment">adjustment2</property>
+ <property name="climb_rate">1</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"/>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Levels of difficulty to print</property>
+ <property name="wrap">True</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="left_padding">24</property>
+ <child>
+ <object class="GtkVBox" id="vbox2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkCheckButton" id="easyCheckButton">
+ <property name="label" translatable="yes">_Easy</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="mediumCheckButton">
+ <property name="label" translatable="yes">_Medium</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="hardCheckButton">
+ <property name="label" translatable="yes">_Hard</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="very_hardCheckButton">
+ <property name="label" translatable="yes">_Very Hard</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Details</property>
+ <property name="wrap">True</property>
+ <attributes>
+ <attribute name="style" value="italic"/>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkAlignment" id="alignment3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <property name="left_padding">24</property>
+ <child>
+ <object class="GtkVBox" id="vbox3">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+ <child>
+ <object class="GtkCheckButton" id="markAsPlayedToggle">
+ <property name="label" translatable="yes">_Mark games as played once you've printed
them.</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="includeOldGamesToggle">
+ <property name="label" translatable="yes">_Include games you've already played in
list of games to print</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancelbutton1</action-widget>
+ <action-widget response="-5">okbutton1</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/src/gnome-sudoku.gresource.xml.in b/src/gnome-sudoku.gresource.xml.in
index f8c08ab..4865b71 100644
--- a/src/gnome-sudoku.gresource.xml.in
+++ b/src/gnome-sudoku.gresource.xml.in
@@ -3,6 +3,7 @@
<gresource prefix="/org/gnome/gnome-sudoku/ui">
<file alias="gnome-sudoku.ui" preprocess="xml-stripblanks">@top_srcdir@/data/gnome-sudoku.ui</file>
<file alias="gnome-sudoku-menu.ui"
preprocess="xml-stripblanks">@top_srcdir@/data/gnome-sudoku-menu.ui</file>
+ <file alias="print-games.ui" preprocess="xml-stripblanks">@top_srcdir@/data/print-games.ui</file>
</gresource>
<gresource prefix="/org/gnome/gnome-sudoku/puzzles">
<file alias="easy">@top_srcdir@/data/easy</file>
diff --git a/src/gnome-sudoku.vala b/src/gnome-sudoku.vala
index 24b306b..28957b5 100644
--- a/src/gnome-sudoku.vala
+++ b/src/gnome-sudoku.vala
@@ -460,14 +460,15 @@ public class Sudoku : Gtk.Application
{
if (game_box.visible)
{
- SudokuPrinter printer = new SudokuPrinter (game.board.clone (), ref window);
+ SudokuPrinter printer = new SudokuPrinter ({game.board.clone ()}, ref window);
printer.print_sudoku ();
}
}
public void print_multiple_cb ()
{
- stdout.printf ("TODO: Print multiple\n");
+ GamePrinter printer = new GamePrinter (sudoku_store, ref window);
+ printer.run_dialog ();
}
public void possible_numbers_cb ()
diff --git a/src/sudoku-board.vala b/src/sudoku-board.vala
index 470595d..7cdaed1 100644
--- a/src/sudoku-board.vala
+++ b/src/sudoku-board.vala
@@ -61,6 +61,27 @@ public class SudokuBoard
get { return _filled == _cols * _rows && !broken; }
}
+ public double difficulty_rating { get; private set; }
+
+ private bool in_range (float[] range)
+ {
+ return (difficulty_rating >= range[0] && difficulty_rating < range[1]);
+ }
+
+ public DifficultyCatagory get_difficulty_catagory ()
+ {
+ if (in_range(DifficultyRating.EASY_RANGE))
+ return DifficultyCatagory.EASY;
+ else if (in_range(DifficultyRating.MEDIUM_RANGE))
+ return DifficultyCatagory.MEDIUM;
+ else if (in_range(DifficultyRating.HARD_RANGE))
+ return DifficultyCatagory.HARD;
+ else if (in_range(DifficultyRating.VERY_HARD_RANGE))
+ return DifficultyCatagory.VERY_HARD;
+ else
+ return DifficultyCatagory.EASY;
+ }
+
public signal void completed ();
/* The set of coordinates on the board which are invalid */
@@ -170,7 +191,7 @@ public class SudokuBoard
return board;
}
- public void set_from_string (string s, string delimiter = "", string empty_value = "0")
+ public void set_from_string (string s, string delimiter = "", string empty_value = "0", string
rating_delimiter = "\t")
{
//stdout.printf("Processing %s\n", s);
@@ -178,7 +199,10 @@ public class SudokuBoard
string[] cells = s.split (delimiter, number_of_cells);
- //stdout.printf("Cells %d %d\n", number_of_cells, cells.length);
+ string[] rating = cells[cells.length -1].split (rating_delimiter, 2);
+ cells[cells.length - 1] = rating[0];
+ difficulty_rating = double.parse (rating[1]);
+
for (int i = 0; i < number_of_cells; i++)
{
string cell = cells[i];
diff --git a/src/sudoku-printer.vala b/src/sudoku-printer.vala
index ecf08b4..ab28c84 100644
--- a/src/sudoku-printer.vala
+++ b/src/sudoku-printer.vala
@@ -1,38 +1,40 @@
using Gtk;
+using Gee;
using Gdk;
public class SudokuPrinter : GLib.Object {
- private SudokuBoard board;
- private DifficultyRating difficulty_rating;
+ private SudokuBoard[] boards;
private ApplicationWindow window;
private int margin;
private int n_sudokus;
private int sudokus_per_page;
- private Gtk.PrintOperation print_op;
+ private PrintOperation print_op;
- public void print_sudoku ()
+ public PrintOperationResult print_sudoku ()
{
- Gtk.PrintOperationResult result = print_op.run (Gtk.PrintOperationAction.PRINT_DIALOG, window);
+ PrintOperationResult result = print_op.run (Gtk.PrintOperationAction.PRINT_DIALOG, window);
if (result == Gtk.PrintOperationResult.ERROR)
{
Gtk.MessageDialog error_dialog = new Gtk.MessageDialog (window,
Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, "Error printing file\n");
error_dialog.response.connect ((w) => {
- error_dialog.destroy();
+ error_dialog.destroy ();
});
error_dialog.show ();
}
+
+ return result;
}
- public SudokuPrinter (SudokuBoard board, ref ApplicationWindow window)
+ public SudokuPrinter (SudokuBoard[] boards, ref ApplicationWindow window, int sudokus_per_page = 1)
{
- this.board = board;
+ this.boards = boards;
this.window = window;
this.margin = 25;
- this.n_sudokus = 1;
- this.sudokus_per_page = 1;
+ this.n_sudokus = boards.length;
+ this.sudokus_per_page = sudokus_per_page;
this.print_op = new Gtk.PrintOperation ();
print_op.begin_print.connect (begin_print_cb);
@@ -41,31 +43,66 @@ public class SudokuPrinter : GLib.Object {
private void begin_print_cb (Gtk.PrintOperation operation, Gtk.PrintContext context)
{
- operation.set_n_pages ((n_sudokus / sudokus_per_page) + ((n_sudokus % sudokus_per_page) & 1));
+ int remainder = (n_sudokus % sudokus_per_page) == 0 ? 0 : 1;
+ operation.set_n_pages ((n_sudokus / sudokus_per_page) + remainder);
}
private void draw_page_cb (Gtk.PrintOperation operation, Gtk.PrintContext context, int page_nr)
{
Cairo.Context cr = context.get_cairo_context ();
- double width = context.get_width ();
- double height = context.get_height ();
+ var width = context.get_width ();
+ var height = context.get_height ();
+
+ var best_values = fit_squares_in_rectangle (width, height, margin);
+ var best_fit = best_values[0];
+ var best_square_size = best_values[1];
- double[] best_values = fit_squares_in_rectangle (width, height, sudokus_per_page, margin);
- double best_fit = best_values[0];
- double best_square_size = best_values[1];
+ var start = page_nr * sudokus_per_page;
+ var end = (start + sudokus_per_page) > boards.length ? boards.length : (start + sudokus_per_page);
+ SudokuBoard[] sudokus_on_page = boards[start : end];
- int start = page_nr * sudokus_per_page;
- int left = margin;
- int top = margin;
+ double left = margin;
+ double top = margin;
+ int[] pos = {1, 1};
+ var label = "";
- draw_sudoku (cr, best_square_size, left, top);
+ foreach (SudokuBoard sudoku in sudokus_on_page)
+ {
+ if (n_sudokus > 1)
+ label = sudoku.get_difficulty_catagory ().to_string () + " (" +
sudoku.difficulty_rating.to_string ()[0:4] + ")";
+ else
+ label = "";
+ cr.set_font_size (12);
+ cr.select_font_face ("Sans", Cairo.FontSlant.NORMAL, Cairo.FontWeight.BOLD);
+ cr.set_source_rgb (0, 0, 0);
+ Cairo.TextExtents extents;
+ cr.text_extents (label, out extents);
+ cr.move_to (left, top - extents.height / 2);
+ cr.show_text (label);
+
+ draw_sudoku (cr, sudoku, best_square_size, left, top);
+
+ if (pos[0] < best_fit)
+ {
+ left = left + best_square_size + margin;
+ pos[0] += 1;
+ }
+ else
+ {
+ top = top + best_square_size + margin;
+ left = margin;
+ pos[0] = 1;
+ pos[1] += 1;
+ }
+ }
}
- private double[] fit_squares_in_rectangle (double width, double height, int n, int margin)
+ private double[] fit_squares_in_rectangle (double width, double height, int margin)
{
- double best_square_size = 0;
+ var n = sudokus_per_page;
+ var best_square_size = 0.0;
double[] best_fit = {0,0};
- double square_size = 0;
+ var square_size = 0.0;
for (var n_across = 1; n_across <= n; n_across++)
{
@@ -93,7 +130,7 @@ public class SudokuPrinter : GLib.Object {
return best_fit;
}
- private void draw_sudoku (Cairo.Context cr, double size, int offset_x, int offset_y)
+ private void draw_sudoku (Cairo.Context cr, SudokuBoard sudoku_board, double size, double offset_x,
double offset_y)
{
const int SUDOKU_SIZE = 9;
const int N_BOXES = 3;
@@ -103,13 +140,13 @@ public class SudokuPrinter : GLib.Object {
const double[] BORDER_COLOR = {1.0, 1.0, 1.0};
const double[] LINE_COLOR = {0.0, 0.0, 0.0};
- double THIN = size / 500.0;
- double THICK = THIN * 5;
- double BORDER = THICK;
- double WHITE_SPACE = (size - (2 * BORDER)- (2 * THICK) - ((N_BOXES -1) * THICK) - ((N_BOXES * 2) *
THIN));
- double SQUARE_SIZE = WHITE_SPACE / SUDOKU_SIZE;
+ var THIN = size / 500.0;
+ var THICK = THIN * 5;
+ var BORDER = THICK;
+ var WHITE_SPACE = (size - (2 * BORDER)- (2 * THICK) - ((N_BOXES -1) * THICK) - ((N_BOXES * 2) *
THIN));
+ var SQUARE_SIZE = WHITE_SPACE / SUDOKU_SIZE;
- int FONT_SIZE = (int) SQUARE_SIZE / 2;
+ var FONT_SIZE = (int) SQUARE_SIZE / 2;
const Cairo.FontWeight FONT_WEIGHT = Cairo.FontWeight.NORMAL;
double[] outer = {offset_x, offset_x + size, offset_y, offset_y + size}; // left, right, top, bottom
@@ -138,10 +175,10 @@ public class SudokuPrinter : GLib.Object {
cr.set_source_rgb (LINE_COLOR[0], LINE_COLOR[1], LINE_COLOR[2]);
cr.stroke ();
- double[] pos = new double[SUDOKU_SIZE+1];
- double position = BORDER + THICK;
+ var pos = new double[SUDOKU_SIZE+1];
+ var position = BORDER + THICK;
pos[0] = position + SQUARE_SIZE / 2.0;
- double last_line = 0;
+ var last_line = 0.0;
for (var n = 1; n <= SUDOKU_SIZE; n++)
{
@@ -167,9 +204,9 @@ public class SudokuPrinter : GLib.Object {
}
cr.set_font_size (FONT_SIZE);
- string letter = "";
+ var letter = "";
Cairo.TextExtents extents;
- int[,] sudoku = board.get_cells ();
+ var sudoku = sudoku_board.get_cells ();
for (var x = 0; x < SUDOKU_SIZE; x++)
{
@@ -182,7 +219,7 @@ public class SudokuPrinter : GLib.Object {
{
letter = (sudoku[y,x]).to_string ();
- if (board.is_fixed[y,x])
+ if (sudoku_board.is_fixed[y,x])
{
cr.select_font_face ("Sans", Cairo.FontSlant.NORMAL, FONT_WEIGHT);
cr.set_source_rgb (0, 0, 0);
@@ -200,3 +237,127 @@ public class SudokuPrinter : GLib.Object {
}
}
}
+
+public class GamePrinter: GLib.Object {
+
+ private SudokuStore store;
+ private ApplicationWindow window;
+ private GLib.Settings settings;
+ private Gtk.Dialog dialog;
+ private HashMap<string, CheckButton> options_map;
+ private SpinButton sudokusToPrintSpinButton;
+ private SpinButton sudokusPerPageSpinButton;
+
+ public GamePrinter (SudokuStore store, ref ApplicationWindow window)
+ {
+ this.store = store;
+ this.window = window;
+ this.settings = new GLib.Settings ("org.gnome.gnome-sudoku");
+ this.options_map = new HashMap<string, CheckButton> ();
+
+ Gtk.Builder builder = new Builder ();
+ try
+ {
+ builder.add_from_resource ("/org/gnome/gnome-sudoku/ui/print-games.ui");
+ }
+ catch (GLib.Error e)
+ {
+ GLib.warning ("Could not load UI: %s", e.message);
+ }
+ builder.connect_signals (null);
+ this.dialog = builder.get_object ("dialog") as Dialog;
+ dialog.set_transient_for (window);
+ dialog.set_default_response (Gtk.ResponseType.OK);
+ dialog.response.connect (response_cb);
+
+ string[,] settings_to_widgets = {
+ {"mark-printed-as-played", "markAsPlayedToggle"},
+ {"print-already-played-games", "includeOldGamesToggle"},
+ {"print-easy", "easyCheckButton"},
+ {"print-medium", "mediumCheckButton"},
+ {"print-hard", "hardCheckButton"},
+ {"print-very-hard", "very_hardCheckButton"}};
+ CheckButton check_button;
+ string setting0, setting1;
+
+ for (var i=0; i<6; i++)
+ {
+ setting0 = settings_to_widgets[i,0];
+ setting1 = settings_to_widgets[i,1];
+ try
+ {
+ check_button = builder.get_object (setting1) as CheckButton;
+ }
+ catch (GLib.Error e)
+ {
+ GLib.warning ("Widget %s does not exist: %s", setting1, e.message);
+ }
+ wrap_toggle (setting0, check_button);
+ options_map.set (setting1, check_button);
+ }
+
+ sudokusToPrintSpinButton = builder.get_object ("sudokusToPrintSpinButton") as SpinButton;
+ sudokusPerPageSpinButton = builder.get_object ("sudokusPerPageSpinButton") as SpinButton;
+
+ wrap_adjustment ("print-multiple-sudokus-to-print", sudokusToPrintSpinButton.get_adjustment ());
+ wrap_adjustment ("sudokus-per-page", sudokusPerPageSpinButton.get_adjustment ());
+ }
+
+ private void wrap_toggle (string key_name, CheckButton action)
+ {
+ action.set_active (settings.get_boolean (key_name));
+ action.toggled.connect (() => settings.set_boolean (key_name, action.get_active ()));
+ }
+
+ private void wrap_adjustment (string key_name, Adjustment action)
+ {
+ action.set_value (settings.get_int (key_name));
+ action.value_changed.connect (() => settings.set_int (key_name, (int) action.get_value ()));
+ }
+
+ private void response_cb (Dialog dialog, int response)
+ {
+ if (response != Gtk.ResponseType.ACCEPT && response != Gtk.ResponseType.OK)
+ {
+ dialog.hide ();
+ return;
+ }
+
+ var nsudokus = (int) sudokusToPrintSpinButton.get_adjustment ().get_value ();
+ var sudokus_per_page = (int) sudokusPerPageSpinButton.get_adjustment ().get_value ();
+ DifficultyCatagory[] levels = {};
+
+ if (options_map.get ("easyCheckButton").get_active () == true)
+ levels += DifficultyCatagory.EASY;
+ if (options_map.get ("mediumCheckButton").get_active () == true)
+ levels += DifficultyCatagory.MEDIUM;
+ if (options_map.get ("hardCheckButton").get_active () == true)
+ levels += DifficultyCatagory.HARD;
+ if (options_map.get ("very_hardCheckButton").get_active () == true)
+ levels += DifficultyCatagory.VERY_HARD;
+
+ var boards = new ArrayList<SudokuBoard> ();
+ boards = store.get_assorted_boards (nsudokus, levels);
+
+ SudokuBoard[] sorted_boards = {};
+
+ foreach (SudokuBoard i in boards)
+ sorted_boards += i;
+
+ SudokuPrinter printer = new SudokuPrinter (sorted_boards, ref window, sudokus_per_page);
+ PrintOperationResult result = printer.print_sudoku ();
+
+ if (result == PrintOperationResult.APPLY)
+ {
+ // In future when 'markAsPlayedToggle' is made sensitive,
+ // copy the 'Tracker' portion of code from printing.py here.
+ dialog.hide ();
+ }
+ }
+
+ public void run_dialog ()
+ {
+ dialog.show ();
+ }
+
+}
diff --git a/src/sudoku-solver.vala b/src/sudoku-solver.vala
index 64c02aa..1ce530b 100644
--- a/src/sudoku-solver.vala
+++ b/src/sudoku-solver.vala
@@ -753,7 +753,24 @@ public enum DifficultyCatagory {
EASY,
MEDIUM,
HARD,
- VERY_HARD
+ VERY_HARD;
+
+ public string to_string ()
+ {
+ switch (this)
+ {
+ case EASY:
+ return "Easy";
+ case MEDIUM:
+ return "Medium";
+ case HARD:
+ return "Hard";
+ case VERY_HARD:
+ return "Very hard";
+ default:
+ return "Undefined";
+ }
+ }
}
public class DifficultyRating {
diff --git a/src/sudoku-store.vala b/src/sudoku-store.vala
index 8477c35..63d8b7d 100644
--- a/src/sudoku-store.vala
+++ b/src/sudoku-store.vala
@@ -1,6 +1,6 @@
using Gee;
-class SudokuStore
+public class SudokuStore
{
private ArrayList<SudokuBoard> easy_boards = new ArrayList<SudokuBoard> ();
private ArrayList<SudokuBoard> medium_boards = new ArrayList<SudokuBoard> ();
@@ -18,7 +18,7 @@ class SudokuStore
// Read lines until end of file (null) is reached
while ((line = dis.read_line (null)) != null) {
SudokuBoard board = new SudokuBoard();
- board.set_from_string(line[0:161], " ");
+ board.set_from_string(line, " ");
easy_boards.add(board);
}
@@ -33,7 +33,7 @@ class SudokuStore
// Read lines until end of file (null) is reached
while ((line = dis.read_line (null)) != null) {
SudokuBoard board = new SudokuBoard();
- board.set_from_string(line[0:161], " ");
+ board.set_from_string(line, " ");
medium_boards.add(board);
}
@@ -48,7 +48,7 @@ class SudokuStore
// Read lines until end of file (null) is reached
while ((line = dis.read_line (null)) != null) {
SudokuBoard board = new SudokuBoard();
- board.set_from_string(line[0:161], " ");
+ board.set_from_string(line, " ");
hard_boards.add(board);
}
@@ -63,7 +63,7 @@ class SudokuStore
// Read lines until end of file (null) is reached
while ((line = dis.read_line (null)) != null) {
SudokuBoard board = new SudokuBoard();
- board.set_from_string(line[0:161], " ");
+ board.set_from_string(line, " ");
very_hard_boards.add(board);
}
@@ -106,4 +106,30 @@ class SudokuStore
else
assert_not_reached();
}
+
+ public ArrayList<SudokuBoard> get_assorted_boards(int n, owned DifficultyCatagory[] levels)
+ {
+ var boards = new ArrayList<SudokuBoard> ();
+ int i = 0;
+
+ if (levels.length == 0)
+ levels = {DifficultyCatagory.EASY, DifficultyCatagory.MEDIUM, DifficultyCatagory.HARD,
DifficultyCatagory.VERY_HARD};
+
+ while (i < n)
+ {
+ // In future, modify this while loop to accomodate 'exclude' and 'new' parameters
+ boards.add (get_random_board ((DifficultyCatagory) levels[i++ % levels.length]));
+ }
+
+ CompareDataFunc<SudokuBoard> CompareDifficultyRatings = (a, b) => {
+ if (a.difficulty_rating > b.difficulty_rating)
+ return 1;
+ if (a.difficulty_rating == b.difficulty_rating)
+ return 0;
+ return -1;
+ };
+
+ boards.sort (CompareDifficultyRatings);
+ return boards;
+ }
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]