package players; import TicTac.*; import java.util.*; /** * A smart player that knows how to make the next move based * on the min-max board evaluation strategy. * @author D. X. Nguyen */ public class SmartPlayer2 extends TTPlayer { public SmartPlayer2(char mark) { _mark = mark; } /** * Returns BOTH the min-max value and the TTMove corresponding to * this min-max value for the player whose symbol is playerMark. * Java hack: By passing val as an array of sixe 1, we cam return * the min-max value in val. * @param board the current board configuration. * @param playerMark the character used by the player to mark the board. * @param val an array of size 1, val[0] = the min-max value * to be computed and returned. * @return the best TTMove corresponding to val[0]. */ private TTMove eval(char[][] board, char playerMark, int[] val) { // First, check for the base case and return the payoff function. if (playerWins(board, _mark)) { val[0] = 1; return null; } else if (playerWins (board, TTEngine.GetOpponentMark(_mark))) { val[0] = -1; return null; } else if (getNumEmptyCell (board) == 0) { val[0] = 0; return null; } // recur to compute min-max: val[0] = (_mark == playerMark ? Integer.MIN_VALUE: Integer.MAX_VALUE); Vector moves = GetLegalMoves (playerMark, board); int bestMoveIx = 0; for (int i = 0; i < moves.size(); i++) { TTMove move = (TTMove)moves.elementAt(i); MakeMove (playerMark, move, board); int[] temp = {0}; // any initial value will do. eval (board, TTEngine.GetOpponentMark(playerMark), temp); if (_mark == playerMark) { // it's this SmartPlayer's turn: compute the max if (val[0] < temp[0]) { val[0] = temp[0]; bestMoveIx = i; } } else { // it's the other player's turn: compute the min if (val[0] > temp[0]) { val[0] = temp[0]; bestMoveIx = i; } } undoMove (move, board); } return (TTMove)moves.elementAt(bestMoveIx); } /** * Computes the next move based on the current board status. * @param board_status * @return the "best" TTMove */ public TTMove NextMove (char[][] board_status) { System.out.println ("I'm thinking..."); int[] val = {0}; // any initial value will do. return eval (board_status, _mark, val); } private final boolean playerWins(char[][] board_status, char playerMark) { return (someRowHasAll(board_status, playerMark) || someColHasAll(board_status, playerMark) || someDiagHasAll(board_status, playerMark)); } private final boolean someRowHasAll(char[][] board_status, char mark) { return ((board_status[0][0] == mark && board_status[0][1] == mark && board_status[0][2] == mark) || (board_status[1][0] == mark && board_status[1][1] == mark && board_status[1][2] == mark) || (board_status[2][0] == mark && board_status[2][1] == mark && board_status[2][2] == mark)); } private final boolean someDiagHasAll(char[][] board_status, char mark) { return ((board_status[0][0] == mark && board_status[1][1] == mark && board_status[2][2] == mark) || (board_status[2][0] == mark && board_status[1][1] == mark && board_status[0][2] == mark)); } private final boolean someColHasAll(char[][] board_status, char mark) { return ((board_status[0][0] == mark && board_status[1][0] == mark && board_status[2][0] == mark) || (board_status[0][1] == mark && board_status[1][1] == mark && board_status[2][1] == mark) || (board_status[0][2] == mark && board_status[1][2] == mark && board_status[2][2] == mark)); } private final int getNumEmptyCell(char[][] board_status) { int cell_total = 0; int i, j; for (i=0; i