[gnome-chess] Add support for Fischer and Bronstein clocks
- From: Sahil Sareen <ssareen src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-chess] Add support for Fischer and Bronstein clocks
- Date: Mon, 16 Feb 2015 04:16:05 +0000 (UTC)
commit d00db10c103617fa3d864366eb335624b05ac559
Author: Sahil Sareen <sahil sareen hotmail com>
Date: Mon Feb 16 09:37:37 2015 +0530
Add support for Fischer and Bronstein clocks
* Preferences dialog: Added option for clock type
* Clock Library: Support for these clocks
* Gnome-Chess: Handle fischer/bronstein clocks
https://bugzilla.gnome.org/show_bug.cgi?id=473395
data/org.gnome.chess.gschema.xml | 26 ++++++
data/preferences.ui | 157 ++++++++++++++++++++++++++++++++-
lib/chess-clock.vala | 88 +++++++++++++++++++
lib/chess-pgn.vala | 10 ++
src/gnome-chess.vala | 179 +++++++++++++++++++++++++++++++++++++-
5 files changed, 453 insertions(+), 7 deletions(-)
---
diff --git a/data/org.gnome.chess.gschema.xml b/data/org.gnome.chess.gschema.xml
index c5c4d60..8287e18 100644
--- a/data/org.gnome.chess.gschema.xml
+++ b/data/org.gnome.chess.gschema.xml
@@ -20,6 +20,12 @@
<value value="2" nick="hard"/>
</enum>
+ <enum id="org.gnome.chess.ClockType">
+ <value value="0" nick="simple"/>
+ <value value="1" nick="fischer"/>
+ <value value="2" nick="bronstein"/>
+ </enum>
+
<schema id="org.gnome.chess" path="/org/gnome/chess/" gettext-domain="gnome-chess">
<key name="width" type="i">
<default>700</default>
@@ -76,6 +82,26 @@
<summary>The duration of a game in seconds (0 for no limit)</summary>
<description>The duration of a game in seconds (0 for no limit)</description>
</key>
+ <key name="clock-type" enum="org.gnome.chess.ClockType">
+ <default>'simple'</default>
+ <summary>The type of clock (simple/fischer/bronstein)</summary>
+ <description>The type of clock (simple/fischer/bronstein)</description>
+ </key>
+ <key name="timer-increment" type="i">
+ <default>1</default>
+ <summary>The timer increment set corresponding to clock type (1 second minimum)</summary>
+ <description>The timer increment set corresponding to clock type (1 second minimum)</description>
+ </key>
+ <key name="white-last-move-seconds" type="i">
+ <default>0</default>
+ <summary>Seconds white has used until last move (0 for first move)</summary>
+ <description>Seconds white has used until last move (0 for first move)</description>
+ </key>
+ <key name="black-last-move-seconds" type="i">
+ <default>0</default>
+ <summary>Seconds black has used until last move (0 for first move)</summary>
+ <description>Seconds black has used until last move (0 for first move)</description>
+ </key>
<key name="play-as-white" type="b">
<default>true</default>
<summary>true if the human player is playing white</summary>
diff --git a/data/preferences.ui b/data/preferences.ui
index d4d2733..783eff6 100644
--- a/data/preferences.ui
+++ b/data/preferences.ui
@@ -19,6 +19,46 @@
</row>
</data>
</object>
+ <object class="GtkListStore" id="timer_increment_units_model">
+ <columns>
+ <!-- column-name label -->
+ <column type="gchararray"/>
+ <!-- column-name multiplier -->
+ <column type="gint"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0">seconds</col>
+ <col id="1">1</col>
+ </row>
+ <row>
+ <col id="0">minutes</col>
+ <col id="1">60</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="clock_type_model">
+ <columns>
+ <!-- column-name label -->
+ <column type="gchararray"/>
+ <!-- column-name clock-type -->
+ <column type="gint"/>
+ </columns>
+ <data>
+ <row>
+ <col id="0">Simple</col>
+ <col id="1">0</col>
+ </row>
+ <row>
+ <col id="0">Fischer</col>
+ <col id="1">1</col>
+ </row>
+ <row>
+ <col id="0">Bronstein</col>
+ <col id="1">2</col>
+ </row>
+ </data>
+ </object>
<object class="GtkListStore" id="difficulty_model">
<columns>
<!-- column-name label -->
@@ -41,6 +81,13 @@
</row>
</data>
</object>
+ <object class="GtkAdjustment" id="timer_increment_adjustment">
+ <property name="lower">1</property>
+ <property name="upper">59</property>
+ <property name="step_increment">1</property>
+ <property name="page_increment">10</property>
+ <signal name="value-changed" handler="timer_increment_units_changed_cb" swapped="no"/>
+ </object>
<object class="GtkAdjustment" id="duration_adjustment">
<property name="lower">1</property>
<property name="upper">10</property>
@@ -197,7 +244,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">10</property>
- <property name="n_rows">6</property>
+ <property name="n_rows">8</property>
<property name="n_columns">2</property>
<property name="column_spacing">5</property>
<property name="row_spacing">5</property>
@@ -205,6 +252,59 @@
<placeholder/>
</child>
<child>
+ <object class="GtkLabel" id="clock_type_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" comments="Preferences Dialog: Label before
clock type (Fischer/Bronstein) combo box">_Clock type:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">clock_type_combo</property>
+ </object>
+ <packing>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="timer_increment_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" comments="Preferences Dialog: Label before
timer increment combo box">Timer _increment:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">timer_increment_spin</property>
+ </object>
+ <packing>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options"/>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="clock_type_combo">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">clock_type_model</property>
+ <signal name="changed" handler="clock_type_changed_cb" swapped="no"/>
+ <child>
+ <object class="GtkCellRendererText" id="clock_type_cellrenderer"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkLabel" id="side_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -230,6 +330,8 @@
<property name="mnemonic_widget">opponent_combo</property>
</object>
<packing>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options"/>
</packing>
@@ -251,6 +353,55 @@
</packing>
</child>
<child>
+ <object class="GtkBox" id="timer_increment_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkSpinButton" id="timer_increment_spin">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="adjustment">timer_increment_adjustment</property>
+ <property name="climb_rate">1</property>
+ <property name="numeric">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="timer_increment_units_combo">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">timer_increment_units_model</property>
+ <signal name="changed" handler="timer_increment_units_changed_cb" swapped="no"/>
+ <child>
+ <object class="GtkCellRendererText" id="timer_increment_units_cellrenderer"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ <property name="x_options">GTK_FILL</property>
+ <property name="y_options">GTK_FILL</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkComboBox" id="side_combo">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -433,8 +584,8 @@
</object>
<packing>
<property name="right_attach">2</property>
- <property name="top_attach">5</property>
- <property name="bottom_attach">6</property>
+ <property name="top_attach">7</property>
+ <property name="bottom_attach">8</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
diff --git a/lib/chess-clock.vala b/lib/chess-clock.vala
index 4e5c9f7..7e790b3 100644
--- a/lib/chess-clock.vala
+++ b/lib/chess-clock.vala
@@ -10,6 +10,43 @@
* license.
*/
+public enum ClockType
+{
+ SIMPLE,
+ FISCHER,
+ BRONSTEIN;
+
+ public string to_string ()
+ {
+ switch (this)
+ {
+ case SIMPLE:
+ return "simple";
+ case FISCHER:
+ return "fischer";
+ case BRONSTEIN:
+ return "bronstein";
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public static ClockType string_to_enum (string s)
+ {
+ switch (s)
+ {
+ case "simple":
+ return SIMPLE;
+ case "fischer":
+ return FISCHER;
+ case "bronstein":
+ return BRONSTEIN;
+ default:
+ assert_not_reached ();
+ }
+ }
+}
+
public class ChessClock : Object
{
public int white_initial_seconds { get; private set; }
@@ -20,7 +57,52 @@ public class ChessClock : Object
public int black_seconds_used { get; private set; default = 0; }
+ public ClockType clock_type { get; set; default = ClockType.SIMPLE; }
+
+ public int white_prev_move_seconds { get; private set; default = 0; }
+
+ public int black_prev_move_seconds { get; private set; default = 0; }
+
+ public int white_extra_seconds { get; private set; default = 0; }
+
+ public int black_extra_seconds { get; private set; default = 0; }
+
private Color _active_color = Color.WHITE;
+
+ public int extra_seconds { get; set; default = 0; }
+
+ public void update_prev_move_time ()
+ {
+ if (active_color == Color.WHITE)
+ black_prev_move_seconds = black_seconds_used;
+ else
+ white_prev_move_seconds = white_seconds_used;
+ }
+
+ public void update_extra_seconds ()
+ {
+ int white_move_used = 0, black_move_used = 0;
+ switch (clock_type)
+ {
+ case ClockType.SIMPLE:
+ break;
+ case ClockType.FISCHER:
+ if (active_color == Color.WHITE)
+ white_extra_seconds += extra_seconds;
+ else
+ black_extra_seconds += extra_seconds;
+ break;
+ case ClockType.BRONSTEIN:
+ white_move_used = white_seconds_used - white_prev_move_seconds;
+ black_move_used = black_seconds_used - black_prev_move_seconds;
+ if (active_color != Color.WHITE)
+ white_extra_seconds += int.min(extra_seconds, white_move_used);
+ else
+ black_extra_seconds += int.min(extra_seconds, black_move_used);
+ break;
+ }
+ }
+
public Color active_color
{
get { return _active_color; }
@@ -31,6 +113,12 @@ public class ChessClock : Object
stop ();
_active_color = value;
+
+ // This is a move switch
+ // Update the clocks for Fischer and Bronstein mode
+ update_extra_seconds ();
+ update_prev_move_time ();
+
start ();
}
}
diff --git a/lib/chess-pgn.vala b/lib/chess-pgn.vala
index f51dfb5..39733a6 100644
--- a/lib/chess-pgn.vala
+++ b/lib/chess-pgn.vala
@@ -125,6 +125,16 @@ public class PGNGame : Object
get { return tags.lookup ("BlackTimeLeft"); }
set { tags.insert ("BlackTimeLeft", value); }
}
+ public string? clock_type
+ {
+ get { return tags.lookup ("X-GNOME-ClockType"); }
+ set { tags.insert ("X-GNOME-ClockType", value); }
+ }
+ public string? timer_increment
+ {
+ get { return tags.lookup ("X-GNOME-TimerIncrement"); }
+ set { tags.insert ("X-GNOME-TimerIncrement", value); }
+ }
public bool set_up
{
get { string? v = tags.lookup ("SetUp"); return v != null && v == "1" ? true : false; }
diff --git a/src/gnome-chess.vala b/src/gnome-chess.vala
index af8853e..fc08d69 100644
--- a/src/gnome-chess.vala
+++ b/src/gnome-chess.vala
@@ -27,14 +27,19 @@ public class ChessApplication : Gtk.Application
private Gtk.ComboBox history_combo;
private Gtk.Widget white_time_label;
private Gtk.Widget black_time_label;
+ private Gtk.Widget timer_increment_label;
private Gtk.HeaderBar headerbar;
private Gtk.Dialog? preferences_dialog = null;
private Gtk.ComboBox side_combo;
private Gtk.ComboBox difficulty_combo;
private Gtk.ComboBox duration_combo;
+ private Gtk.ComboBox clock_type_combo;
private Gtk.Adjustment duration_adjustment;
+ private Gtk.Adjustment timer_increment_adjustment;
private Gtk.Box custom_duration_box;
+ private Gtk.Box timer_increment_box;
+ private Gtk.ComboBox timer_increment_units_combo;
private Gtk.ComboBox custom_duration_units_combo;
private uint save_duration_timeout = 0;
private Gtk.FileChooserDialog? open_dialog = null;
@@ -570,6 +575,30 @@ public class ChessApplication : Gtk.Application
game.start ();
+ int timer_increment_adj_value = 0;
+ if (pgn_game.timer_increment != null)
+ timer_increment_adj_value = int.parse (pgn_game.timer_increment);
+ else
+ {
+ timer_increment_adj_value = settings.get_int ("timer-increment");
+ pgn_game.timer_increment = timer_increment_adj_value.to_string ();
+ }
+
+ ClockType clock_type = ClockType.SIMPLE;
+ if (pgn_game.clock_type != null)
+ clock_type = ClockType.string_to_enum (pgn_game.clock_type);
+ else
+ {
+ clock_type = ClockType.string_to_enum (settings.get_string ("clock-type"));
+ pgn_game.clock_type = clock_type.to_string ();
+ }
+
+ if (game.clock != null)
+ {
+ game.clock.extra_seconds = (int) timer_increment_adj_value;
+ game.clock.clock_type = clock_type;
+ }
+
// If loading a completed saved game
if (pgn_game.result == PGNGame.RESULT_WHITE)
game.result = ChessResult.WHITE_WON;
@@ -1535,9 +1564,9 @@ public class ChessApplication : Gtk.Application
int time;
if (color == Color.WHITE)
- time = game.clock.white_initial_seconds - game.clock.white_seconds_used;
+ time = game.clock.white_initial_seconds - game.clock.white_seconds_used +
game.clock.white_extra_seconds;
else
- time = game.clock.black_initial_seconds - game.clock.black_seconds_used;
+ time = game.clock.black_initial_seconds - game.clock.black_seconds_used +
game.clock.black_extra_seconds;
if (time >= 60)
return "%d∶\xE2\x80\x8E%02d".printf (time / 60, time % 60);
@@ -1706,10 +1735,25 @@ public class ChessApplication : Gtk.Application
set_combo (difficulty_combo, 1, settings.get_string ("difficulty"));
duration_combo = (Gtk.ComboBox) preferences_builder.get_object ("duration_combo");
+ clock_type_combo = (Gtk.ComboBox) preferences_builder.get_object ("clock_type_combo");
duration_adjustment = (Gtk.Adjustment) preferences_builder.get_object ("duration_adjustment");
+ timer_increment_adjustment = (Gtk.Adjustment) preferences_builder.get_object
("timer_increment_adjustment");
custom_duration_box = (Gtk.Box) preferences_builder.get_object ("custom_duration_box");
+ timer_increment_box = (Gtk.Box) preferences_builder.get_object ("timer_increment_box");
custom_duration_units_combo = (Gtk.ComboBox) preferences_builder.get_object
("custom_duration_units_combo");
set_duration (settings.get_int ("duration"));
+ timer_increment_label = (Gtk.Widget) preferences_builder.get_object ("timer_increment_label");
+ timer_increment_units_combo = (Gtk.ComboBox) preferences_builder.get_object
("timer_increment_units_combo");
+
+ if (pgn_game.clock_type != null)
+ set_clock_type (ClockType.string_to_enum (pgn_game.clock_type));
+ else
+ set_clock_type ((int) ClockType.string_to_enum (settings.get_string ("clock-type")));
+
+ if (pgn_game.timer_increment != null)
+ set_timer_increment (int.parse (pgn_game.timer_increment));
+ else
+ set_timer_increment (settings.get_int ("timer-increment"));
var orientation_combo = (Gtk.ComboBox) preferences_builder.get_object ("orientation_combo");
set_combo (orientation_combo, 1, settings.get_string ("board-side"));
@@ -1796,6 +1840,61 @@ public class ChessApplication : Gtk.Application
settings.set_string ("difficulty", difficulty);
}
+ private void set_clock_type (int clock_type)
+ {
+ var model = clock_type_combo.model;
+ Gtk.TreeIter iter, active_iter_clock_type = {};
+
+ /* Find the largest units that can be used for this value */
+ if (model.get_iter_first (out iter))
+ {
+ do
+ {
+ int type;
+ model.get (iter, 1, out type, -1);
+ if (type == clock_type)
+ {
+ active_iter_clock_type = iter;
+ }
+ } while (model.iter_next (ref iter));
+ }
+
+ clock_type_combo.set_active_iter (active_iter_clock_type);
+ clock_type_changed_cb (clock_type_combo);
+ }
+
+ private void set_timer_increment (int timer_increment)
+ {
+ int timer_increment_multiplier = 1;
+
+ if (timer_increment >= 60)
+ {
+ timer_increment_adjustment.value = timer_increment / 60;
+ timer_increment_multiplier = 60;
+ } else
+ timer_increment_adjustment.value = timer_increment;
+
+ var model = timer_increment_units_combo.model;
+ Gtk.TreeIter iter, reqd_iter = {};
+
+ /* Find the largest units that can be used for this value */
+ if (model.get_iter_first (out iter))
+ {
+ do
+ {
+ int multiplier;
+ model.get (iter, 1, out multiplier, -1);
+ if (multiplier == timer_increment_multiplier)
+ {
+ reqd_iter = iter;
+ }
+ } while (model.iter_next (ref iter));
+ }
+
+ timer_increment_units_combo.set_active_iter (reqd_iter);
+ timer_increment_units_changed_cb (timer_increment_units_combo);
+ }
+
private void set_duration (int duration, bool simplify = true)
{
var model = custom_duration_units_combo.model;
@@ -1930,6 +2029,57 @@ public class ChessApplication : Gtk.Application
save_duration ();
}
+ [CCode (cname = "G_MODULE_EXPORT timer_increment_units_changed_cb", instance_pos = -1)]
+ public void timer_increment_units_changed_cb (Gtk.Widget widget)
+ {
+ var model = (Gtk.ListStore) timer_increment_units_combo.model;
+ Gtk.TreeIter iter;
+ int multiplier = 0;
+ /* Set the unit labels to the correct plural form */
+ if (model.get_iter_first (out iter))
+ {
+ do
+ {
+ model.get (iter, 1, out multiplier, -1);
+ switch (multiplier)
+ {
+ case 1:
+ model.set (iter, 0, ngettext (/* Preferences Dialog: Combo box entry for a custom clock
type set in seconds */
+ "second", "seconds", (ulong)
timer_increment_adjustment.value), -1);
+ break;
+ case 60:
+ model.set (iter, 0, ngettext (/* Preferences Dialog: Combo box entry for a custom clock
type set in minutes */
+ "minute", "minutes", (ulong)
timer_increment_adjustment.value), -1);
+ break;
+ default:
+ assert_not_reached ();
+ }
+ } while (model.iter_next (ref iter));
+ }
+
+ if (timer_increment_units_combo.get_active_iter (out iter))
+ timer_increment_units_combo.model.get (iter, 1, out multiplier, -1);
+
+ switch (multiplier)
+ {
+ case 1:
+ if (timer_increment_adjustment.get_upper () != 59)
+ timer_increment_adjustment.set_upper (59);
+ break;
+ case 60:
+ if (timer_increment_adjustment.get_upper () != 10)
+ {
+ timer_increment_adjustment.set_upper (10);
+ if (timer_increment_adjustment.value > 10)
+ timer_increment_adjustment.value = 10;
+ }
+ break;
+ default:
+ assert_not_reached ();
+ }
+ settings.set_int ("timer-increment", (int) timer_increment_adjustment.value * multiplier);
+ }
+
private void save_duration ()
{
/* Delay writing the value as it this event will be generated a lot spinning through the value */
@@ -1947,6 +2097,10 @@ public class ChessApplication : Gtk.Application
int duration;
combo.model.get (iter, 1, out duration, -1);
custom_duration_box.visible = duration < 0;
+ clock_type_combo.sensitive = duration != 0;
+
+ if (duration == 0)
+ set_clock_type (ClockType.SIMPLE);
if (duration >= 0)
set_duration (duration, false);
@@ -1957,6 +2111,20 @@ public class ChessApplication : Gtk.Application
save_duration ();
}
+ [CCode (cname = "G_MODULE_EXPORT clock_type_changed_cb", instance_pos = -1)]
+ public void clock_type_changed_cb (Gtk.ComboBox combo)
+ {
+ Gtk.TreeIter iter;
+ if (!combo.get_active_iter (out iter))
+ return;
+ ClockType clock_type;
+ combo.model.get (iter, 1, out clock_type, -1);
+
+ timer_increment_box.visible = clock_type > 0;
+ timer_increment_label.visible = clock_type > 0;
+ settings.set_string ("clock-type", clock_type.to_string ());
+ }
+
[CCode (cname = "G_MODULE_EXPORT preferences_response_cb", instance_pos = -1)]
public void preferences_response_cb (Gtk.Widget widget, int response_id)
{
@@ -2067,8 +2235,11 @@ public class ChessApplication : Gtk.Application
uint white_used = game.clock.white_seconds_used;
uint black_used = game.clock.black_seconds_used;
- pgn_game.white_time_left = (white_initial_time - white_used).to_string ();
- pgn_game.black_time_left = (black_initial_time - black_used).to_string ();
+ uint white_extra = game.clock.white_extra_seconds;
+ uint black_extra = game.clock.black_extra_seconds;
+
+ pgn_game.white_time_left = (white_initial_time - white_used + white_extra).to_string ();
+ pgn_game.black_time_left = (black_initial_time - black_used + black_extra).to_string ();
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]