[four-in-a-row] Add --size command-line support.
- From: Arnaud B. <arnaudb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [four-in-a-row] Add --size command-line support.
- Date: Fri, 27 Dec 2019 16:10:52 +0000 (UTC)
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]