package players; import TicTac.*;import java.util.*; /** * Sample skeleton for a smart player that knows how to make the next move based * on the alpha-beta pruning evaluation strategy. *
In computing the min/max value of a game tree node, we can skip ("prune") the
evaluation of some of the children nodes using what is known as alpha-beta pruning.
1. Let alpha be a lower bound for the value of a max node A, and let B be a child node
of A. If the value v of a child of B is less or equal to alpha, then we can use v as
a value for B and skip the rest of the children of B. This is called "alpha pruning".
2. Let beta be an upper bound for the value of a min node B, and let C be a child node
of B. If the value v of a child of C is greater or equal to beta, then we can use v as
a value for C and skip the rest of the children of C. This is called "beta pruning".
*
@author Dung X. Nguyen
*/
public class SmartPlayer3 extends TTPlayer
{
public SmartPlayer3 (char mark)
{
_mark = mark;
}
/**
* Randomizes the moves array.
*/
private final void randomize (Vector moves)
{
int movesNum = moves.size();
for(int i = 0; i < movesNum; i++)
{
int x = (int) (movesNum * Math.random());
Object tmp = moves.elementAt(i);
moves.setElementAt(moves.elementAt(x), i);
moves.setElementAt(tmp, x);
}
}
/**
* Computes the value of a min node.
* parent node is a max node whose value >= alpha.
*/
private final int getMin (char[][] board, char playerMark, int alpha)
{
// if leaf node then return payoff value:
if (playerWins (board, _mark))
{
return 1;
}
else if (playerWins (board, TTEngine.GetOpponentMark(_mark)))
{
return -1;
}
else if (getNumEmptyCell (board) == 0)
{
return 0;
}
// else compute the minimum of the children node pruning if appropriate.
int temp = Integer.MAX_VALUE;
Vector moves = GetLegalMoves (playerMark, board);
int nMoves = moves.size();
for (int i = 0; i < nMoves; i++ )
{
TTMove move = (TTMove)moves.elementAt(i);
MakeMove (playerMark, move, board);
int childVal = getMax (board, TTEngine.GetOpponentMark(playerMark), temp);
temp = Math.min (temp, childVal);
if (childVal <= alpha)
{
undoMove (move, board);
break;
}
undoMove (move, board);
}
return temp;
}
/**
* Computes the value of max node.
* parent node is a min node whose value <= beta.
*/
private final int getMax (char[][] board, char playerMark, int beta)
{
// if leaf node then return payoff value:
if (playerWins (board, _mark))
{
return 1;
}
else if (playerWins (board, TTEngine.GetOpponentMark(_mark)))
{
return -1;
}
else if (getNumEmptyCell (board) == 0)
{
return 0;
}
// else compute the maximum of the children node pruning if appropriate.
int temp = Integer.MIN_VALUE;
Vector moves = GetLegalMoves (playerMark, board);
int nMoves = moves.size();
for (int i = 0; i < nMoves; i++ )
{
TTMove move = (TTMove)moves.elementAt(i);
MakeMove (playerMark, move, board);
int childVal = getMin (board, TTEngine.GetOpponentMark(playerMark), temp);
temp = Math.max (temp, childVal);
if (beta <= childVal)
{
undoMove (move, board);
break;
}
undoMove (move, board);
}
return temp;
}
/**
* Computes the next move based on the current board status.
* @param board
* @return the next best move.
*/
public TTMove NextMove (char[][] board)
{
System.out.println ("I'm thinking...");
int best = getMax (board, _mark, Integer.MAX_VALUE);
Vector moves = GetLegalMoves (_mark, board);
randomize (moves);
for (int i = 0; i < moves.size(); i++)
{
TTMove move = (TTMove)moves.elementAt(i);
MakeMove (_mark, move, board);
int temp = getMin (board, TTEngine.GetOpponentMark(_mark), Integer.MIN_VALUE);
if (temp == best)
{
undoMove (move, board);
System.out.println ("OK...");
return move;
}
undoMove (move, board);
}
return null; // should never get here!
}
private final boolean playerWins (char[][] board, char playerMark)
{
return someRowHasAll (board, playerMark)
|| someColHasAll (board, playerMark)
|| someDiagHasAll (board, playerMark);
}
private final boolean someRowHasAll (char[][] board, char mark)
{
return (board[0][0] == mark && board[0][1] == mark && board[0][2] == mark)
|| (board[1][0] == mark && board[1][1] == mark && board[1][2] == mark)
|| (board[2][0] == mark && board[2][1] == mark && board[2][2] == mark);
}
private final boolean someDiagHasAll (char[][] board, char mark)
{
return (board[0][0] == mark && board[1][1] == mark && board[2][2] == mark)
|| (board[2][0] == mark && board[1][1] == mark && board[0][2] == mark);
}
private final boolean someColHasAll (char[][] board, char mark)
{
return (board[0][0] == mark && board[1][0] == mark && board[2][0] == mark)
|| (board[0][1] == mark && board[1][1] == mark && board[2][1] == mark)
|| (board[0][2] == mark && board[1][2] == mark && board[2][2] == mark);
}
private final int getNumEmptyCell (char[][] board)
{ int cell_total = 0;
int i, j;
for (i=0; i