[four-in-a-row] AI: code style fixes
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [four-in-a-row] AI: code style fixes
- Date: Sun, 5 Oct 2014 00:28:11 +0000 (UTC)
commit f873f49f323a24e8f2b943c6634f32389068b856
Author: Arnaud Bonatti <arnaud bonatti gmail com>
Date: Sun Oct 5 01:37:31 2014 +0200
AI: code style fixes
https://bugzilla.gnome.org/show_bug.cgi?id=737908
src/ai.vala | 325 ++++++++++++++++++++++-------------------------------------
1 files changed, 119 insertions(+), 206 deletions(-)
---
diff --git a/src/ai.vala b/src/ai.vala
index a02337b..5c2dc5e 100644
--- a/src/ai.vala
+++ b/src/ai.vala
@@ -15,10 +15,10 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with Four-in-a-row. If not, see <http://www.gnu.org/licenses/>.*/
+ * along with Four-in-a-row. If not, see <http://www.gnu.org/licenses/>. */
-/*Here NEG_INF is supposed to be the lowest possible int value. int.MIN
+/* Here NEG_INF is supposed to be the lowest possible int value. int.MIN
MAX_HEURIST_VALUE is the maximum value that the heuristic functions can return.
It is returned when AI wins. -1*MAX_HEURIST_VALUE is returned when Human wins
MAX_HEURIST_VALUE < NEG_INF/plies */
@@ -31,93 +31,81 @@ enum Difficulty {EASY, MEDIUM, HARD;}
int playgame (string moves_until_now)
{
- var t = new DecisionTree();
+ var t = new DecisionTree ();
return t.playgame (moves_until_now);
}
public class DecisionTree
{
- /* to mantain the status of the board, to be used by the heuristic function, the top left cell is 0,0
*/
+ /* to mantain the status of the board, to be used by the heuristic function, the top left cell is [0,
0] */
private Player[,] board = new Player [BOARD_ROWS, BOARD_COLUMNS];
- /* plies - depth of the DecisionTree*/
+ /* plies - depth of the DecisionTree */
private int plies = 8;
- /* last_moving_player - The player who made the last move, set to Player.NONE if no one has made a
move yet*/
+ /* last_moving_player - The player who made the last move, set to Player.NONE if no one has made a
move yet */
private Player last_moving_player = Player.NONE;
- /* next_move_in_column - stores the column number in which next move is to be made*/
+ /* next_move_in_column - stores the column number in which next move is to be made */
private int next_move_in_column = -1;
- /* stores the difficulty level of the game*/
+ /* stores the difficulty level of the game */
private Difficulty level;
- /* Initializes an empty board*/
+ /* Initializes an empty board */
public DecisionTree ()
{
- for (int i=0; i < BOARD_ROWS; i++)
- {
- for (int j=0; j < BOARD_COLUMNS; j++)
- {
- board[i,j] = Player.NONE;
- }
- }
+ for (int i = 0; i < BOARD_ROWS; i++)
+ for (int j = 0; j < BOARD_COLUMNS; j++)
+ board [i, j] = Player.NONE;
}
- /* utility function for debugging purposes, prints a snapshot of current status of the board*/
+ /* utility function for debugging purposes, prints a snapshot of current status of the board */
public void print_board ()
{
- for (int i=0; i< BOARD_ROWS; i++)
+ for (int i = 0; i< BOARD_ROWS; i++)
{
for (int j = 0; j < BOARD_COLUMNS; j++)
- {
- stdout.printf("%d\t",board[i,j]);
- }
- stdout.printf("\n");
+ stdout.printf ("%d\t", board [i, j]);
+ stdout.printf ("\n");
}
- stdout.printf("\n");
+ stdout.printf ("\n");
}
/* Recursively implements a negamax tree in memory with alpha-beta pruning. The function is first
called for the root node.
- It returns the value of the current node. For nodes at height == 0, the value is determined by a
heuristic function.*/
+ It returns the value of the current node. For nodes at height == 0, the value is determined by a
heuristic function. */
private int negamax (int height, int alpha, int beta)
{
-
- /* 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())
+ /* 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 ())
{
if (last_moving_player == Player.HUMAN)
- return heurist();
+ return heurist ();
else if (last_moving_player == Player.AI)
- return -1 * heurist();
+ return -1 * heurist ();
else
return 0;
}
/* Local variable that stores the maximum value returned by the node's children so far.
- None of the children have returned anything so far. Hence, it is initialized with NEG_INF*/
+ None of the children have returned anything so far. Hence, it is initialized with NEG_INF.
*/
int max = NEG_INF;
/* Local variable that stores the column number in which next move is to be made.
- Initialized with -1 because we do not know the column number yet.*/
+ Initialized with -1 because we do not know the column number yet. */
int next = -1;
- for (int i=0; i < BOARD_COLUMNS; i++)
+ for (int i = 0; i < BOARD_COLUMNS; i++)
{
- /* make a move into the i'th column*/
- if (move(i))
+ /* make a move into the i'th column */
+ if (move (i))
{
- int temp;
-
- /* victory() checks if making a move in the i'th column results in a victory
for someone. */
- /* Multiply by a height factor to avoid closer threats first */
- if (last_moving_player == Player.HUMAN)
- temp = -1 * victory(i) * height;
- else
- temp = victory(i) * height;
+ /* victory() checks if making a move in the i'th column results in a victory
for someone.
+ Multiply by a height factor to avoid closer threats first. */
+ var temp = victory (i) * height * (last_moving_player == Player.HUMAN ? -1 :
1);
- /* if making a move in this column resulted in a victory for someone,
temp!=0, we do not need to go
- further down the negamax tree*/
+ /* if making a move in this column resulted in a victory for someone, temp !=
0, we do not need to go
+ further down the negamax tree */
if (temp == 0)
- temp = -1 * negamax(height - 1, -1 * beta, -1 * alpha);
+ temp = -1 * negamax (height - 1, -1 * beta, -1 * alpha);
- unmove(i);
+ unmove (i);
if (temp > max)
{
@@ -125,18 +113,11 @@ public class DecisionTree
max = temp;
}
-
if (temp > alpha)
- {
alpha = temp;
- }
-
if (alpha >= beta)
- {
break;
- }
-
}
}
@@ -144,7 +125,6 @@ public class DecisionTree
if (height == plies)
next_move_in_column = next;
-
return max;
}
@@ -154,23 +134,22 @@ public class DecisionTree
{
int cell;
- /* board[cell,i] would now be the cell on which the last move was made */
- for (cell = 0; cell < BOARD_ROWS && board[cell,i] == Player.NONE; cell++);
+ /* board [cell, i] would now be the cell on which the last move was made */
+ for (cell = 0; cell < BOARD_ROWS && board [cell, i] == Player.NONE; cell++);
int temp = 0;
- temp = vertical_win(cell,i);
+ temp = vertical_win (cell, i);
if (temp != 0) return temp;
- temp = horizontal_win(cell,i);
+ temp = horizontal_win (cell, i);
if (temp != 0) return temp;
- temp = backward_diagonal_win(cell,i);
+ temp = backward_diagonal_win (cell, i);
if (temp != 0) return temp;
- temp = forward_diagonal_win(cell,i);
+ temp = forward_diagonal_win (cell, i);
return temp;
-
}
/* all the win functions that follow return 0 is no one wins, MAX_HEURIST_VALUE if AI wins, -1 *
MAX_HEURIST_VALUE if human wins */
@@ -178,16 +157,11 @@ public class DecisionTree
{
int count = 0;
- for (int k = i, l = j; k >= 0 && l < BOARD_COLUMNS && board[k,l] == last_moving_player; k--,
l++, count++);
- for (int k = i + 1, l = j - 1; k < BOARD_ROWS && l >= 0 && board[k,l] == last_moving_player;
k++, l--, count++);
+ for (int k = i, l = j; k >= 0 && l < BOARD_COLUMNS && board [k, l] == last_moving_player;
k--, l++, count++);
+ for (int k = i + 1, l = j - 1; k < BOARD_ROWS && l >= 0 && board [k, l] ==
last_moving_player; k++, l--, count++);
if (count >= 4)
- {
- if (last_moving_player == Player.HUMAN)
- return -1 * MAX_HEURIST_VALUE;
- else
- return MAX_HEURIST_VALUE;
- }
+ return MAX_HEURIST_VALUE * (last_moving_player == Player.HUMAN ? -1 : 1);
return 0;
}
@@ -196,16 +170,11 @@ public class DecisionTree
{
int count = 0;
- for (int k = i, l = j; k >= 0 && l >= 0 && board[k,l] == last_moving_player; k--, l--,
count++);
- for (int k = i + 1, l = j + 1; k < BOARD_ROWS && l < BOARD_COLUMNS && board[k,l] ==
last_moving_player; k++, l++, count++);
+ for (int k = i, l = j; k >= 0 && l >= 0 && board [k, l] == last_moving_player; k--, l--,
count++);
+ for (int k = i + 1, l = j + 1; k < BOARD_ROWS && l < BOARD_COLUMNS && board [k, l] ==
last_moving_player; k++, l++, count++);
if (count >= 4)
- {
- if (last_moving_player == Player.HUMAN)
- return -1 * MAX_HEURIST_VALUE;
- else
- return MAX_HEURIST_VALUE;
- }
+ return MAX_HEURIST_VALUE * (last_moving_player == Player.HUMAN ? -1 : 1);
return 0;
}
@@ -214,16 +183,11 @@ public class DecisionTree
{
int count = 0;
- for (int k = j; k >= 0 && board[i,k] == last_moving_player; k--, count++);
- for (int k = j+1; k < BOARD_COLUMNS && board[i,k] == last_moving_player; k++, count++);
+ for (int k = j; k >= 0 && board [i, k] == last_moving_player; k--, count++);
+ for (int k = j + 1; k < BOARD_COLUMNS && board [i, k] == last_moving_player; k++, count++);
if (count >= 4)
- {
- if (last_moving_player == Player.HUMAN)
- return -1 * MAX_HEURIST_VALUE;
- else
- return MAX_HEURIST_VALUE;
- }
+ return MAX_HEURIST_VALUE * (last_moving_player == Player.HUMAN ? -1 : 1);
return 0;
}
@@ -232,138 +196,114 @@ public class DecisionTree
{
int count = 0;
- for (int k = i; k < BOARD_ROWS && board[k,j] == last_moving_player; k++ , count++);
+ for (int k = i; k < BOARD_ROWS && board [k, j] == last_moving_player; k++, count++);
if (count >= 4)
- {
- if (last_moving_player == Player.HUMAN)
- return -1 * MAX_HEURIST_VALUE;
- else
- return MAX_HEURIST_VALUE;
- }
+ return MAX_HEURIST_VALUE * (last_moving_player == Player.HUMAN ? -1 : 1);
return 0;
}
- /*returns true if the board is full, false if not*/
+ /* returns true if the board is full, false if not */
private bool board_full ()
{
- bool empty = false;
for (int i = 0 ; i < BOARD_COLUMNS ; i++)
- {
- if (board[0,i] == Player.NONE)
- {
- empty = true;
- break;
- }
- }
- return !empty;
+ if (board [0, i] == Player.NONE)
+ return false;
+ return true;
}
- /* makes a move into the i'th column. Returns true if the move was succesful, false if it wasn't*/
+ /* makes a move into the i'th column. Returns true if the move was succesful, false if it wasn't */
private bool move (int i)
{
int cell;
- for(cell = BOARD_ROWS - 1; cell >= 0 && board[cell,i] != Player.NONE; cell -= 1);
+ for (cell = BOARD_ROWS - 1; cell >= 0 && board [cell, i] != Player.NONE; cell--);
- if(cell < 0)
+ if (cell < 0)
return false;
- /*if it is AI's first move or the last move was made by human */
+ /* if it is AI's first move or the last move was made by human */
if (last_moving_player == Player.NONE || last_moving_player == Player.HUMAN)
{
- board[cell,i] = Player.AI;
+ board [cell, i] = Player.AI;
last_moving_player = Player.AI;
}
else
{
- board[cell,i] = Player.HUMAN;
+ board [cell, i] = Player.HUMAN;
last_moving_player = Player.HUMAN;
}
return true;
}
- /* unmove the last move made in the i'th column.*/
+ /* unmove the last move made in the i'th column */
private void unmove (int i)
{
int cell;
- for (cell = BOARD_ROWS - 1; cell >= 0 && board[cell,i] != Player.NONE; cell -= 1);
+ for (cell = BOARD_ROWS - 1; cell >= 0 && board [cell, i] != Player.NONE; cell--);
- board[cell + 1,i] = Player.NONE;
+ board [cell + 1, i] = Player.NONE;
if (last_moving_player == Player.AI)
last_moving_player = Player.HUMAN;
else if (last_moving_player == Player.HUMAN)
last_moving_player = Player.AI;
-
}
- /* vstr is the sequence of moves made until now. We update DecisionTree::board to reflect these
sequence of moves.*/
+ /* vstr is the sequence of moves made until now. We update DecisionTree::board to reflect these
sequence of moves. */
public void update_board (string vstr)
{
next_move_in_column = -1;
- /* AI will make the first move, nothing to add to the board*/
+ /* AI will make the first move, nothing to add to the board */
if (vstr.length == 2) return;
- Player move;
-
- if (vstr.length % 2 == 0)
- move = Player.AI;
- else
- move = Player.HUMAN;
+ var move = vstr.length % 2 == 0 ? Player.AI : Player.HUMAN;
for (int i = 1; i < vstr.length - 1; i++)
{
- int column = int.parse(vstr[i].to_string()) -1;
-
+ int column = int.parse (vstr [i].to_string ()) - 1;
int cell;
- for (cell = BOARD_ROWS - 1; cell >= 0 && board[cell,column] != Player.NONE; cell -=
1);
+ for (cell = BOARD_ROWS - 1; cell >= 0 && board [cell, column] != Player.NONE; cell--);
- board[cell, column] = move;
+ board [cell, column] = move;
- if (move == Player.HUMAN)
- move = Player.AI;
- else
- move = Player.HUMAN;
+ move = move == Player.HUMAN ? Player.AI : Player.HUMAN;
}
last_moving_player = Player.HUMAN;
}
- /* check for immediate win of AI/HUMAN. It checks the current state of the board. Returns -1 if no
immediate win for Player P.
- Otherwise returns the column number in which Player P should move to win.*/
+ /* Check for immediate win of AI/HUMAN. It checks the current state of the board. Returns -1 if no
immediate win for Player P.
+ Otherwise returns the column number in which Player P should move to win. */
private int immediate_win (Player p)
{
Player old_last_moving_player = last_moving_player;
- if (p == Player.AI)
- last_moving_player = Player.HUMAN;
- else
- last_moving_player = Player.AI;
+ last_moving_player = p == Player.AI ? Player.HUMAN : Player.AI;
for (int i = 0; i < BOARD_COLUMNS; i++)
{
- if (move(i))
- {
- if (victory(i) != 0)
- {
- unmove(i);
- last_moving_player = old_last_moving_player;
- return i;
- }
+ if (!move (i))
+ continue;
- unmove(i);
+ if (victory (i) != 0)
+ {
+ unmove (i);
+ last_moving_player = old_last_moving_player;
+ return i;
}
+
+ unmove (i);
}
last_moving_player = old_last_moving_player;
- /* returns -1 if no immediate win for Player p*/
+ /* returns -1 if no immediate win for Player p */
return -1;
}
@@ -371,75 +311,59 @@ public class DecisionTree
public int playgame (string vstr)
{
/* set the Difficulty level */
- set_level(vstr);
+ set_level (vstr);
- /* update DecisionTree::board to reflect the moves made until now*/
- update_board(vstr);
+ /* update DecisionTree::board to reflect the moves made until now */
+ update_board (vstr);
- /* check if AI can win by making a move immediately*/
+ /* if AI can win by making a move immediately, make that move;
+ main.c has indexing beginning from 1 instead of 0, hence, we add 1 */
int temp = immediate_win (Player.AI);
-
- /* if the AI can win, then make that move. main.c has indexing beginning from 1 instead of 0,
hence, we add 1.*/
if (temp != -1)
return temp + 1;
- /*check if HUMAN can win by making a move immediately*/
+ /* 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);
-
- /* if the HUMAN can win, we make AI move in that column so as avoid loss.*/
if (temp != -1)
return temp + 1;
- /*call negamax tree on the current state of the board.*/
- negamax(plies, NEG_INF, -1 * NEG_INF);
+ /* call negamax tree on the current state of the board */
+ negamax (plies, NEG_INF, -1 * NEG_INF);
- /* return the column number in which next move should be made.*/
+ /* return the column number in which next move should be made */
return next_move_in_column + 1;
-
}
- /* The evaluation function to be called when we have reached the maximum depth in the DecisionTree*/
+ /* The evaluation function to be called when we have reached the maximum depth in the DecisionTree */
private int heurist ()
{
if (level == Difficulty.EASY)
- return heurist_easy();
-
+ return heurist_easy ();
else if (level == Difficulty.MEDIUM)
- return heurist_medium();
-
+ return heurist_medium ();
else
- return heurist_hard();
-
+ return heurist_hard ();
}
private int heurist_easy ()
{
- return -1 * heurist_hard();
+ return -1 * heurist_hard ();
}
private int heurist_medium ()
{
- return Random.int_range(1,49);
+ return Random.int_range (1, 49);
}
private int heurist_hard ()
{
- int count = 0;
-
- count = count_3_in_a_row(Player.AI);
-
- count -= count_3_in_a_row(Player.HUMAN);
-
- count = count*100;
-
- if (count == 0)
- count = Random.int_range(1,49);
-
- return count;
+ var count = count_3_in_a_row (Player.AI) - count_3_in_a_row (Player.HUMAN);
+ return count == 0 ? Random.int_range (1, 49) : count * 100;
}
/* Count the number of threes in a row for Player P. It counts all those 3 which have an empty cell
in the vicinity to make it
- four in a row*/
+ four in a row. */
private int count_3_in_a_row (Player p)
{
int count = 0;
@@ -452,55 +376,50 @@ public class DecisionTree
{
for (int i = 0; i < BOARD_ROWS; i++)
{
- if (board[i,j] != Player.NONE)
+ if (board [i, j] != Player.NONE)
break;
- if (all_adjacent_empty(i,j))
+ if (all_adjacent_empty (i, j))
continue;
- board[i,j] = p;
+ board [i, j] = p;
- if (victory(j) != 0)
+ if (victory (j) != 0)
count++;
- board[i,j] = Player.NONE;
-
+ board [i, j] = Player.NONE;
}
}
last_moving_player = old_last_moving_player;
return count;
}
- /* checks if all adjacent cells to board[i,j] are empty*/
+ /* checks if all adjacent cells to board [i, j] are empty */
private bool all_adjacent_empty (int i, int j)
{
for (int k = -1 ; k <= 1; k++)
{
- for (int l = -1; l <=1; l++)
+ for (int l = -1; l <= 1; l++)
{
if (k == 0 && l == 0)
continue;
- if ((i+k) >= 0 && (i+k) < BOARD_ROWS && (j+l) >= 0 && (j+l) < BOARD_COLUMNS)
- {
- if(board[i+k,j+l] != Player.NONE)
- return false;
- }
+ if (i + k >= 0 && i + k < BOARD_ROWS && j + l >= 0 && j + l < BOARD_COLUMNS
&& board [i + k, j + l] != Player.NONE)
+ return false;
}
}
return true;
}
- /* set the number of plies and the difficulty level*/
+ /* set the number of plies and the difficulty level */
private void set_level (string vstr)
{
-
- if (vstr[0] == 'a')
+ if (vstr [0] == 'a')
{
level = Difficulty.EASY;
plies = 4;
}
- else if (vstr[0] == 'b')
+ else if (vstr [0] == 'b')
{
level = Difficulty.MEDIUM;
plies = 7;
@@ -512,29 +431,23 @@ public class DecisionTree
}
}
- /* utility function for testing purposes*/
+ /* utility function for testing purposes */
public int playandcheck (string vstr)
{
- set_level(vstr);
-
- update_board(vstr);
+ set_level (vstr);
+ update_board (vstr);
int temp = immediate_win (Player.AI);
-
if (temp != -1)
- {
return 1000;
- }
temp = immediate_win (Player.HUMAN);
-
if (temp != -1)
return temp + 1;
- negamax(plies, NEG_INF, -1 * NEG_INF);
+ negamax (plies, NEG_INF, -1 * NEG_INF);
return next_move_in_column + 1;
-
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]