[gnome-games/glchess-vala] Get a chess clock working



commit 8dc0089e8682f083610f300f89a15935e71ca7e9
Author: Robert Ancell <robert ancell canonical com>
Date:   Fri Jan 7 15:20:27 2011 +1100

    Get a chess clock working

 glchess/src/Makefile.am      |    3 +-
 glchess/src/chess-clock.vala |  156 +++++++++++++++++++++++++++++++-----------
 glchess/src/chess-game.vala  |   18 +++++-
 glchess/src/glchess.vala     |   38 ++++++++--
 4 files changed, 166 insertions(+), 49 deletions(-)
---
diff --git a/glchess/src/Makefile.am b/glchess/src/Makefile.am
index 2d06d92..85640d8 100644
--- a/glchess/src/Makefile.am
+++ b/glchess/src/Makefile.am
@@ -7,12 +7,12 @@ glchess_SOURCES = \
 	glchess.vala \
 	ai-profile.vala \
 	chess-bitboard.vala \
+	chess-clock.vala \
 	chess-engine.vala \
 	chess-engine-cecp.vala \
 	chess-engine-uci.vala \
 	chess-game.vala \
 	chess-pgn.vala \
-	chess-clock.vala \
 	chess-view.vala \
 	chess-view-2d.vala \
 	chess-view-3d.vala \
@@ -21,6 +21,7 @@ glchess_SOURCES = \
 
 test_chess_game_SOURCES = \
 	chess-bitboard.vala \
+	chess-clock.vala \
 	chess-game.vala \
 	test-chess-game.vala
 
diff --git a/glchess/src/chess-clock.vala b/glchess/src/chess-clock.vala
index 4704eae..c1b8a98 100644
--- a/glchess/src/chess-clock.vala
+++ b/glchess/src/chess-clock.vala
@@ -1,77 +1,153 @@
 public class ChessClock : Object
 {
+    private uint _white_duration;
+    public uint white_duration
+    {
+        get { return _white_duration; }
+    }
+    private uint _black_duration;
+    public uint black_duration
+    {
+        get { return _black_duration; }
+    }
+
+    private uint _white_used;
+    public uint white_used
+    {
+        get
+        {
+            if (active_color == Color.WHITE)
+                return _white_used + (uint) (timer.elapsed () * 1000);
+            else
+                return _white_used;
+        }
+    }
+
+    public uint white_used_in_seconds
+    {
+        get { return (white_used + 500) / 1000; }
+    }
+
+    private uint _black_used;
+    public uint black_used
+    {
+        get
+        {
+            if (active_color == Color.WHITE)
+                return _black_used;
+            else
+                return _black_used + (uint) (timer.elapsed () * 1000);
+        }
+    }
+
+    public uint black_used_in_seconds
+    {
+        get { return (black_used + 500) / 1000; }
+    }
+
+    public Color _active_color = Color.WHITE;
+    public Color active_color
+    {
+        get { return _active_color; }
+        set
+        {
+            if (value == active_color)
+                return;
+
+            stop ();
+            _active_color = value;
+            start ();
+        }
+    }
+
     private Timer timer;
-    private uint white_duration;
-    private uint black_duration;
-    private uint white_used;
-    private uint black_used;
-    private Color active_color = Color.WHITE;
-    private uint timeout = 0;
+    private uint expire_timeout = 0;
+    private uint tick_timeout = 0;
 
     public signal void tick ();
     public signal void expired ();
 
     public ChessClock (uint white_duration, uint black_duration, uint white_used = 0, uint black_used = 0)
     {
-        this.white_duration = white_duration;
-        this.black_duration = black_duration;
-        this.white_used = white_used;
-        this.black_used = black_used;
+        _white_duration = white_duration * 1000;
+        _black_duration = black_duration * 1000;
+        _white_used = white_used;
+        _black_used = black_used;
         timer = new Timer ();
     }
-
+    
+    private bool is_started
+    {
+        get { return expire_timeout != 0; }
+    }
+    
     public void start ()
     {
-        if (timeout != 0)
+        if (is_started)
             return;
 
-        uint remaining;
+        /* Start stopwatch */
+        timer.start ();
+
+        /* Notify when this timer has expired */
         if (active_color == Color.WHITE)
-        {
-            if (white_used > white_duration)
-                white_used = white_duration;
-            remaining = white_duration - white_used;
-        }
+            expire_timeout = Timeout.add (white_duration - _white_used, timer_expired_cb);
         else
-        {
-            if (black_used > black_duration)
-                black_used = black_duration;
-            remaining = black_duration - black_used;
-        }
-        timer.start ();
+            expire_timeout = Timeout.add (black_duration - _black_used, timer_expired_cb);
 
-        timeout = Timeout.add (remaining, timer_expired_cb);
+        /* Wake up each second */
+        tick_cb ();
     }
 
     private bool timer_expired_cb ()
     {
-        timeout = 0;
+        stop ();
         expired ();
         return false;
     }
 
-    public void stop ()
+    private bool tick_cb ()
     {
-        if (timeout == 0)
-            return;
-        timer.stop ();
-        Source.remove (timeout);
-        timeout = 0;
+        if (tick_timeout != 0)
+            tick ();
 
-        var elapsed = (uint) (timer.elapsed () * 1000000);
+        uint elapsed = (uint) (timer.elapsed () * 1000);
+        uint used;
         if (active_color == Color.WHITE)
-            white_used += elapsed;
+            used = _white_used + elapsed;
         else
-            black_used += elapsed;
+            used = _black_used + elapsed;
+        var next_tick_time = ((used / 1000) + 1) * 1000;
+        tick_timeout = Timeout.add (next_tick_time - used, tick_cb);
+
+        return false;
     }
 
-    public void set_color (Color color)
+    public void stop ()
     {
-        if (color == active_color)
+        if (!is_started)
             return;
 
-        active_color = color;
-        stop ();
-        start ();
+        timer.stop ();
+        Source.remove (expire_timeout);
+        expire_timeout = 0;
+        Source.remove (tick_timeout);
+        tick_timeout = 0;
+
+        var elapsed = (uint) (timer.elapsed () * 1000);
+        if (active_color == Color.WHITE)
+        {
+            _white_used += elapsed;
+            if (_white_used > white_duration)
+                _white_used = white_duration;
+        }
+        else
+        {
+            _black_used += elapsed;
+            if (_black_used > black_duration)
+                _black_used = black_duration;
+        }
+
+        timer.reset ();
     }
 }
diff --git a/glchess/src/chess-game.vala b/glchess/src/chess-game.vala
index ef5e418..0b475e0 100644
--- a/glchess/src/chess-game.vala
+++ b/glchess/src/chess-game.vala
@@ -787,6 +787,7 @@ public enum ChessRule
 public class ChessGame
 {
     public bool is_started;
+    public ChessClock clock;
     public ChessResult result;
     public ChessRule rule;
     public List<ChessState> move_stack;
@@ -811,6 +812,8 @@ public class ChessGame
 
     public ChessGame (string fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")
     {
+        clock = new ChessClock (60, 60);
+
         is_started = false;
         move_stack.prepend (new ChessState (fen));
         result = ChessResult.IN_PROGRESS;
@@ -866,6 +869,7 @@ public class ChessGame
             state.last_move.moved_rook.moved ();
         moved (state.last_move);
 
+        clock.active_color = current_player.color;
         current_player.start_turn ();
         turn_started (current_player);
 
@@ -905,11 +909,23 @@ public class ChessGame
 
         reset ();
 
+        clock.expired.connect (clock_expired_cb);
+        clock.active_color = current_player.color;
+        clock.start ();
+
         started ();
         current_player.start_turn ();
         turn_started (current_player);
     }
-    
+
+    private void clock_expired_cb (ChessClock clock)
+    {
+        if (current_player.color == Color.WHITE)
+            stop (ChessResult.BLACK_WON, ChessRule.TIMEOUT);
+        else
+            stop (ChessResult.WHITE_WON, ChessRule.TIMEOUT);
+    }
+
     public void abandon ()
     {
         if (!is_started)
diff --git a/glchess/src/glchess.vala b/glchess/src/glchess.vala
index b9c0579..3d5c888 100644
--- a/glchess/src/glchess.vala
+++ b/glchess/src/glchess.vala
@@ -19,6 +19,9 @@ public class Application
     private Gtk.Widget next_move_button;
     private Gtk.Widget last_move_button;
     private Gtk.ComboBox history_combo;
+    private Gtk.Widget white_time_label;
+    private Gtk.Widget black_time_label;
+
     private Gtk.Dialog? preferences_dialog = null;
     private Gtk.ComboBox duration_combo;
     private Gtk.Adjustment duration_adjustment;
@@ -68,6 +71,8 @@ public class Application
         next_move_button = (Gtk.Widget) builder.get_object ("next_move_button");
         last_move_button = (Gtk.Widget) builder.get_object ("last_move_button");
         history_combo = (Gtk.ComboBox) builder.get_object ("history_combo");
+        white_time_label = (Gtk.Widget) builder.get_object ("white_time_label");
+        black_time_label = (Gtk.Widget) builder.get_object ("black_time_label");
         settings.bind ("show-toolbar", builder.get_object ("toolbar"), "visible", SettingsBindFlags.DEFAULT);
         settings.bind ("show-history", builder.get_object ("navigation_box"), "visible", SettingsBindFlags.DEFAULT);
         var view_box = (Gtk.VBox) builder.get_object ("view_box");
@@ -199,6 +204,7 @@ public class Application
         game.turn_started.connect (game_turn_cb);
         game.moved.connect (game_move_cb);
         game.ended.connect (game_end_cb);
+        game.clock.tick.connect (game_clock_tick_cb);
 
         var model = (Gtk.ListStore) history_combo.model;
         model.clear ();
@@ -236,6 +242,9 @@ public class Application
                 break;
             }
         }
+
+        white_time_label.queue_draw ();
+        black_time_label.queue_draw ();
     }
 
     private ChessEngine? get_engine (string name)
@@ -321,6 +330,12 @@ public class Application
             opponent_engine.start_game ();
     }
 
+    private void game_clock_tick_cb (ChessClock clock)
+    {
+        white_time_label.queue_draw ();
+        black_time_label.queue_draw ();
+    }
+
     private void game_turn_cb (ChessGame game, ChessPlayer player)
     {
         if (opponent_engine != null && player == opponent)
@@ -549,6 +564,9 @@ public class Application
         info_title_label.set_markup ("<big><b>%s</b></big>".printf (title));
         info_label.set_text (reason);
         info_bar.show ();
+
+        white_time_label.queue_draw ();
+        black_time_label.queue_draw ();
     }
 
     public void show ()
@@ -606,30 +624,36 @@ public class Application
         quit ();
     }
 
-    [CCode (cname = "G_MODULE_EXPORT black_time_draw_cb", instance_pos = -1)]
-    public bool black_time_draw_cb (Gtk.Widget widget, Cairo.Context c)
+    [CCode (cname = "G_MODULE_EXPORT white_time_draw_cb", instance_pos = -1)]
+    public bool white_time_draw_cb (Gtk.Widget widget, Cairo.Context c)
     {
         double fg[3] = { 0.0, 0.0, 0.0 };
         double bg[3] = { 1.0, 1.0, 1.0 };
 
-        draw_time (widget, c, "â??", fg, bg);
+        draw_time (widget, c, (int) (game.clock.white_duration / 1000 - game.clock.white_used_in_seconds), fg, bg);
         return false;
     }
 
-    [CCode (cname = "G_MODULE_EXPORT white_time_draw_cb", instance_pos = -1)]
-    public bool white_time_draw_cb (Gtk.Widget widget, Cairo.Context c)
+    [CCode (cname = "G_MODULE_EXPORT black_time_draw_cb", instance_pos = -1)]
+    public bool black_time_draw_cb (Gtk.Widget widget, Cairo.Context c)
     {
         double fg[3] = { 1.0, 1.0, 1.0 };
         double bg[3] = { 0.0, 0.0, 0.0 };
 
-        draw_time (widget, c, "â??", fg, bg);
+        draw_time (widget, c, (int) (game.clock.black_duration / 1000 - game.clock.black_used_in_seconds), fg, bg);
         return false;
     }
 
-    private void draw_time (Gtk.Widget widget, Cairo.Context c, string text, double[] fg, double[] bg)
+    private void draw_time (Gtk.Widget widget, Cairo.Context c, int used, double[] fg, double[] bg)
     {
         double alpha = 1.0;
 
+        string text = "â??";
+        if (used >= 60)
+            text = "%d:%02d".printf (used / 60, used % 60);
+        else if (used >= 0)
+            text = ":%02d".printf (used);
+
         if (widget.get_state () == Gtk.StateType.INSENSITIVE)
             alpha = 0.5;
         c.set_source_rgba (bg[0], bg[1], bg[2], alpha);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]