Skip to content
Commits on Source (20)
43.1 - January 23, 2023
=======================
44.beta - February 10, 2023
===========================
- Gate extra warnings behind hidden setting (#64)
- Undo/redo for earmarks is now less broken (#65)
44.alpha - January 5, 2023
==========================
- Revert "Fix redundant undo stack entries for earmarks" (#65)
- Warnings when solution to puzzle is violated no longer consider earmarks (#66)
- Make earmark popover open on long press (#7, Albin Larsson)
- Add "wrap around" keyboard navigation (!47, Albin Larsson)
- Updated translations
43.0 - September 15, 2022
......
......@@ -51,7 +51,8 @@
<value key="Purism::form_factor">mobile</value>
</custom>
<releases>
<release version="43.1" date="2023-01-23"/>
<release version="44~beta" date="2023-02-10"/>
<release version="44~alpha" date="2023-01-05"/>
<release version="43.0" date="2022-09-15"/>
<release version="43~beta" date="2022-08-05"/>
<release version="43~alpha" date="2022-07-08" />
......
......@@ -28,6 +28,11 @@
<summary>Warn about unfillable squares and duplicate numbers</summary>
<description>Displays a big red X in a square if it cannot possibly be filled by any number and duplicate numbers are highlighted in red</description>
</key>
<key name="show-extra-warnings" type="b">
<default>false</default>
<summary>Additionally warn when correct solution is violated or not earmarked</summary>
<description>Changes the background color of a square to red if the value does not match puzzle solution, or if no earmark matches the puzzle solution</description>
</key>
<key name="highlighter" type="b">
<default>false</default>
<summary>Highlight row, column and square that contain the selected cell</summary>
......
......@@ -27,7 +27,7 @@
G_BEGIN_DECLS
int *qqwing_generate_puzzle(int difficulty);
gboolean qqwing_solve_puzzle(int* puzzle);
gboolean qqwing_solve_puzzle(int *puzzle);
int qqwing_count_solutions_limited(int *puzzle);
void qqwing_print_stats(int *puzzle);
char *qqwing_get_version(void);
......
......@@ -21,8 +21,7 @@
[CCode (cheader_filename = "qqwing-wrapper.h")]
namespace QQwing {
[CCode (array_length=false)]
int[] generate_puzzle (int difficulty);
[CCode (array_length=false)] int[] generate_puzzle (int difficulty);
bool solve_puzzle([CCode (array_length = false)] int[] puzzle);
int count_solutions_limited ([CCode (array_length = false)] int[] puzzle);
void print_stats ([CCode (array_length = false)] int[] puzzle);
......
......@@ -378,10 +378,10 @@ public class SudokuBoard : Object
public void solve ()
{
int[] solution_1d = convert_2d_to_1d(cells);
int[] solution_1d = convert_2d_to_1d (cells);
if (QQwing.solve_puzzle (solution_1d))
solution = convert_1d_to_2d(solution_1d);
solution = convert_1d_to_2d (solution_1d);
else
solution = null;
}
......@@ -393,7 +393,7 @@ public class SudokuBoard : Object
public int count_solutions_limited ()
{
int[] cells_1d = convert_2d_to_1d(cells);
int[] cells_1d = convert_2d_to_1d (cells);
return QQwing.count_solutions_limited (cells_1d);
}
......
......@@ -4,7 +4,7 @@ project('gnome-sudoku', ['c', 'cpp', 'vala'],
],
license: 'GPL3+',
meson_version: '>= 0.59',
version: '43.1'
version: '44.beta'
)
application_id = 'org.gnome.Sudoku'
add_project_arguments([
......
msgid ""
msgstr ""
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-sudoku/issues\n"
"POT-Creation-Date: 2022-11-01 22:24+0000\n"
"POT-Creation-Date: 2022-07-10 09:30+0000\n"
"Last-Translator: Нанба Наала <naala-nanba@rambler.ru>\n"
"Language-Team: Abkhazian <daniel.abzakh@gmail.com>\n"
"Language: ab\n"
......@@ -9,7 +9,6 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-DamnedLies-Scope: partial\n"
#: data/sudoku-window.ui:7
msgid "_New Puzzle"
......@@ -17,7 +16,7 @@ msgstr "_Ахыҧҽыга ҿыц"
#: data/sudoku-window.ui:11
msgid "_Clear Board"
msgstr "_Аӷәы арыцқьара"
msgstr "_Аӷәы Арыцқьара "
#: data/sudoku-window.ui:17 data/print-dialog.ui:38
msgid "_Print"
......@@ -33,7 +32,7 @@ msgstr "Акьыҧхьра _Ҧыҭк Ахыҧҽыгақәа…"
#: data/sudoku-window.ui:32
msgid "High_lighter"
msgstr "_Аҿаҧарақәа_ралкаара"
msgstr "Аҿаҧарақәа_ралкаара"
#: data/sudoku-window.ui:36
msgid "_Warnings"
......@@ -48,7 +47,7 @@ msgid "_About Sudoku"
msgstr "_Судоку Иазкны"
#: data/sudoku-window.ui:52 data/sudoku-window.ui:57
#: data/org.gnome.Sudoku.desktop.in:3 src/gnome-sudoku.vala:498
#: data/org.gnome.Sudoku.desktop.in:3 src/gnome-sudoku.vala:495
#: src/sudoku-window.vala:213
msgid "Sudoku"
msgstr "Судоку"
......@@ -79,7 +78,7 @@ msgstr "_Имариоу"
#: data/sudoku-window.ui:241 data/print-dialog.ui:172
msgid "_Medium"
msgstr "_Абжьаратәи"
msgstr "_Агәыбжьанытәи"
#: data/sudoku-window.ui:249 data/print-dialog.ui:188
msgid "_Hard"
......@@ -87,7 +86,7 @@ msgstr "_Иуадаҩу"
#: data/sudoku-window.ui:257 data/print-dialog.ui:204
msgid "_Very Hard"
msgstr "_Даара иуадаҩу"
msgstr "_Даара Иуадаҩу"
#: data/sudoku-window.ui:265
msgid "_Create your own puzzle"
......@@ -133,7 +132,7 @@ msgstr ""
msgid "A GNOME sudoku game preview"
msgstr "Судоку GNOME ахәмарра заатәи ахәаҧшра"
#: data/org.gnome.Sudoku.appdata.xml.in:75
#: data/org.gnome.Sudoku.appdata.xml.in:73
msgid "The GNOME Project"
msgstr "The GNOME Project"
......@@ -184,7 +183,7 @@ msgstr ""
#: data/org.gnome.Sudoku.gschema.xml:37
msgid "Width of the window in pixels"
msgstr "Аԥенџьыр аҭбаара пиксельла"
msgstr ""
#: data/org.gnome.Sudoku.gschema.xml:41
msgid "Height of the window in pixels"
......@@ -192,11 +191,11 @@ msgstr "Аԥенџьыр аҳаракыра пиксельла"
#: data/org.gnome.Sudoku.gschema.xml:45
msgid "true if the window is maximized"
msgstr "иалхзар,аԥенџьыр иамоуп иреиҳау ашәага"
msgstr ""
#: data/org.gnome.Sudoku.gschema.xml:49
msgid "Initialize the earmarks with the possible values for each cell"
msgstr "аҿаҧара цыҧхьаӡа азы анеира ахьауа аҵакқәа рырбара"
msgstr ""
#: data/print-dialog.ui:18
msgid "Print Multiple Puzzles"
......@@ -204,7 +203,7 @@ msgstr "Ҧыҭк ахыҧҽыгақәа ркьыҧхьра"
#: data/print-dialog.ui:27
msgid "_Cancel"
msgstr "_Аԥыхра"
msgstr "_Аҧыхры"
#: data/print-dialog.ui:65
msgid "_Number of puzzles"
......@@ -218,27 +217,27 @@ msgstr ""
msgid "Difficulty"
msgstr "Ауадаҩра"
#: lib/sudoku-board.vala:644
#: lib/sudoku-board.vala:591
msgid "Unknown Difficulty"
msgstr "Еилкаам Ауадаҩра Аҳаракыра"
#: lib/sudoku-board.vala:646
#: lib/sudoku-board.vala:593
msgid "Easy Difficulty"
msgstr "Имариоу Ауадаҩра"
#: lib/sudoku-board.vala:648
#: lib/sudoku-board.vala:595
msgid "Medium Difficulty"
msgstr "Игәыбжьанытәиу Ауадаҩра"
#: lib/sudoku-board.vala:650
#: lib/sudoku-board.vala:597
msgid "Hard Difficulty"
msgstr "Иҳараку Ауадаҩра"
#: lib/sudoku-board.vala:652
#: lib/sudoku-board.vala:599
msgid "Very Hard Difficulty"
msgstr "Даара Иҳараку Ауадаҩра"
#: lib/sudoku-board.vala:654
#: lib/sudoku-board.vala:601
msgid "Custom Puzzle"
msgstr "Ахархәаратә хыҧҽыга"
......@@ -291,14 +290,14 @@ msgstr "_Ахырқәшара"
#: src/gnome-sudoku.vala:291
msgid "Play _Again"
msgstr "_Еиҭа ахәмарра"
msgstr "Еиҭа хәмарра"
#: src/gnome-sudoku.vala:400
#: src/gnome-sudoku.vala:397
msgid "Reset the board to its original state?"
msgstr "Ахәмарратә ӷәы аханатәтәи аҭагылазаашьа ахь архынҳәра?"
#. Appears on the About dialog. %s is the version of the QQwing puzzle generator in use.
#: src/gnome-sudoku.vala:495
#: src/gnome-sudoku.vala:492
#, c-format
msgid ""
"The popular Japanese logic puzzle\n"
......@@ -309,7 +308,7 @@ msgstr ""
"\n"
"Ахыҧҽыгақәа аҧҵахоит QQwing %s "
#: src/gnome-sudoku.vala:506
#: src/gnome-sudoku.vala:503
msgid "translator-credits"
msgstr "Нанба Наала <naala-nanba@rambler.ru>, 2022"
......@@ -323,9 +322,9 @@ msgid "Error printing file:"
msgstr "Афаил акьыҧхьараан иҟалеит агха:"
#. Text on overlay when game is paused
#: src/sudoku-view.vala:756
#: src/sudoku-view.vala:669
msgid "Paused"
msgstr "Ааҭгылара"
msgstr "Иаанкылоуп"
#: src/sudoku-window.vala:154
msgid "Select Difficulty"
......@@ -346,3 +345,6 @@ msgstr "Ахыҧҽыга ҿыц алагара"
msgid "_Start Playing"
msgstr "_Ахәмарра алагара"
msgid "_Resume"
msgstr "_Аиҭаҿакра"
......@@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: gnome-games master\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-sudoku/issues\n"
"POT-Creation-Date: 2022-11-01 22:24+0000\n"
"PO-Revision-Date: 2022-11-28 02:42+0300\n"
"PO-Revision-Date: 2022-11-28 02:43+0300\n"
"Last-Translator: Launchpad translators\n"
"Language-Team: Belarusian <i18n-bel-gnome@googlegroups.com>\n"
"Language: be\n"
......@@ -341,7 +341,7 @@ msgid "Error printing file:"
msgstr "Памылка друкавання файла:"
#. Text on overlay when game is paused
#: src/sudoku-view.vala:756
#: src/sudoku-view.vala:806
msgid "Paused"
msgstr "Паўза"
......
......@@ -121,19 +121,26 @@ public class Sudoku : Gtk.Application
});
add_action (action);
var highlighter_action = settings.create_action ("highlighter");
highlighter_action.notify["state"].connect (() => {
action = settings.create_action ("show-extra-warnings");
action.notify["state"].connect (() => {
if (view != null && current_game_mode == GameMode.PLAY)
view.show_extra_warnings = settings.get_boolean ("show-extra-warnings");
});
add_action (action);
action = settings.create_action ("highlighter");
action.notify["state"].connect (() => {
if (view != null)
view.highlighter = settings.get_boolean ("highlighter");
});
add_action (highlighter_action);
add_action (action);
var initialize_earmarks_action = settings.create_action ("initialize-earmarks");
initialize_earmarks_action.notify["state"].connect (() => {
action = settings.create_action ("initialize-earmarks");
action.notify["state"].connect (() => {
if (view != null)
view.initialize_earmarks = settings.get_boolean ("initialize-earmarks");
});
add_action (initialize_earmarks_action);
add_action (action);
set_accels_for_action ("app.new-game", {"<Primary>n"});
set_accels_for_action ("app.print", {"<Primary>p"});
......@@ -311,7 +318,7 @@ public class Sudoku : Gtk.Application
private void start_game (SudokuBoard board)
{
if (current_game_mode == GameMode.PLAY)
board.solve();
board.solve ();
if (game != null)
{
......
......@@ -40,6 +40,8 @@ private class SudokuCellView : DrawingArea
private bool left_control;
private bool right_control;
public Gtk.GestureLongPress long_press;
public int value
{
get { return game.board [row, col]; }
......@@ -102,6 +104,17 @@ private class SudokuCellView : DrawingArea
}
}
private bool _show_extra_warnings = false;
public bool show_extra_warnings
{
get { return _show_extra_warnings; }
set
{
_show_extra_warnings = value;
queue_draw ();
}
}
public bool selected { get; set; }
public bool highlighted_background { get; set; }
public bool highlighted_value { get; set; }
......@@ -162,6 +175,14 @@ private class SudokuCellView : DrawingArea
return false;
}
public void long_press_event ()
{
if (game.mode == GameMode.PLAY && (is_fixed || game.paused))
return;
show_earmark_picker ();
}
private void create_earmark_picker ()
{
earmark_picker = new NumberPicker (ref game.board, true);
......@@ -240,7 +261,7 @@ private class SudokuCellView : DrawingArea
popover = null;
// Destroying a popover means that this type of warning is now possible.
if (warn_incorrect_solution())
if (warn_incorrect_solution ())
queue_draw ();
}
}
......@@ -374,7 +395,7 @@ private class SudokuCellView : DrawingArea
}
// Releasing a control means that this type of warning is now possible.
if (control_released && warn_incorrect_solution())
if (control_released && warn_incorrect_solution ())
queue_draw ();
}
......@@ -392,7 +413,7 @@ private class SudokuCellView : DrawingArea
// Highlight the cell if the value or earmarks are inconsistent with
// a known solution, if any.
if (warn_incorrect_solution())
if (warn_incorrect_solution ())
{
bool cell_error = false;
int solution = game.board.get_solution (row, col);
......@@ -401,6 +422,24 @@ private class SudokuCellView : DrawingArea
// Check value against the solution.
cell_error = value != solution;
}
else
{
// Check earmarks against the solution.
var marks = game.board.get_earmarks (row, col);
bool earmarked = false;
bool solution_found = false;
for (int num = 1; num <= marks.length; num++)
{
if (marks[num - 1])
{
earmarked = true;
if (num == solution)
solution_found = true;
}
}
if (earmarked && !solution_found)
cell_error = true;
}
// Make the error cell more red by reducing the other colors to 60%.
if (cell_error)
......@@ -545,16 +584,16 @@ private class SudokuCellView : DrawingArea
// Return true if the user is to be warned when the value or earmarks are
// inconsistent with the known solution, and it is ok for the user to be
// warned.
private bool warn_incorrect_solution()
private bool warn_incorrect_solution ()
{
// In the following popovers are checked so that the solution of the cell
// is not revealed to the user as the user enters candidate numbers for
// the cell using the earmark picker. Similarly don't reveal the solution
// while earmarks are being entered with the control key.
return _show_warnings && // show warnings?
(popover == null) && (earmark_popover == null) && // popovers gone?
return _show_extra_warnings && // show extra warnings?
(popover == null) && (earmark_popover == null) && // popovers gone?
(!left_control) && (!right_control) && // control keys not pressed?
game.board.solved(); // solution exists?
game.board.solved (); // solution exists?
}
}
......@@ -574,6 +613,8 @@ public class SudokuView : AspectFrame
private DrawingArea drawing;
private Grid grid;
private EventControllerKey key_controller;
private int selected_row = -1;
private int selected_col = -1;
private void set_selected (int cell_row, int cell_col)
......@@ -591,6 +632,35 @@ public class SudokuView : AspectFrame
}
}
private bool on_key_pressed (EventControllerKey _key_controller, uint keyval, uint keycode, ModifierType state)
{
if ((keyval == Gdk.Key.Left || keyval == Gdk.Key.KP_Left) && selected_col == 0)
{
cells[selected_row, 8].grab_focus ();
return true;
}
if ((keyval == Gdk.Key.Right || keyval == Gdk.Key.KP_Right) && selected_col == 8)
{
cells[selected_row, 0].grab_focus ();
return true;
}
if ((keyval == Gdk.Key.Up || keyval == Gdk.Key.KP_Up) && selected_row == 0)
{
cells[8, selected_col].grab_focus ();
return true;
}
if ((keyval == Gdk.Key.Down || keyval == Gdk.Key.KP_Down) && selected_row == 8)
{
cells[0, selected_col].grab_focus ();
return true;
}
return false;
}
public SudokuView (SudokuGame game)
{
shadow_type = ShadowType.NONE;
......@@ -674,6 +744,12 @@ public class SudokuView : AspectFrame
return false;
});
cell.long_press = new Gtk.GestureLongPress (cell);
cell.long_press.set_propagation_phase (Gtk.PropagationPhase.TARGET);
cell.long_press.pressed.connect (() => {
cell.long_press_event ();
});
cell.notify["value"].connect ((s, p)=> {
if (_show_possibilities || _show_warnings || game.board.broken || previous_board_broken_state)
previous_board_broken_state = game.board.broken;
......@@ -694,6 +770,9 @@ public class SudokuView : AspectFrame
grid.show_all ();
overlay.show ();
drawing.hide ();
key_controller = new EventControllerKey (this);
key_controller.key_pressed.connect (on_key_pressed);
}
private void update_highlights ()
......@@ -763,6 +842,18 @@ public class SudokuView : AspectFrame
}
}
private bool _show_extra_warnings = false;
public bool show_extra_warnings
{
get { return _show_extra_warnings; }
set {
_show_extra_warnings = value;
for (var i = 0; i < game.board.rows; i++)
for (var j = 0; j < game.board.cols; j++)
cells[i,j].show_extra_warnings = _show_extra_warnings;
}
}
private bool _show_possibilities = false;
public bool show_possibilities
{
......
......@@ -139,6 +139,7 @@ public class SudokuWindow : ApplicationWindow
view.show_warnings = true;
else
view.show_warnings = settings.get_boolean ("show-warnings");
view.show_extra_warnings = settings.get_boolean ("show-extra-warnings");
view.highlighter = settings.get_boolean ("highlighter");
view.initialize_earmarks = settings.get_boolean ("initialize-earmarks");
......