[four-in-a-row] Add --size command-line support.



commit 26ee7b485f3f4785e9da68cfe2bfa2f09068ad40
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date:   Fri Dec 27 11:17:28 2019 +0100

    Add --size command-line support.

 src/ai.vala              | 79 ++++++++++++++++++++++++++++-----------------
 src/four-in-a-row.vala   | 49 +++++++++++++++++++---------
 src/game-board-view.vala | 20 ++++++------
 src/game-board.vala      | 27 ++++++++++------
 src/player.vala          | 10 +++---
 src/test-ai.vala         | 84 ++++++++++++++++++++++++------------------------
 6 files changed, 158 insertions(+), 111 deletions(-)
---
diff --git a/src/ai.vala b/src/ai.vala
index cea5990..9014133 100644
--- a/src/ai.vala
+++ b/src/ai.vala
@@ -37,20 +37,20 @@ namespace AI
     \*/
 
     /* returns the column number in which the next move has to be made. Returns uint8.MAX if the board is 
full. */
-    internal static uint8 playgame (Difficulty level, string vstr)
+    internal static uint8 playgame (uint8 size, Difficulty level, string vstr)
     {
         Player [,] board;
-        init_board_from_string (vstr, out board);
+        init_board_from_string (size, vstr, out board);
 
         /* if AI can win by making a move immediately, make that move */
         uint8 temp = immediate_win (Player.OPPONENT, ref board);
-        if (temp < BOARD_COLUMNS)
+        if (temp < size)
             return temp;
 
         /* if HUMAN can win by making a move immediately,
            we make AI move in that column so as avoid loss */
         temp = immediate_win (Player.HUMAN, ref board);
-        if (temp < BOARD_COLUMNS)
+        if (temp < size)
             return temp;
 
         /* call negamax tree on the current state of the board */
@@ -62,17 +62,17 @@ namespace AI
     }
 
     /* utility function for testing purposes */
-    internal static uint8 playandcheck (Difficulty level, string vstr)
+    internal static uint8 playandcheck (uint8 size, Difficulty level, string vstr)
     {
         Player [,] board;
-        init_board_from_string (vstr, out board);
+        init_board_from_string (size, vstr, out board);
 
         uint8 temp = immediate_win (Player.OPPONENT, ref board);
-        if (temp < BOARD_COLUMNS)
+        if (temp < size)
             return 100;
 
         temp = immediate_win (Player.HUMAN, ref board);
-        if (temp < BOARD_COLUMNS)
+        if (temp < size)
             return temp;
 
         /* call negamax tree on the current state of the board */
@@ -87,12 +87,14 @@ namespace AI
     \*/
 
     /* vstr is the sequence of moves made until now;  */
-    private static void init_board_from_string (string vstr, out Player [,] board)
+    private static void init_board_from_string (uint8 size, string vstr, out Player [,] board)
     {
+        uint8 n_rows = size - 1;
+        uint8 n_cols = size;
         /* empty board */
-        board = new Player [BOARD_ROWS, BOARD_COLUMNS];
-        for (uint8 i = 0; i < BOARD_ROWS; i++)
-            for (uint8 j = 0; j < BOARD_COLUMNS; j++)
+        board = new Player [n_rows, n_cols];
+        for (uint8 i = 0; i < n_rows; i++)
+            for (uint8 j = 0; j < n_cols; j++)
                 board [i, j] = Player.NOBODY;
 
         /* AI will make the first move */
@@ -105,6 +107,7 @@ namespace AI
 
     private static inline void update_board (string vstr, ref Player [,] board)
     {
+        uint8 n_rows = (uint8) board.length [0];
         Player move = vstr.length % 2 == 0 ? Player.OPPONENT : Player.HUMAN;
 
         for (uint8 i = 0; i < vstr.length; i++)
@@ -113,7 +116,7 @@ namespace AI
 
             /* find the cell on which the move is made */
             int8 row;
-            for (row = BOARD_ROWS - 1; row >= 0 && board [row, column] != Player.NOBODY; row--);
+            for (row = n_rows - 1; row >= 0 && board [row, column] != Player.NOBODY; row--);
 
             board [row, column] = move;
 
@@ -129,6 +132,7 @@ namespace AI
        It returns the value of the current node. For nodes at height == 0, the value is determined by a 
heuristic function. */
     private static int16 negamax (uint8 height, int16 alpha, int16 beta, Player player, Difficulty level, 
ref Player [,] board, ref uint8 next_move_in_column)
     {
+        uint8 n_cols = (uint8) board.length [1];
         /* base case of recursive function, returns if we have reached the lowest depth of DecisionTree or 
the board if full */
         if (height == 0 || board_full (ref board))
         {
@@ -149,7 +153,7 @@ namespace AI
            Initialized with uint8.MAX because we do not know the column number yet. */
         uint8 next = uint8.MAX;
 
-        for (uint8 column = 0; column < BOARD_COLUMNS; column++)
+        for (uint8 column = 0; column < n_cols; column++)
         {
             if (!move (player, column, ref board))
                 continue;
@@ -189,9 +193,10 @@ namespace AI
     /* all these functions return true if the given player wins, or false */
     private static bool victory (Player player, uint8 column, ref Player [,] board)
     {
+        uint8 n_rows = (uint8) board.length [0];
         /* find the cell on which the last move was made */
         uint8 row;
-        for (row = 0; row < BOARD_ROWS && board [row, column] == Player.NOBODY; row++);
+        for (row = 0; row < n_rows && board [row, column] == Player.NOBODY; row++);
 
         return vertical_win             (player, row, column, ref board)
             || horizontal_win           (player, row, column, ref board)
@@ -201,48 +206,54 @@ namespace AI
 
     private static inline bool forward_diagonal_win (Player player, uint8 _i, uint8 _j, ref Player [,] board)
     {
+        uint8 n_rows = (uint8) board.length [0];
+        uint8 n_cols = (uint8) board.length [1];
         int8 i = (int8) _i;
         int8 j = (int8) _j;
 
         uint8 count = 0;
 
-        for (int8 k = i, l = j; k >= 0 && l < BOARD_COLUMNS && board [k, l] == player; k--, l++, count++);
-        for (int8 k = i + 1, l = j - 1; k < BOARD_ROWS && l >= 0 && board [k, l] == player; k++, l--, 
count++);
+        for (int8 k = i, l = j; k >= 0 && l < n_cols && board [k, l] == player; k--, l++, count++);
+        for (int8 k = i + 1, l = j - 1; k < n_rows && l >= 0 && board [k, l] == player; k++, l--, count++);
 
         return count >= 4;
     }
 
     private static inline bool backward_diagonal_win (Player player, uint8 _i, uint8 _j, ref Player [,] 
board)
     {
+        uint8 n_rows = (uint8) board.length [0];
+        uint8 n_cols = (uint8) board.length [1];
         int8 i = (int8) _i;
         int8 j = (int8) _j;
 
         uint8 count = 0;
 
         for (int8 k = i, l = j; k >= 0 && l >= 0 && board [k, l] == player; k--, l--, count++);
-        for (int8 k = i + 1, l = j + 1; k < BOARD_ROWS && l < BOARD_COLUMNS && board [k, l] == player; k++, 
l++, count++);
+        for (int8 k = i + 1, l = j + 1; k < n_rows && l < n_cols && board [k, l] == player; k++, l++, 
count++);
 
         return count >= 4;
     }
 
     private static inline bool horizontal_win (Player player, uint8 _i, uint8 _j, ref Player [,] board)
     {
+        uint8 n_cols = (uint8) board.length [1];
         int8 i = (int8) _i;
         int8 j = (int8) _j;
 
         uint8 count = 0;
 
         for (int8 k = j; k >= 0 && board [i, k] == player; k--, count++);
-        for (int8 k = j + 1; k < BOARD_COLUMNS && board [i, k] == player; k++, count++);
+        for (int8 k = j + 1; k < n_cols && board [i, k] == player; k++, count++);
 
         return count >= 4;
     }
 
     private static inline bool vertical_win (Player player, uint8 i, uint8 j, ref Player [,] board)
     {
+        uint8 n_rows = (uint8) board.length [0];
         uint8 count = 0;
 
-        for (uint8 k = i; k < BOARD_ROWS && board [k, j] == player; k++, count++);
+        for (uint8 k = i; k < n_rows && board [k, j] == player; k++, count++);
 
         return count >= 4;
     }
@@ -254,7 +265,8 @@ namespace AI
     /* returns true if the board is full, false if not */
     private static bool board_full (ref Player [,] board)
     {
-        for (uint8 i = 0 ; i < BOARD_COLUMNS ; i++)
+        uint8 n_cols = (uint8) board.length [1];
+        for (uint8 i = 0 ; i < n_cols; i++)
             if (board [0, i] == Player.NOBODY)
                 return false;
         return true;
@@ -263,9 +275,10 @@ namespace AI
     /* makes a move into the column'th column. Returns true if the move was succesful, false if it wasn't */
     private static bool move (Player player, uint8 column, ref Player [,] board)
     {
+        uint8 n_rows = (uint8) board.length [0];
         /* find the cell on which to move */
         int8 row;
-        for (row = BOARD_ROWS - 1; row >= 0 && board [row, column] != Player.NOBODY; row--);
+        for (row = n_rows - 1; row >= 0 && board [row, column] != Player.NOBODY; row--);
 
         if (row < 0)
             return false;
@@ -277,9 +290,10 @@ namespace AI
     /* unmove the last move made in the column'th column */
     private static void unmove (uint8 column, ref Player [,] board)
     {
+        uint8 n_rows = (uint8) board.length [0];
         /* find the cell on which the last move was made */
         uint8 row;
-        for (row = 0; row < BOARD_ROWS && board [row, column] == Player.NOBODY; row++);
+        for (row = 0; row < n_rows && board [row, column] == Player.NOBODY; row++);
 
         board [row, column] = Player.NOBODY;
     }
@@ -288,7 +302,8 @@ namespace AI
        Otherwise returns the column number in which Player P should move to win. */
     private static uint8 immediate_win (Player player, ref Player [,] board)
     {
-        for (uint8 i = 0; i < BOARD_COLUMNS; i++)
+        uint8 n_cols = (uint8) board.length [1];
+        for (uint8 i = 0; i < n_cols; i++)
         {
             if (!move (player, i, ref board))
                 continue;
@@ -307,9 +322,11 @@ namespace AI
     /* utility function for debugging purposes, prints a snapshot of current status of the board */
 //    private static void print_board (ref Player [,] board)
 //    {
-//        for (uint8 i = 0; i < BOARD_ROWS; i++)
+//        uint8 n_rows = (uint8) board.length [0];
+//        uint8 n_cols = (uint8) board.length [1];
+//        for (uint8 i = 0; i < n_rows; i++)
 //        {
-//            for (uint8 j = 0; j < BOARD_COLUMNS; j++)
+//            for (uint8 j = 0; j < n_cols; j++)
 //                stdout.printf ("%d\t", board [i, j]);
 //            stdout.printf ("\n");
 //        }
@@ -352,11 +369,13 @@ namespace AI
        which have an empty cell in the vicinity to make it four in a row. */
     private static int8 count_3_in_a_row (Player player, ref Player [,] board)
     {
+        uint8 n_rows = (uint8) board.length [0];
+        uint8 n_cols = (uint8) board.length [1];
         int8 count = 0;
 
-        for (uint8 j = 0; j < BOARD_COLUMNS; j++)
+        for (uint8 j = 0; j < n_cols; j++)
         {
-            for (uint8 i = 0; i < BOARD_ROWS; i++)
+            for (uint8 i = 0; i < n_rows; i++)
             {
                 if (board [i, j] != Player.NOBODY)
                     break;
@@ -383,6 +402,8 @@ namespace AI
     /* checks if all adjacent cells to board [i, j] are empty */
     private static inline bool all_adjacent_empty (uint8 _i, uint8 _j, ref Player [,] board)
     {
+        uint8 n_rows = (uint8) board.length [0];
+        uint8 n_cols = (uint8) board.length [1];
         int8 i = (int8) _i;
         int8 j = (int8) _j;
 
@@ -392,7 +413,7 @@ namespace AI
             {
                 if (k == 0 && l == 0)
                     continue;
-                if (i + k >= 0 && i + k < BOARD_ROWS && j + l >= 0 && j + l < BOARD_COLUMNS && board [i + k, 
j + l] != Player.NOBODY)
+                if (i + k >= 0 && i + k < n_rows && j + l >= 0 && j + l < n_cols && board [i + k, j + l] != 
Player.NOBODY)
                     return false;
             }
         }
diff --git a/src/four-in-a-row.vala b/src/four-in-a-row.vala
index 5db1c40..cdac0e9 100644
--- a/src/four-in-a-row.vala
+++ b/src/four-in-a-row.vala
@@ -46,7 +46,7 @@ private class FourInARow : Gtk.Application
     private Player player = Player.NOBODY;
     private Player winner = Player.NOBODY;
     private Player last_first_player = Player.NOBODY;
-    private Board game_board = new Board ();
+    private Board game_board;
     private bool one_player_game;
     private Difficulty ai_level;
     /**
@@ -90,6 +90,7 @@ private class FourInARow : Gtk.Application
     private uint8 theme_id;
 
     private static string? level = null;
+    private static int size = 7;
     private static bool? sound = null;
 
     private const OptionEntry [] option_entries =
@@ -103,6 +104,12 @@ private class FourInARow : Gtk.Application
         /* Translators: command-line option description, see 'four-in-a-row --help' */
         { "mute", 0, OptionFlags.NONE, OptionArg.NONE, null,                    N_("Turn off the sound"), 
null },
 
+        /* Translators: command-line option description, see 'four-in-a-row --help' */
+        { "size", 's', OptionFlags.NONE, OptionArg.INT, ref size,               N_("Size of the board"),
+
+        /* Translators: in the command-line options description, text to indicate the user should specify a 
size, see 'four-in-a-row --help' */
+                                                                                N_("SIZE") },
+
         /* Translators: command-line option description, see 'four-in-a-row --help' */
         { "unmute", 0, OptionFlags.NONE, OptionArg.NONE, null,                  N_("Turn on the sound"), 
null },
 
@@ -135,11 +142,6 @@ private class FourInARow : Gtk.Application
         return new FourInARow ().run (args);
     }
 
-    construct
-    {
-        clear_board ();
-    }
-
     private FourInARow ()
     {
         Object (application_id: "org.gnome.Four-in-a-row", flags: ApplicationFlags.FLAGS_NONE);
@@ -156,6 +158,19 @@ private class FourInARow : Gtk.Application
             return Posix.EXIT_SUCCESS;
         }
 
+        if (size < 4)
+        {
+            /* Translators: command-line error message, displayed for an incorrect game size request; try 
'four-in-a-row -s 2' */
+            stderr.printf ("%s\n", _("Size must be at least 4."));
+            return Posix.EXIT_FAILURE;
+        }
+        if (size > 16)
+        {
+            /* Translators: command-line error message, displayed for an incorrect game size request; try 
'four-in-a-row -s 17' */
+            stderr.printf ("%s\n", _("Size must not be more than 16."));
+            return Posix.EXIT_FAILURE;
+        }
+
         if (options.contains ("mute"))
             sound = false;
         else if (options.contains ("unmute"))
@@ -202,6 +217,9 @@ private class FourInARow : Gtk.Application
             settings.apply ();
         }
 
+        game_board = new Board ((uint8) size);
+        clear_board ();
+
         if (settings.get_boolean ("sound"))
             init_sound ();
 
@@ -425,7 +443,8 @@ private class FourInARow : Gtk.Application
             switch_players ();
 
         winner = NOBODY;
-        column = (BOARD_COLUMNS % 2 == 0 && get_locale_direction () == TextDirection.RTL) ? BOARD_COLUMNS / 
2 - 1 : BOARD_COLUMNS / 2;
+        column = (/* BOARD_COLUMNS */ size % 2 == 0 && get_locale_direction () == TextDirection.RTL) ? /* 
BOARD_COLUMNS */ (uint8) size / 2 - 1
+                                                                                                     : /* 
BOARD_COLUMNS */ (uint8) size / 2;
         column_moveto = column;
         row = 0;
         row_dropto = 0;
@@ -439,8 +458,8 @@ private class FourInARow : Gtk.Application
         if (!is_player_human ())
         {
             playgame_timeout = Timeout.add (COMPUTER_INITIAL_DELAY, () => {
-                    uint8 c = AI.playgame (ai_level, vstr);
-                    if (c >= BOARD_COLUMNS) // c could be uint8.MAX if board is full
+                    uint8 c = AI.playgame ((uint8) size, ai_level, vstr);
+                    if (c >= /* BOARD_COLUMNS */ size) // c could be uint8.MAX if board is full
                         return Source.REMOVE;
                     process_move (c);
                     playgame_timeout = 0;
@@ -601,8 +620,8 @@ private class FourInARow : Gtk.Application
             if (!is_player_human ())
             {
                 playgame_timeout = Timeout.add (COMPUTER_MOVE_DELAY, () => {
-                        uint8 col = AI.playgame (ai_level, vstr);
-                        if (col >= BOARD_COLUMNS)   // c could be uint8.MAX if the board is full
+                        uint8 col = AI.playgame ((uint8) size, ai_level, vstr);
+                        if (col >= /* BOARD_COLUMNS */ size)   // c could be uint8.MAX if the board is full
                             set_gameover (true);
                         var nm = new NextMove (col, this);
                         Timeout.add (SPEED_DROP, nm.exec);
@@ -624,7 +643,7 @@ private class FourInARow : Gtk.Application
                 play_sound (SoundID.PLAYER_WIN);
             window.allow_hint (false);
         }
-        else if (moves == BOARD_ROWS * BOARD_COLUMNS)
+        else if (moves == /* BOARD_ROWS */ (size - 1) * /* BOARD_COLUMNS */ size)
         {
             set_gameover (true);
             winner = NOBODY;
@@ -857,8 +876,8 @@ private class FourInARow : Gtk.Application
         /* Translators: text *briefly* displayed in the headerbar/actionbar, when a hint is requested */
         set_status_message (_("I’m Thinking…"));
 
-        uint8 c = AI.playgame (Difficulty.HARD, vstr);
-        if (c >= BOARD_COLUMNS)
+        uint8 c = AI.playgame ((uint8) size, Difficulty.HARD, vstr);
+        if (c >= /* BOARD_COLUMNS */ size)
             assert_not_reached ();  // c could be uint8.MAX if the board if full
 
         column_moveto = c;
@@ -1010,7 +1029,7 @@ private class FourInARow : Gtk.Application
         }
         else if (key == "Right" || event.keyval == keypress_right)
         {
-            if (column >= BOARD_COLUMNS_MINUS_ONE)
+            if (column >= /* BOARD_COLUMNS_MINUS_ONE */ size - 1)
                 return false;
             column_moveto++;
             move_cursor (column_moveto);
diff --git a/src/game-board-view.vala b/src/game-board-view.vala
index 5aae168..d234a52 100644
--- a/src/game-board-view.vala
+++ b/src/game-board-view.vala
@@ -78,8 +78,8 @@ private class GameBoardView : Gtk.DrawingArea
         int allocated_width  = get_allocated_width ();
         int allocated_height = get_allocated_height ();
         int size = int.min (allocated_width, allocated_height);
-        tile_size = size / BOARD_SIZE;
-        board_size = tile_size * BOARD_SIZE;
+        tile_size = size / game_board.size;
+        board_size = tile_size * game_board.size;
         board_x = (allocated_width  - board_size) / 2;
         board_y = (allocated_height - board_size) / 2;
 
@@ -109,8 +109,8 @@ private class GameBoardView : Gtk.DrawingArea
         cr.restore ();
 
         /* tiles */
-        for (uint8 row = 0; row < BOARD_ROWS_PLUS_ONE; row++)
-            for (uint8 col = 0; col < BOARD_COLUMNS; col++)
+        for (uint8 row = 0; row < /* BOARD_ROWS_PLUS_ONE */ game_board.size; row++)
+            for (uint8 col = 0; col < /* BOARD_COLUMNS */ game_board.size; col++)
                 paint_tile (cr, row, col);
 
         /* grid */
@@ -169,7 +169,7 @@ private class GameBoardView : Gtk.DrawingArea
         cr.set_dash (dashes, /* offset */ 0.0);
 
         /* draw the grid on the background pixmap */
-        for (uint8 i = 1; i < BOARD_SIZE; i++)
+        for (uint8 i = 1; i < /* BOARD_SIZE */ game_board.size; i++)
         {
             double line_offset = i * tile_size + 0.5;
             // vertical lines
@@ -253,15 +253,15 @@ private class GameBoardView : Gtk.DrawingArea
     {
         int raw_tile_size = pb_tileset_raw.get_height ();
 
-        pb_bground_raw = new Gdk.Pixbuf (Gdk.Colorspace.RGB, /* alpha */ true, /* bits per sample */ 8, 
raw_tile_size * BOARD_COLUMNS, raw_tile_size * BOARD_ROWS_PLUS_ONE);
-        for (int i = 0; i < BOARD_COLUMNS; i++)
+        pb_bground_raw = new Gdk.Pixbuf (Gdk.Colorspace.RGB, /* alpha */ true, /* bits per sample */ 8, 
raw_tile_size * /* BOARD_COLUMNS */ game_board.size, raw_tile_size * /* BOARD_ROWS_PLUS_ONE */ 
game_board.size);
+        for (int i = 0; i < /* BOARD_COLUMNS */ game_board.size; i++)
         {
             pb_tileset_raw.copy_area (raw_tile_size * 3, 0,
                                       raw_tile_size, raw_tile_size,
                                       pb_bground_raw,
                                       i * raw_tile_size, 0);
 
-            for (int j = 1; j < BOARD_ROWS_PLUS_ONE; j++)
+            for (int j = 1; j < /* BOARD_ROWS_PLUS_ONE */ game_board.size; j++)
                 pb_tileset_raw.copy_area (raw_tile_size * 2, 0,
                                           raw_tile_size, raw_tile_size,
                                           pb_bground_raw,
@@ -303,7 +303,7 @@ private class GameBoardView : Gtk.DrawingArea
     private inline bool get_column (int x, int y, out uint8 col)
     {
         int _col = (x - board_x) / tile_size;
-        if (x < board_x || y < board_y || _col < 0 || _col > BOARD_COLUMNS_MINUS_ONE)
+        if (x < board_x || y < board_y || _col < 0 || _col > /* BOARD_COLUMNS_MINUS_ONE */ game_board.size - 
1)
         {
             col = 0;
             return false;
@@ -311,7 +311,7 @@ private class GameBoardView : Gtk.DrawingArea
         col = (uint8) _col;
 
         int row = (y - board_y) / tile_size;
-        if (row < 0 || row > BOARD_ROWS)
+        if (row < 0 || row > /* BOARD_ROWS */ game_board.size - 1)
             return false;
 
         return true;
diff --git a/src/game-board.vala b/src/game-board.vala
index 362578b..2212296 100644
--- a/src/game-board.vala
+++ b/src/game-board.vala
@@ -20,11 +20,18 @@
 
 private class Board : Object
 {
+    [CCode (notify = false)] public uint8 size { internal get; protected construct; default = 7; }
+
     private static Player [,] gboard;
 
-    internal Board ()
+    construct
+    {
+        gboard = new Player [/* BOARD_COLUMNS */ size, /* BOARD_ROWS_PLUS_ONE */ size];
+    }
+
+    internal Board (uint8 size)
     {
-        gboard = new Player [BOARD_COLUMNS, BOARD_ROWS_PLUS_ONE];
+        Object (size: size);
     }
 
     internal new void @set (uint8 x, uint8 y, Player tile)
@@ -39,8 +46,8 @@ private class Board : Object
 
     internal void clear ()
     {
-        for (uint8 row = 0; row < BOARD_ROWS_PLUS_ONE; row++)
-            for (uint8 col = 0; col < BOARD_COLUMNS; col++)
+        for (uint8 row = 0; row < /* BOARD_ROWS_PLUS_ONE */ size; row++)
+            for (uint8 col = 0; col < /* BOARD_COLUMNS */ size; col++)
                 gboard [row, col] = Player.NOBODY;
     }
 
@@ -48,7 +55,7 @@ private class Board : Object
     {
         uint8 row = 1;
 
-        while (row < BOARD_ROWS_PLUS_ONE && gboard [row, col] == Player.NOBODY)
+        while (row < /* BOARD_ROWS_PLUS_ONE */ size && gboard [row, col] == Player.NOBODY)
             row++;
         return row - 1;
     }
@@ -100,7 +107,7 @@ private class Board : Object
         col_2 = col;
         while (col_1 > 0 && gboard [row, col_1 - 1] == tile)
             col_1 = col_1 - 1;
-        while (col_2 < BOARD_ROWS && gboard [row, col_2 + 1] == tile)
+        while (col_2 < /* BOARD_ROWS */ size - 1 && gboard [row, col_2 + 1] == tile)
             col_2 = col_2 + 1;
         return col_2 - col_1 >= 3;
     }
@@ -115,7 +122,7 @@ private class Board : Object
         col_2 = col;
         while (row_1 > 1 && gboard [row_1 - 1, col] == tile)
             row_1 = row_1 - 1;
-        while (row_2 < BOARD_ROWS && gboard [row_2 + 1, col] == tile)
+        while (row_2 < /* BOARD_ROWS */ size - 1 && gboard [row_2 + 1, col] == tile)
             row_2 = row_2 + 1;
         return row_2 - row_1 >= 3;
     }
@@ -134,7 +141,7 @@ private class Board : Object
             row_1 = row_1 - 1;
             col_1 = col_1 - 1;
         }
-        while (col_2 < BOARD_COLUMNS_MINUS_ONE && row_2 < BOARD_ROWS && gboard [row_2 + 1, col_2 + 1] == 
tile)
+        while (col_2 < /* BOARD_COLUMNS_MINUS_ONE */ size - 1 && row_2 < /* BOARD_ROWS */ size - 1 && gboard 
[row_2 + 1, col_2 + 1] == tile)
         {
             row_2 = row_2 + 1;
             col_2 = col_2 + 1;
@@ -151,12 +158,12 @@ private class Board : Object
         row_2 = row;
         col_1 = col;
         col_2 = col;
-        while (col_1 < BOARD_COLUMNS_MINUS_ONE && row_1 > 1 && gboard [row_1 - 1, col_1 + 1] == tile)
+        while (col_1 < /* BOARD_COLUMNS_MINUS_ONE */ size - 1 && row_1 > 1 && gboard [row_1 - 1, col_1 + 1] 
== tile)
         {
             row_1 = row_1 - 1;
             col_1 = col_1 + 1;
         }
-        while (col_2 > 0 && row_2 < BOARD_ROWS && gboard [row_2 + 1, col_2 - 1] == tile)
+        while (col_2 > 0 && row_2 < /* BOARD_ROWS */ size - 1 && gboard [row_2 + 1, col_2 - 1] == tile)
         {
             row_2 = row_2 + 1;
             col_2 = col_2 - 1;
diff --git a/src/player.vala b/src/player.vala
index 82e41cd..1799b72 100644
--- a/src/player.vala
+++ b/src/player.vala
@@ -18,11 +18,11 @@
    with GNOME Four-in-a-row.  If not, see <https://www.gnu.org/licenses/>.
 */
 
-private const uint8 BOARD_COLUMNS = 7;
-private const uint8 BOARD_COLUMNS_MINUS_ONE = 6;
-private const uint8 BOARD_ROWS = 6;
-private const uint8 BOARD_ROWS_PLUS_ONE = 7;
-private const uint8 BOARD_SIZE = 7; // as long as that is needed, impossible to have n_rows != n_cols - 1
+// private const uint8 BOARD_COLUMNS = 7;
+// private const uint8 BOARD_COLUMNS_MINUS_ONE = 6;
+// private const uint8 BOARD_ROWS = 6;
+// private const uint8 BOARD_ROWS_PLUS_ONE = 7;
+// private const uint8 BOARD_SIZE = 7; // as long as that is needed, impossible to have n_rows != n_cols - 1
 
 private enum Player
 {
diff --git a/src/test-ai.vala b/src/test-ai.vala
index 54524cd..1686471 100644
--- a/src/test-ai.vala
+++ b/src/test-ai.vala
@@ -52,99 +52,99 @@ private int main (string [] args)
 private static inline void test_horizontal_win ()
 {
     /*In the first statement below, the AI has made moves into the 1st, 2nd and 3rd columns. To win, AI must 
move in the 4th column.*/
-    assert_true (AI.playgame (Difficulty.EASY, "172737") == 3);
-    assert_true (AI.playgame (Difficulty.EASY, "731565131132442") == 5);
-    assert_true (AI.playgame (Difficulty.EASY, "23222565722356161113344") == 3);
-    assert_true (AI.playgame (Difficulty.EASY, "24221532257425554334174667745333771") == 0);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "172737") == 3);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "731565131132442") == 5);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "23222565722356161113344") == 3);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "24221532257425554334174667745333771") == 0);
 }
 
 /* Tests if the AI makes moves so as to take up immediate vertical wins.*/
 private static inline void test_vertical_win ()
 {
-    assert_true (AI.playgame (Difficulty.EASY, "121314") == 0);
-    assert_true (AI.playgame (Difficulty.EASY, "1445653552661313") == 0);
-    assert_true (AI.playgame (Difficulty.EASY, "43233427775257671") == 6);
-    assert_true (AI.playgame (Difficulty.EASY, "54747745454432332171211626") == 1);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "121314") == 0);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "1445653552661313") == 0);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "43233427775257671") == 6);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "54747745454432332171211626") == 1);
 }
 
 /* Tests if the AI makes moves so as to take up immediate forward diagonal wins.*/
 private static inline void test_forward_diagonal_win ()
 {
-    assert_true (AI.playgame (Difficulty.EASY, "5422116471244621162215757") == 6);
-    assert_true (AI.playgame (Difficulty.EASY, "425642442662127141211717577634333") == 2);
-    assert_true (AI.playgame (Difficulty.EASY, "13256552232266266677544335113111354") == 3);
-    assert_true (AI.playgame (Difficulty.EASY, "457131133454122554411224526257776773336") == 5);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "5422116471244621162215757") == 6);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "425642442662127141211717577634333") == 2);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "13256552232266266677544335113111354") == 3);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "457131133454122554411224526257776773336") == 
5);
 }
 
 /* Tests if the AI makes moves so as to take up immediate backward diagonal wins.*/
 private static inline void test_backward_diagonal_win ()
 {
-    assert_true (AI.playgame (Difficulty.EASY, "542232734314211") == 0);
-    assert_true (AI.playgame (Difficulty.EASY, "141511331514322") == 1);
-    assert_true (AI.playgame (Difficulty.EASY, "54732345221334511") == 0);
-    assert_true (AI.playgame (Difficulty.EASY, "425642442662127141211717577634333") == 2);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "542232734314211") == 0);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "141511331514322") == 1);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "54732345221334511") == 0);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "425642442662127141211717577634333") == 2);
 }
 
 /* Tests if the AI makes moves which prevents HUMAN from taking immediate vertical victories. Consider that 
a HUMAN has 3 balls in the
    first column. The AI's next move should be in the 1st column or else, HUMAN will claim victory on his 
next turn.*/
 private static inline void test_avoid_vertical_loss ()
 {
-    assert_true (AI.playgame (Difficulty.EASY, "4256311727343") == 2);
-    assert_true (AI.playgame (Difficulty.EASY, "364257154132234") == 3);
-    assert_true (AI.playgame (Difficulty.EASY, "14456626447517113775") == 4);
-    assert_true (AI.playgame (Difficulty.EASY, "5474774545443233217121") == 0);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "4256311727343") == 2);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "364257154132234") == 3);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "14456626447517113775") == 4);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "5474774545443233217121") == 0);
 }
 
 /* Tests if the AI makes moves which prevents HUMAN from taking immediate forward diagonal victories*/
 private static inline void test_avoid_forward_diagonal_loss ()
 {
-    assert_true (AI.playgame (Difficulty.EASY, "3425647733156657") == 6);
-    assert_true (AI.playgame (Difficulty.EASY, "144566264475171137") == 6);
-    assert_true (AI.playgame (Difficulty.EASY, "4344223537211511334") == 3);
-    assert_true (AI.playgame (Difficulty.EASY, "414352556776644354312541117") == 6);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "3425647733156657") == 6);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "144566264475171137") == 6);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "4344223537211511334") == 3);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "414352556776644354312541117") == 6);
 }
 
 /* Tests if the AI makes moves which prevents HUMAN from taking immediate backward diagonal victories*/
 private static inline void test_avoid_backward_diagonal_loss ()
 {
-    assert_true (AI.playgame (Difficulty.EASY, "4746523422253") == 2);
-    assert_true (AI.playgame (Difficulty.EASY, "434422353721151") == 0);
-    assert_true (AI.playgame (Difficulty.EASY, "414131152551352") == 1);
-    assert_true (AI.playgame (Difficulty.EASY, "144566264475171137755333") == 2);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "4746523422253") == 2);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "434422353721151") == 0);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "414131152551352") == 1);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "144566264475171137755333") == 2);
 
 }
 
 /* Tests if the AI makes moves which prevents HUMAN from taking immediate horizontal victories*/
 private static inline void test_avoid_horizontal_loss ()
 {
-    assert_true (AI.playgame (Difficulty.EASY, "44536") == 6);
-    assert_true (AI.playgame (Difficulty.EASY, "74553413111711477772") == 1);
-    assert_true (AI.playgame (Difficulty.EASY, "24346643121711232335") == 4);
-    assert_true (AI.playgame (Difficulty.EASY, "2414735646535511133663161524") == 3);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "44536") == 6);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "74553413111711477772") == 1);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "24346643121711232335") == 4);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "2414735646535511133663161524") == 3);
 }
 
 /* Tests if AI can detect full boards, and thus draw games. */
 private static inline void test_draw ()
 {
-    assert_true (AI.playgame (Difficulty.EASY, "131131311365222666722424776673737445544555") == uint8.MAX);
-    assert_true (AI.playgame (Difficulty.EASY, "612115113543232243342556647442561763567777") == uint8.MAX);
-    assert_true (AI.playgame (Difficulty.EASY, "422611141211327525633553444326437557767667") == uint8.MAX);
-    assert_true (AI.playgame (Difficulty.EASY, "421211657571775477522113343443236665534266") == uint8.MAX);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "131131311365222666722424776673737445544555") 
== uint8.MAX);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "612115113543232243342556647442561763567777") 
== uint8.MAX);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "422611141211327525633553444326437557767667") 
== uint8.MAX);
+    assert_true (AI.playgame (/* size */ 7, Difficulty.EASY, "421211657571775477522113343443236665534266") 
== uint8.MAX);
 }
 
 /* Tests if AI makes valid moves, i.e., between column 1 and column 7. */
 private static inline void test_random ()
 {
-    uint8 x = AI.playgame (Difficulty.EASY, "44325621435");
+    uint8 x = AI.playgame (/* size */ 7, Difficulty.EASY, "44325621435");
     assert_true (x <= 6);
 
-    x = AI.playgame (Difficulty.EASY, "24147356465355111336631615");
+    x = AI.playgame (/* size */ 7, Difficulty.EASY, "24147356465355111336631615");
     assert_true (x <= 6);
 
-    x = AI.playgame (Difficulty.EASY, "2435731546171117741662262335");
+    x = AI.playgame (/* size */ 7, Difficulty.EASY, "2435731546171117741662262335");
     assert_true (x <= 6);
 
-    x = AI.playgame (Difficulty.EASY, "144566264475171137755333366577544611");
+    x = AI.playgame (/* size */ 7, Difficulty.EASY, "144566264475171137755333366577544611");
     assert_true (x <= 6);
 }
 
@@ -162,7 +162,7 @@ private static inline uint8 test_ai_vs_ai (Difficulty easier_AI, Difficulty hard
 
         while (true)
         {
-            uint8 move = AI.playandcheck (easier_AI, easier.str);
+            uint8 move = AI.playandcheck (/* size */ 7, easier_AI, easier.str);
             if (move == uint8.MAX)
             {
                 draw++;
@@ -178,7 +178,7 @@ private static inline uint8 test_ai_vs_ai (Difficulty easier_AI, Difficulty hard
             easier.insert (easier.str.length, (move + 1).to_string ());
             harder.insert (harder.str.length, (move + 1).to_string ());
 
-            move = AI.playandcheck (harder_AI, harder.str);
+            move = AI.playandcheck (/* size */ 7, harder_AI, harder.str);
 
             if (move == uint8.MAX)
             {


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