[iagno] Introduce GameState.



commit 8f28b036d46faad90ee94b16949a693c73f37db7
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Fri Mar 22 14:39:52 2019 +0100

    Introduce GameState.
    
    A GameState object keeps all the
    useful informations about a game
    state. It is minimalistic and so
    better when the AI deals with it
    and will also be easily saved in
    an history of the game not based
    on a long list of flipped tiles.
    
    Game is for now a subclass of it
    but that should be changed next.

 src/computer-player.vala |  42 ++---
 src/game.vala            | 478 ++++++++++++++++++++++++++++-------------------
 src/iagno.vala           |   2 +-
 src/test-iagno.vala      | 236 +++++++++++------------
 4 files changed, 414 insertions(+), 344 deletions(-)
---
diff --git a/src/computer-player.vala b/src/computer-player.vala
index df6b51c..1a4d38e 100644
--- a/src/computer-player.vala
+++ b/src/computer-player.vala
@@ -92,7 +92,7 @@ private class ComputerPlayer : Object
 
     private void complete_move (uint8 x, uint8 y)
     {
-        if (game.place_tile (x, y) == 0)
+        if (!game.place_tile (x, y))
         {
             critical ("Computer chose an invalid move: %d,%d\n%s", x, y, game.to_string ());
 
@@ -100,7 +100,7 @@ private class ComputerPlayer : Object
             uint8 new_x;
             uint8 new_y;
             random_select (game, out new_x, out new_y);
-            if (game.place_tile (new_x, new_y) == 0)
+            if (!game.place_tile (new_x, new_y))
             {
                 critical ("Computer chose an invalid move for the second time: %d,%d\n%s", new_x, new_y, 
game.to_string ());
                 assert_not_reached ();
@@ -216,7 +216,7 @@ private class ComputerPlayer : Object
         /* Choose a location to place by building the tree of possible moves and
          * using the minimax algorithm to pick the best branch with the chosen
          * strategy. */
-        Game g = new Game.copy (game);
+        GameState g = new GameState.copy_simplify (game);
         int depth = difficulty_level * 2;
         /* The -1 is because the search sometimes returns NEGATIVE_INFINITY. */
         int a = NEGATIVE_INFINITY - 1;
@@ -230,13 +230,7 @@ private class ComputerPlayer : Object
             if (move == null)
                 assert_not_reached ();
 
-            Game _g = new Game.copy (g);
-
-            if (_g.place_tile (((!) move).x, ((!) move).y, true) == 0)
-            {
-                critical ("Computer marked move (depth %d, %d,%d, %d flips) as valid, but is invalid when 
checking.\n%s", depth, ((!) move).x, ((!) move).y, ((!) move).n_tiles, _g.to_string ());
-                assert_not_reached ();
-            }
+            GameState _g = new GameState.copy_and_move (g, ((!) move).x, ((!) move).y);
 
             int a_new = -1 * search (_g, depth, NEGATIVE_INFINITY, -a);
             if (a_new > a)
@@ -248,7 +242,7 @@ private class ComputerPlayer : Object
         }
     }
 
-    private int search (Game g, int depth, int a, int b)
+    private int search (GameState g, int depth, int a, int b)
         requires (a <= b)
     {
         /* End of the game, return a near-infinite evaluation */
@@ -276,13 +270,7 @@ private class ComputerPlayer : Object
                 if (move == null)
                     assert_not_reached ();
 
-                Game _g = new Game.copy (g);
-
-                if (_g.place_tile (((!) move).x, ((!) move).y) == 0)
-                {
-                    critical ("Computer marked move (depth %d, %d,%d, %d flips) as valid, but is invalid 
when checking.\n%s", depth, ((!) move).x, ((!) move).y, ((!) move).n_tiles, _g.to_string ());
-                    assert_not_reached ();
-                }
+                GameState _g = new GameState.copy_and_move (g, ((!) move).x, ((!) move).y);
 
                 int a_new = -1 * search (_g, depth - 1, -b, -a);
                 if (a_new > a)
@@ -293,11 +281,9 @@ private class ComputerPlayer : Object
                     break;
             }
         }
-        else
+        else // pass
         {
-            Game _g = new Game.copy (g);
-
-            _g.pass ();
+            GameState _g = new GameState.copy_and_pass (g);
 
             int a_new = -1 * search (_g, depth - 1, -b, -a);
             if (a_new > a)
@@ -307,13 +293,13 @@ private class ComputerPlayer : Object
         return a;
     }
 
-    private static void get_possible_moves_sorted (Game g, ref List<PossibleMove?> moves)
+    private static void get_possible_moves_sorted (GameState g, ref List<PossibleMove?> moves)
     {
         for (uint8 x = 0; x < g.size; x++)
         {
             for (uint8 y = 0; y < g.size; y++)
             {
-                uint8 n_tiles = g.place_tile (x, y, false);
+                uint8 n_tiles = g.test_placing_tile (x, y);
                 if (n_tiles == 0)
                     continue;
 
@@ -334,7 +320,7 @@ private class ComputerPlayer : Object
     * * AI
     \*/
 
-    private static int calculate_heuristic (Game g, ref uint8 difficulty_level)
+    private static int calculate_heuristic (GameState g, ref uint8 difficulty_level)
     {
         int tile_difference = (int) g.n_current_tiles - (int) g.n_opponent_tiles;
 
@@ -350,7 +336,7 @@ private class ComputerPlayer : Object
         return tile_difference + eval_heuristic (g) + around (g) ;
     }
 
-    private static int eval_heuristic (Game g)
+    private static int eval_heuristic (GameState g)
     {
         if (g.size != 8)     // TODO
             return 0;
@@ -369,7 +355,7 @@ private class ComputerPlayer : Object
         return count;
     }
 
-    private static int around (Game g)
+    private static int around (GameState g)
     {
         int count = 0;
         for (int8 x = 0; x < (int8) g.size; x++)
@@ -396,7 +382,7 @@ private class ComputerPlayer : Object
         return count;
     }
 
-    private static int is_empty (Game g, int8 x, int8 y)
+    private static int is_empty (GameState g, int8 x, int8 y)
     {
         if (!g.is_valid_location_signed (x, y))
             return 0;
diff --git a/src/game.vala b/src/game.vala
index 4e7436e..34022f0 100644
--- a/src/game.vala
+++ b/src/game.vala
@@ -20,36 +20,93 @@
    along with GNOME Reversi.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-private class Game : Object
+private class GameState : Object
 {
-    /* Tiles on the board */
-    private Player [,] tiles;
+    [CCode (notify = false)] public Player current_color { internal get; protected construct set; default = 
Player.NONE; }
+
+    internal string to_string ()
+    {
+        string s = "\n";
+
+        for (uint8 y = 0; y < size; y++)
+        {
+            for (uint8 x = 0; x < size; x++)
+                s += " " + tiles [x, y].to_string ();
+            s += "\n";
+        }
+
+        return s;
+    }
+
+    /*\
+    * * board
+    \*/
 
     [CCode (notify = false)] public uint8 size { internal get; protected construct; default = 8; }
 
-    /* Undoing */
-    private uint8? [] undo_stack;
-    private int history_index = -1;
+    protected Player [,] tiles;
 
-    /* Color to move next; Dark always plays first;
-     * should be dark if number_of_moves % 2 == 0 */
-    [CCode (notify = false)] internal Player current_color { internal get; private set; default = 
Player.DARK; }
-    [CCode (notify = false)] internal uint8 number_of_moves { internal get; private set; default = 0; }
+    construct
+    {
+        tiles = new Player [size, size];
+    }
 
-    /* Indicate who's the next player who can move */
-    [CCode (notify = false)] internal bool current_player_can_move { internal get; private set; default = 
true; }
-    [CCode (notify = true)] internal bool is_complete { internal get; private set; default = false; }
+    internal GameState.copy_simplify (Game game)
+    {
+        Object (size: game.size, current_color: game.current_color);
 
-    /* Indicate that a player should move */
-    internal signal void turn_ended ();
-    /* Indicate a square has changed */
-    internal signal void square_changed (uint8 x, uint8 y, Player new_color);
+        for (uint8 x = 0; x < size; x++)
+            for (uint8 y = 0; y < size; y++)
+                tiles [x, y] = game.tiles [x, y];
+
+        current_player_can_move = game.current_player_can_move;
+        is_complete = game.is_complete;
+        n_current_tiles = game.n_current_tiles;
+        n_opponent_tiles = game.n_opponent_tiles;
+    }
+
+    internal GameState.copy_and_pass (GameState game)
+    {
+        Object (size: game.size, current_color: Player.flip_color (game.current_color));
+
+        for (uint8 x = 0; x < size; x++)
+            for (uint8 y = 0; y < size; y++)
+                tiles [x, y] = game.tiles [x, y];
+
+        n_current_tiles = game.n_opponent_tiles;
+        n_opponent_tiles = game.n_current_tiles;
+
+        // we already know all that, it is just for checking
+        update_who_can_move ();
+        if (!current_player_can_move || is_complete)
+            assert_not_reached ();
+    }
+
+    internal GameState.copy_and_move (GameState game, uint8 move_x, uint8 move_y)
+    {
+        Player move_color = game.current_color;
+        Object (size: game.size, current_color: Player.flip_color (move_color));
+
+        for (uint8 x = 0; x < size; x++)
+            for (uint8 y = 0; y < size; y++)
+                tiles [x, y] = game.tiles [x, y];
+
+        n_current_tiles = game.n_opponent_tiles;
+        n_opponent_tiles = game.n_current_tiles;
+
+        if (_place_tile (move_x, move_y, move_color, /* apply move */ true) == 0)
+        {
+            critical ("Computer marked move (%d, %d) as valid, but is invalid when checking.\n%s", move_x, 
move_y, to_string ());
+            assert_not_reached ();
+        }
+
+        update_who_can_move ();
+    }
 
     /*\
-    * * Number of tiles on the board
+    * * number of tiles on the board
     \*/
 
-    [CCode (notify = false)] internal uint8 initial_number_of_tiles { internal get; private set; }
     [CCode (notify = false)] internal uint8 n_tiles
     {
         internal get { return n_dark_tiles + n_light_tiles; }
@@ -70,7 +127,7 @@ private class Game : Object
     [CCode (notify = false)] internal uint8 n_current_tiles
     {
         internal get { return current_color == Player.LIGHT ? n_light_tiles : n_dark_tiles; }
-        private set {
+        protected set {
             if (current_color == Player.LIGHT)
                 _n_light_tiles = value;
             else
@@ -81,7 +138,7 @@ private class Game : Object
     [CCode (notify = false)] internal uint8 n_opponent_tiles
     {
         internal get { return current_color == Player.DARK ? n_light_tiles : n_dark_tiles; }
-        private set {
+        protected set {
             if (current_color == Player.DARK)
                 _n_light_tiles = value;
             else
@@ -90,122 +147,20 @@ private class Game : Object
     }
 
     /*\
-    * * Creation / exporting
+    * * public information
     \*/
 
-    [CCode (notify = false)] public bool alternative_start { internal get; protected construct; }
-
-    construct
-    {
-        tiles = new Player [size, size];
-    }
-
-    internal Game (bool alternative_start = false, uint8 _size = 8)
-        requires (_size >= 4)
-        requires (_size <= 16)
-    {
-        Object (alternative_start: alternative_start, size: _size);
-
-        for (uint8 x = 0; x < _size; x++)
-            for (uint8 y = 0; y < _size; y++)
-                tiles [x, y] = Player.NONE;
-
-        init_undo_stack (_size, out undo_stack);
-
-        if (_size % 2 == 0)
-        {
-            /* Setup board with four tiles by default */
-            initial_number_of_tiles = 4;
-            tiles [_size / 2 - 1, _size / 2 - 1] = alternative_start ? Player.DARK : Player.LIGHT;
-            tiles [_size / 2 - 1, _size / 2] = Player.DARK;
-            tiles [_size / 2, _size / 2 - 1] = alternative_start ? Player.LIGHT : Player.DARK;
-            tiles [_size / 2, _size / 2] = Player.LIGHT;
-            n_current_tiles = 2;
-            n_opponent_tiles = 2;
-        }
-        else
-        {
-            /* Logical starting position for odd board */
-            initial_number_of_tiles = 7;
-            tiles [(_size - 1) / 2, (_size - 1) / 2] = Player.DARK;
-            tiles [(_size + 1) / 2, (_size - 3) / 2] = alternative_start ? Player.LIGHT : Player.DARK;
-            tiles [(_size - 3) / 2, (_size + 1) / 2] = alternative_start ? Player.LIGHT : Player.DARK;
-            tiles [(_size - 1) / 2, (_size - 3) / 2] = Player.LIGHT;
-            tiles [(_size - 3) / 2, (_size - 1) / 2] = alternative_start ? Player.DARK : Player.LIGHT;
-            tiles [(_size + 1) / 2, (_size - 1) / 2] = alternative_start ? Player.DARK : Player.LIGHT;
-            tiles [(_size - 1) / 2, (_size + 1) / 2] = Player.LIGHT;
-            n_current_tiles = 3;
-            n_opponent_tiles = 4;
-        }
-    }
-
-    internal Game.from_strings (string [] setup, Player to_move, uint8 _size = 8)
-        requires (_size >= 4)
-        requires (_size <= 16)
-        requires (to_move != Player.NONE)
-        requires (setup.length == _size)
-    {
-        Object (size: _size);
-
-        initial_number_of_tiles = (size % 2 == 0) ? 4 : 7;
-        init_undo_stack (_size, out undo_stack);
-
-        _n_dark_tiles = 0;
-        _n_light_tiles = 0;
-
-        for (uint8 y = 0; y < _size; y++)
-        {
-            if (setup [y].length != _size * 2)
-                warn_if_reached ();
-            for (uint8 x = 0; x < _size; x++)
-            {
-                Player player = Player.from_char (setup [y][x * 2 + 1]);
-                if      (player == Player.DARK)  _n_dark_tiles++;
-                else if (player == Player.LIGHT) _n_light_tiles++;
-                tiles [x, y] = player;
-            }
-        }
-
-        current_color = to_move;
-
-        warn_if_fail (string.joinv ("\n", (string?[]) setup).strip () == to_string ().strip ());
-    }
-
-    internal string to_string ()
-    {
-        string s = "\n";
-
-        for (uint8 y = 0; y < size; y++)
-        {
-            for (uint8 x = 0; x < size; x++)
-                s += " " + tiles [x, y].to_string ();
-            s += "\n";
-        }
-
-        return s;
-    }
-
-    internal Game.copy (Game game)
+    internal Player get_owner (uint8 x, uint8 y)
+        requires (is_valid_location_unsigned (x, y))
     {
-        Object (size: game.size);
-
-        for (uint8 x = 0; x < size; x++)
-            for (uint8 y = 0; y < size; y++)
-                tiles [x, y] = game.tiles [x, y];
-
-        number_of_moves         = game.number_of_moves;
-        current_color           = game.current_color;
-        n_current_tiles         = game.n_current_tiles;
-        n_opponent_tiles        = game.n_opponent_tiles;
-        current_player_can_move = game.current_player_can_move;
-
-        init_undo_stack (_size, out undo_stack);
-        /* warning: history not copied */
+        return tiles [x, y];
     }
-
-    /*\
-    * * Public information
-    \*/
+ // internal new uint8 get (uint8 x, uint8 y)    // allows calling game [x, y]
+ //     requires (x < size)
+ //     requires (y < size)
+ // {
+ //     return tiles [x, y];
+ // }
 
     internal inline bool is_valid_location_signed (int8 x, int8 y)
     {
@@ -218,80 +173,53 @@ private class Game : Object
         return x < size && y < size;
     }
 
-    internal Player get_owner (uint8 x, uint8 y)
-        requires (is_valid_location_unsigned (x, y))
-    {
-        return tiles [x, y];
-    }
+    /*\
+    * * ... // completeness
+    \*/
 
-    internal bool can_place (uint8 x, uint8 y, Player color)
-        requires (is_valid_location_unsigned (x, y))
-        requires (color != Player.NONE)
+    internal uint8 test_placing_tile (uint8 x, uint8 y)
     {
-        if (tiles [x, y] != Player.NONE)
-            return false;
-
-        if (can_flip_tiles (x, y,  1,  0, color) > 0) return true;
-        if (can_flip_tiles (x, y,  1,  1, color) > 0) return true;
-        if (can_flip_tiles (x, y,  0,  1, color) > 0) return true;
-        if (can_flip_tiles (x, y, -1,  1, color) > 0) return true;
-        if (can_flip_tiles (x, y, -1,  0, color) > 0) return true;
-        if (can_flip_tiles (x, y, -1, -1, color) > 0) return true;
-        if (can_flip_tiles (x, y,  0, -1, color) > 0) return true;
-        if (can_flip_tiles (x, y,  1, -1, color) > 0) return true;
-        return false;
+        return _place_tile (x, y, current_color, /* apply move */ false);
     }
 
-    /*\
-    * * Actions (apart undo)
-    \*/
-
-    internal uint8 place_tile (uint8 x, uint8 y, bool apply = true)
+    protected uint8 _place_tile (uint8 x, uint8 y, Player color, bool apply)
         requires (is_valid_location_unsigned (x, y))
     {
         if (tiles [x, y] != Player.NONE)
             return 0;
 
         uint8 tiles_turned = 0;
-        tiles_turned += flip_tiles (x, y,  1,  0, apply);
-        tiles_turned += flip_tiles (x, y,  1,  1, apply);
-        tiles_turned += flip_tiles (x, y,  0,  1, apply);
-        tiles_turned += flip_tiles (x, y, -1,  1, apply);
-        tiles_turned += flip_tiles (x, y, -1,  0, apply);
-        tiles_turned += flip_tiles (x, y, -1, -1, apply);
-        tiles_turned += flip_tiles (x, y,  0, -1, apply);
-        tiles_turned += flip_tiles (x, y,  1, -1, apply);
+        tiles_turned += flip_tiles (x, y, color,  1,  0, apply);
+        tiles_turned += flip_tiles (x, y, color,  1,  1, apply);
+        tiles_turned += flip_tiles (x, y, color,  0,  1, apply);
+        tiles_turned += flip_tiles (x, y, color, -1,  1, apply);
+        tiles_turned += flip_tiles (x, y, color, -1,  0, apply);
+        tiles_turned += flip_tiles (x, y, color, -1, -1, apply);
+        tiles_turned += flip_tiles (x, y, color,  0, -1, apply);
+        tiles_turned += flip_tiles (x, y, color,  1, -1, apply);
 
         if (tiles_turned == 0)
             return 0;
 
         if (apply)
         {
-            set_tile (x, y);
+            set_tile (x, y, color);
             end_of_turn ();
         }
 
         return tiles_turned;
     }
 
-    internal void pass ()
-        requires (!current_player_can_move)
-    {
-        end_of_turn ();
-    }
+    protected virtual void end_of_turn () {}
 
-    private void end_of_turn ()
-        requires (history_index >= -1 && history_index < undo_stack.length - 2)
-    {
-        current_color = Player.flip_color (current_color);
-        number_of_moves++;
-        history_index++;
-        undo_stack [history_index] = null;
-        update_who_can_move ();
-        turn_ended ();
-    }
+    /*\
+    * * can move
+    \*/
 
-    private void update_who_can_move ()
+    [CCode (notify = false)] internal bool current_player_can_move { internal get; private set; default = 
true; }
+    [CCode (notify = true)] internal bool is_complete { internal get; protected set; default = false; }
+
+    protected void update_who_can_move ()
     {
         Player enemy = Player.flip_color (current_color);
         bool opponent_can_move = false;
@@ -313,13 +241,31 @@ private class Game : Object
             is_complete = true;
     }
 
+    internal bool can_place (uint8 x, uint8 y, Player color)
+        requires (is_valid_location_unsigned (x, y))
+        requires (color != Player.NONE)
+    {
+        if (tiles [x, y] != Player.NONE)
+            return false;
+
+        if (can_flip_tiles (x, y, color,  1,  0) > 0) return true;
+        if (can_flip_tiles (x, y, color,  1,  1) > 0) return true;
+        if (can_flip_tiles (x, y, color,  0,  1) > 0) return true;
+        if (can_flip_tiles (x, y, color, -1,  1) > 0) return true;
+        if (can_flip_tiles (x, y, color, -1,  0) > 0) return true;
+        if (can_flip_tiles (x, y, color, -1, -1) > 0) return true;
+        if (can_flip_tiles (x, y, color,  0, -1) > 0) return true;
+        if (can_flip_tiles (x, y, color,  1, -1) > 0) return true;
+        return false;
+    }
+
     /*\
-    * * Flipping tiles
+    * * flipping tiles
     \*/
 
-    private uint8 flip_tiles (uint8 x, uint8 y, int8 x_step, int8 y_step, bool apply)
+    private uint8 flip_tiles (uint8 x, uint8 y, Player color, int8 x_step, int8 y_step, bool apply)
     {
-        uint8 enemy_count = can_flip_tiles (x, y, x_step, y_step, current_color);
+        uint8 enemy_count = can_flip_tiles (x, y, color, x_step, y_step);
         if (enemy_count == 0)
             return 0;
 
@@ -327,15 +273,18 @@ private class Game : Object
         {
             for (int8 i = 1; i <= enemy_count; i++)
             {
-                n_opponent_tiles--;
-                set_tile (x + (uint8) (i * x_step),
-                          y + (uint8) (i * y_step));
+                if      (color == Player.DARK)  _n_light_tiles--;
+                else if (color == Player.LIGHT) _n_dark_tiles--;
+                else    assert_not_reached ();
+                set_tile ((uint8) ((int8) x + (i * x_step)),
+                          (uint8) ((int8) y + (i * y_step)),
+                          color);
             }
         }
         return enemy_count;
     }
 
-    private uint8 can_flip_tiles (uint8 x, uint8 y, int8 x_step, int8 y_step, Player color)
+    protected uint8 can_flip_tiles (uint8 x, uint8 y, Player color, int8 x_step, int8 y_step)
     {
         Player enemy = Player.flip_color (color);
 
@@ -350,24 +299,150 @@ private class Game : Object
         } while (is_valid_location_signed (xt, yt) && tiles [xt, yt] == enemy);
 
         /* Must be a line of enemy pieces then one of ours */
-        if (enemy_count == 0 || !is_valid_location_signed (xt, yt) || tiles [xt, yt] != color)
+        if (enemy_count <= 0 || !is_valid_location_signed (xt, yt) || tiles [xt, yt] != color)
             return 0;
 
         return (uint8) enemy_count;
     }
 
-    private void set_tile (uint8 x, uint8 y)
+    protected virtual void set_tile (uint8 x, uint8 y, Player color)
+    {
+        if      (color == Player.DARK)  _n_dark_tiles++;
+        else if (color == Player.LIGHT) _n_light_tiles++;
+        else    assert_not_reached ();
+        tiles [x, y] = color;
+    }
+}
+
+private class Game : GameState
+{
+    /* Undoing */
+    private uint8? [] undo_stack;
+    private int history_index = -1;
+
+    [CCode (notify = false)] internal uint8 number_of_moves { internal get; private set; default = 0; }
+
+    /* Indicate that a player should move */
+    internal signal void turn_ended ();
+    /* Indicate a square has changed */
+    internal signal void square_changed (uint8 x, uint8 y, Player new_color);
+
+    [CCode (notify = false)] internal uint8 initial_number_of_tiles { internal get; private set; }
+
+    /*\
+    * * creation
+    \*/
+
+    [CCode (notify = false)] public bool alternative_start { internal get; protected construct; }
+
+    internal Game (bool alternative_start = false, uint8 _size = 8)
+        requires (_size >= 4)
+        requires (_size <= 16)
+    {
+        Object (alternative_start: alternative_start, size: _size, current_color: /* Dark always starts */ 
Player.DARK);
+
+        for (uint8 x = 0; x < _size; x++)
+            for (uint8 y = 0; y < _size; y++)
+                tiles [x, y] = Player.NONE;
+
+        init_undo_stack (_size, out undo_stack);
+
+        if (_size % 2 == 0)
+        {
+            /* Setup board with four tiles by default */
+            initial_number_of_tiles = 4;
+            tiles [_size / 2 - 1, _size / 2 - 1] = alternative_start ? Player.DARK : Player.LIGHT;
+            tiles [_size / 2 - 1, _size / 2] = Player.DARK;
+            tiles [_size / 2, _size / 2 - 1] = alternative_start ? Player.LIGHT : Player.DARK;
+            tiles [_size / 2, _size / 2] = Player.LIGHT;
+            n_current_tiles = 2;
+            n_opponent_tiles = 2;
+        }
+        else
+        {
+            /* Logical starting position for odd board */
+            initial_number_of_tiles = 7;
+            tiles [(_size - 1) / 2, (_size - 1) / 2] = Player.DARK;
+            tiles [(_size + 1) / 2, (_size - 3) / 2] = alternative_start ? Player.LIGHT : Player.DARK;
+            tiles [(_size - 3) / 2, (_size + 1) / 2] = alternative_start ? Player.LIGHT : Player.DARK;
+            tiles [(_size - 1) / 2, (_size - 3) / 2] = Player.LIGHT;
+            tiles [(_size - 3) / 2, (_size - 1) / 2] = alternative_start ? Player.DARK : Player.LIGHT;
+            tiles [(_size + 1) / 2, (_size - 1) / 2] = alternative_start ? Player.DARK : Player.LIGHT;
+            tiles [(_size - 1) / 2, (_size + 1) / 2] = Player.LIGHT;
+            n_current_tiles = 3;
+            n_opponent_tiles = 4;
+        }
+    }
+
+    internal Game.from_strings (string [] setup, Player to_move, uint8 _size = 8)
+        requires (_size >= 4)
+        requires (_size <= 16)
+        requires (to_move != Player.NONE)
+        requires (setup.length == _size)
+    {
+        Object (size: _size, current_color: to_move);
+
+        initial_number_of_tiles = (_size % 2 == 0) ? 4 : 7;
+        init_undo_stack (_size, out undo_stack);
+
+        uint8 n_dark_tiles = 0;
+        uint8 n_light_tiles = 0;
+
+        for (uint8 y = 0; y < _size; y++)
+        {
+            if (setup [y].length != _size * 2)
+                warn_if_reached ();
+            for (uint8 x = 0; x < _size; x++)
+            {
+                Player player = Player.from_char (setup [y][x * 2 + 1]);
+                if      (player == Player.DARK)  n_dark_tiles++;
+                else if (player == Player.LIGHT) n_light_tiles++;
+                tiles [x, y] = player;
+            }
+        }
+
+        if (to_move == Player.DARK)
+        {
+            n_current_tiles  = n_dark_tiles;
+            n_opponent_tiles = n_light_tiles;
+        }
+        else
+        {
+            n_current_tiles  = n_light_tiles;
+            n_opponent_tiles = n_dark_tiles;
+        }
+
+        warn_if_fail (string.joinv ("\n", (string?[]) setup).strip () == to_string ().strip ());
+    }
+
+    /*\
+    * * actions (apart undo)
+    \*/
+
+    internal /* success */ bool place_tile (uint8 x, uint8 y)
+    {
+        return _place_tile (x, y, current_color, /* apply move */ true) != 0;
+    }
+
+    internal void pass ()
+        requires (!current_player_can_move)
+    {
+        end_of_turn ();
+    }
+
+    protected override void end_of_turn ()
         requires (history_index >= -1 && history_index < undo_stack.length - 2)
     {
-        n_current_tiles++;
+        current_color = Player.flip_color (current_color);
+        number_of_moves++;
         history_index++;
-        undo_stack [history_index] = x + y * size;
-        tiles [x, y] = current_color;
-        square_changed (x, y, current_color);
+        undo_stack [history_index] = null;
+        update_who_can_move ();
+        turn_ended ();
     }
 
     /*\
-    * * Undo
+    * * undo
     \*/
 
     internal void undo (uint8 count = 1)
@@ -411,6 +486,15 @@ private class Game : Object
         }
     }
 
+    protected override void set_tile (uint8 x, uint8 y, Player color)
+        requires (history_index >= -1 && history_index < undo_stack.length - 2)
+    {
+        history_index++;
+        undo_stack [history_index] = x + y * size;
+        base.set_tile (x, y, color);
+        square_changed (x, y, color);
+    }
+
     private void unset_tile (uint8 tile_number, Player replacement_color)
     {
         n_current_tiles--;
diff --git a/src/iagno.vala b/src/iagno.vala
index a47d478..8310014 100644
--- a/src/iagno.vala
+++ b/src/iagno.vala
@@ -515,7 +515,7 @@ private class Iagno : Gtk.Application
         if ((game.current_color != player_one && computer != null) || !game.current_player_can_move)
             return;
 
-        if (game.place_tile (x, y) == 0)
+        if (!game.place_tile (x, y))
         {
             /* Translators: during a game, notification to display when the player tries to make an illegal 
move */
             window.set_subtitle (_("You can’t move there!"));
diff --git a/src/test-iagno.vala b/src/test-iagno.vala
index bc2859b..4a3bc4b 100644
--- a/src/test-iagno.vala
+++ b/src/test-iagno.vala
@@ -91,7 +91,7 @@ private class TestIagno : Object
                             " L L L L L L L L" };
         Game game = new Game.from_strings (board, Player.DARK);
         assert_true (game.number_of_moves == 0);
-        assert_true (game.place_tile (7, 2) > 0);
+        assert_true (game.place_tile (7, 2));
         assert_true (game.number_of_moves == 1);
         assert_true (!game.current_player_can_move);
         game.pass ();
@@ -99,7 +99,7 @@ private class TestIagno : Object
         game.undo (2);
         assert_true (game.number_of_moves == 0);
         assert_true (game.to_string ().strip () == string.joinv ("\n", board).strip ());
-        assert_true (game.place_tile (7, 2) > 0);
+        assert_true (game.place_tile (7, 2));
         assert_true (game.number_of_moves == 1);
         assert_true (!game.current_player_can_move);
         game.undo (1);
@@ -111,9 +111,9 @@ private class TestIagno : Object
     {
         Game game = new Game ();
         assert_true (game.number_of_moves == 0);
-        game.place_tile (2, 3);
+        assert_true (game.place_tile (2, 3));
         assert_true (game.number_of_moves == 1);
-        game.place_tile (2, 2);
+        assert_true (game.place_tile (2, 2));
         assert_true (game.number_of_moves == 2);
     }
 
@@ -129,7 +129,7 @@ private class TestIagno : Object
                             " D D D D D D D D" };
         Game game = new Game.from_strings (board, Player.DARK);
         assert_true (game.current_color == Player.DARK);
-        assert_true (game.place_tile (1, 2) > 0);
+        assert_true (game.place_tile (1, 2));
         assert_true (game.current_color == Player.LIGHT);
         assert_true (!game.current_player_can_move);
         game.pass ();
@@ -235,61 +235,61 @@ private class TestIagno : Object
         Game game = new Game.from_strings (board, Player.DARK);
         ComputerPlayer ai = new ComputerPlayer (game, /* AI level */ 3);
 
-        assert_true (game.place_tile (4, 1, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 1));
         assert_true (ai.force_moving (5, 5));
-        assert_true (game.place_tile (4, 5, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 5));
         assert_true (ai.force_moving (3, 5));
-        assert_true (game.place_tile (2, 5, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 5));
         assert_true (ai.force_moving (2, 4));
-        assert_true (game.place_tile (4, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 6));
         assert_true (ai.force_moving (2, 6));
-        assert_true (game.place_tile (1, 4, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 4));
         assert_true (ai.force_moving (0, 4));
-        assert_true (game.place_tile (2, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 3));
         assert_true (ai.force_moving (1, 3));
-        assert_true (game.place_tile (1, 5, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 5));
         assert_true (ai.force_moving (2, 2));
-        assert_true (game.place_tile (3, 2, /* apply */ true) != 0);
+        assert_true (game.place_tile (3, 2));
         assert_true (ai.force_moving (5, 2));
-        assert_true (game.place_tile (6, 4, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 4));
         assert_true (ai.force_moving (5, 6));
-        assert_true (game.place_tile (3, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (3, 0));
         assert_true (ai.force_moving (0, 5));
-        assert_true (game.place_tile (3, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (3, 6));
         assert_true (ai.force_moving (5, 7));
-        assert_true (game.place_tile (0, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 3));
         assert_true (ai.force_moving (0, 2));
-        assert_true (game.place_tile (6, 5, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 5));
         assert_true (ai.force_moving (1, 2));
-        assert_true (game.place_tile (3, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (3, 7));
         assert_true (ai.force_moving (2, 7));
-        assert_true (game.place_tile (4, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 7));
         assert_true (ai.force_moving (6, 6));
-        assert_true (game.place_tile (2, 1, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 1));
         assert_true (ai.force_moving (2, 0));
-        assert_true (game.place_tile (1, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 0));
         assert_true (ai.force_moving (1, 1));
-        assert_true (game.place_tile (6, 2, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 2));
         assert_true (ai.force_moving (4, 0));
-        assert_true (game.place_tile (5, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (5, 0));
         assert_true (ai.force_moving (7, 3));
-        assert_true (game.place_tile (6, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 3));
         assert_true (ai.force_moving (7, 2));
-        assert_true (game.place_tile (5, 1, /* apply */ true) != 0);
+        assert_true (game.place_tile (5, 1));
         assert_true (ai.force_moving (6, 1));
-        assert_true (game.place_tile (7, 4, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 4));
         assert_true (ai.force_moving (7, 5));
-        assert_true (game.place_tile (7, 1, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 1));
         assert_true (ai.force_moving (7, 0));
-        assert_true (game.place_tile (7, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 7));
         assert_true (ai.force_moving (6, 7));
-        assert_true (game.place_tile (7, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 6));
         assert_true (ai.force_moving (6, 0));
-        assert_true (game.place_tile (0, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 0));
         assert_true (ai.force_moving (0, 1));
-        assert_true (game.place_tile (0, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 6));
         assert_true (ai.force_moving (1, 6));
-        assert_true (game.place_tile (1, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 7));
         assert_true (ai.force_moving (0, 7));
     }
 
@@ -308,61 +308,61 @@ private class TestIagno : Object
         Game game = new Game.from_strings (board, Player.DARK);
         ComputerPlayer ai = new ComputerPlayer (game, /* AI level */ 3);
 
-        assert_true (game.place_tile (4, 2, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 2));
         assert_true (ai.force_moving (5, 5));
-        assert_true (game.place_tile (6, 4, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 4));
         assert_true (ai.force_moving (5, 2));
-        assert_true (game.place_tile (6, 5, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 5));
         assert_true (ai.force_moving (2, 2));
-        assert_true (game.place_tile (3, 1, /* apply */ true) != 0);
+        assert_true (game.place_tile (3, 1));
         assert_true (ai.force_moving (4, 5));
-        assert_true (game.place_tile (3, 5, /* apply */ true) != 0);
+        assert_true (game.place_tile (3, 5));
         assert_true (ai.force_moving (6, 3));
-        assert_true (game.place_tile (2, 4, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 4));
         assert_true (ai.force_moving (3, 6));
-        assert_true (game.place_tile (7, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 3));
         assert_true (ai.force_moving (2, 5));
-        assert_true (game.place_tile (3, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (3, 7));
         assert_true (ai.force_moving (7, 5));
-        assert_true (game.place_tile (5, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (5, 6));
         assert_true (ai.force_moving (5, 7));
-        assert_true (game.place_tile (6, 2, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 2));
         assert_true (ai.force_moving (4, 6));
-        assert_true (game.place_tile (4, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 7));
         assert_true (ai.force_moving (2, 7));
-        assert_true (game.place_tile (1, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 3));
         assert_true (ai.force_moving (1, 2));
-        assert_true (game.place_tile (0, 2, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 2));
         assert_true (ai.force_moving (2, 1));
-        assert_true (game.place_tile (2, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 0));
         assert_true (ai.force_moving (1, 1));
-        assert_true (game.place_tile (2, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 6));
         assert_true (ai.force_moving (1, 7));
-        assert_true (game.place_tile (4, 1, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 1));
         assert_true (ai.force_moving (7, 4));
-        assert_true (game.place_tile (7, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 6));
         assert_true (ai.force_moving (0, 4));
-        assert_true (game.place_tile (0, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 3));
         assert_true (ai.force_moving (0, 1));
-        assert_true (game.place_tile (1, 4, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 4));
         assert_true (ai.force_moving (6, 6));
-        assert_true (game.place_tile (1, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 6));
         assert_true (ai.force_moving (4, 0));
-        assert_true (game.place_tile (3, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (3, 0));
         assert_true (ai.force_moving (1, 0));
-        assert_true (game.place_tile (5, 1, /* apply */ true) != 0);
+        assert_true (game.place_tile (5, 1));
         assert_true (ai.force_moving (7, 2));
-        assert_true (game.place_tile (7, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 7));
         assert_true (ai.force_moving (6, 0));
-        assert_true (game.place_tile (6, 1, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 1));
         assert_true (ai.force_moving (6, 7));
-        assert_true (game.place_tile (0, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 7));
         assert_true (ai.force_moving (5, 0));
-        assert_true (game.place_tile (0, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 0));
         assert_true (ai.force_moving (0, 6));
-        assert_true (game.place_tile (0, 5, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 5));
         assert_true (ai.force_moving (1, 5));
-        assert_true (game.place_tile (7, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 0));
         assert_true (ai.force_moving (7, 1));
     }
 
@@ -382,61 +382,61 @@ private class TestIagno : Object
         ComputerPlayer ai = new ComputerPlayer (game, /* AI level */ 3);
 
         assert_true (ai.force_moving (3, 5));
-        assert_true (game.place_tile (6, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 3));
         assert_true (ai.force_moving (3, 2));
-        assert_true (game.place_tile (2, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 3));
         assert_true (ai.force_moving (1, 4));
-        assert_true (game.place_tile (4, 5, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 5));
         assert_true (ai.force_moving (6, 5));
-        assert_true (game.place_tile (2, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 6));
         assert_true (ai.force_moving (2, 5));
-        assert_true (game.place_tile (3, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (3, 6));
         assert_true (ai.force_moving (2, 2));
-        assert_true (game.place_tile (0, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 3));
         assert_true (ai.force_moving (6, 2));
-        assert_true (game.place_tile (1, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 3));
         assert_true (ai.force_moving (0, 5));
-        assert_true (game.place_tile (4, 1, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 1));
         assert_true (ai.force_moving (5, 1));
-        assert_true (game.place_tile (6, 4, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 4));
         assert_true (ai.force_moving (1, 5));
-        assert_true (game.place_tile (5, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (5, 0));
         assert_true (ai.force_moving (7, 3));
-        assert_true (game.place_tile (2, 4, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 4));
         assert_true (ai.force_moving (3, 0));
-        assert_true (game.place_tile (4, 2, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 2));
         assert_true (ai.force_moving (3, 1));
-        assert_true (game.place_tile (0, 4, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 4));
         assert_true (ai.force_moving (0, 2));
-        assert_true (game.place_tile (1, 2, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 2));
         assert_true (ai.force_moving (4, 7));
-        assert_true (game.place_tile (2, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 7));
         assert_true (ai.force_moving (0, 6));
-        assert_true (game.place_tile (4, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 6));
         assert_true (ai.force_moving (5, 7));
-        assert_true (game.place_tile (5, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (5, 6));
         assert_true (ai.force_moving (2, 1));
-        assert_true (game.place_tile (2, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 0));
         assert_true (ai.force_moving (1, 0));
-        assert_true (game.place_tile (7, 5, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 5));
         assert_true (ai.force_moving (6, 7));
-        assert_true (game.place_tile (7, 2, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 2));
         assert_true (ai.force_moving (7, 6));
-        assert_true (game.place_tile (7, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 7));
         assert_true (ai.force_moving (3, 7));
-        assert_true (game.place_tile (7, 4, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 4));
         assert_true (ai.force_moving (1, 1));
-        assert_true (game.place_tile (6, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 6));
         assert_true (ai.force_moving (6, 1));
-        assert_true (game.place_tile (0, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 0));
         assert_true (ai.force_moving (1, 7));
-        assert_true (game.place_tile (4, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 0));
         assert_true (ai.force_moving (6, 0));
-        assert_true (game.place_tile (0, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 7));
         assert_true (ai.force_moving (0, 1));
-        assert_true (game.place_tile (1, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 6));
         assert_true (ai.force_moving (7, 1));
-        assert_true (game.place_tile (7, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 0));
     }
 
     private static void test_complete_game_4 ()
@@ -455,63 +455,63 @@ private class TestIagno : Object
         ComputerPlayer ai = new ComputerPlayer (game, /* AI level */ 3);
 
         assert_true (ai.force_moving (5, 4));
-        assert_true (game.place_tile (6, 4, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 4));
         assert_true (ai.force_moving (1, 5));
-        assert_true (game.place_tile (2, 2, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 2));
         assert_true (ai.force_moving (3, 5));
-        assert_true (game.place_tile (1, 4, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 4));
         assert_true (ai.force_moving (6, 3));
-        assert_true (game.place_tile (4, 2, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 2));
         assert_true (ai.force_moving (4, 1));
-        assert_true (game.place_tile (5, 5, /* apply */ true) != 0);
+        assert_true (game.place_tile (5, 5));
         assert_true (ai.force_moving (2, 3));
-        assert_true (game.place_tile (4, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 0));
         assert_true (ai.force_moving (5, 6));
-        assert_true (game.place_tile (2, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 6));
         assert_true (ai.force_moving (2, 5));
-        assert_true (game.place_tile (0, 4, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 4));
         assert_true (ai.force_moving (0, 6));
-        assert_true (game.place_tile (1, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 3));
         assert_true (ai.force_moving (5, 1));
-        assert_true (game.place_tile (6, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 7));
         assert_true (ai.force_moving (3, 6));
-        assert_true (game.place_tile (3, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (3, 7));
         assert_true (ai.force_moving (5, 0));
-        assert_true (game.place_tile (6, 5, /* apply */ true) != 0);
+        assert_true (game.place_tile (6, 5));
         assert_true (ai.force_moving (3, 0));
-        assert_true (game.place_tile (3, 1, /* apply */ true) != 0);
+        assert_true (game.place_tile (3, 1));
         assert_true (ai.force_moving (0, 2));
-        assert_true (game.place_tile (5, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (5, 3));
         assert_true (ai.force_moving (7, 4));
-        assert_true (game.place_tile (7, 2, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 2));
         assert_true (ai.force_moving (7, 5));
-        assert_true (game.place_tile (4, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 6));
         assert_true (ai.force_moving (1, 2));
-        assert_true (game.place_tile (7, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 3));
         assert_true (ai.force_moving (6, 2));
-        assert_true (game.place_tile (7, 6, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 6));
         assert_true (ai.force_moving (2, 7));
-        assert_true (game.place_tile (1, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 7));
         assert_true (ai.force_moving (2, 0));
-        assert_true (game.place_tile (7, 1, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 1));
         assert_true (ai.force_moving (6, 6));
-        assert_true (game.place_tile (0, 3, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 3));
         assert_true (ai.force_moving (0, 5));
-        assert_true (game.place_tile (7, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 7));
         assert_true (ai.force_moving (6, 1));
-        assert_true (game.place_tile (7, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (7, 0));
         assert_true (ai.force_moving (6, 0));
-        assert_true (game.place_tile (1, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (1, 0));
         assert_true (ai.force_moving (1, 6));
-        assert_true (game.place_tile (2, 1, /* apply */ true) != 0);
+        assert_true (game.place_tile (2, 1));
         game.pass ();
-        assert_true (game.place_tile (0, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 7));
         game.pass ();
-        assert_true (game.place_tile (0, 1, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 1));
         assert_true (ai.force_moving (1, 1));
-        assert_true (game.place_tile (0, 0, /* apply */ true) != 0);
+        assert_true (game.place_tile (0, 0));
         game.pass ();
-        assert_true (game.place_tile (4, 7, /* apply */ true) != 0);
+        assert_true (game.place_tile (4, 7));
         assert_true (ai.force_moving (5, 7));
     }
 }


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