Untitled
unknown
java
3 years ago
8.1 kB
4
Indexable
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import static java.lang.Math.max;
import static java.lang.Math.min;
/**
* This is the class that we will have to implement for the assignment
*/
public class StudentPlayer extends Player{
// Some constants for the code
private final int AI = 2;
private final int HUMAN = 1;
private final int TIE = 0;
// constructor, do not touch
public StudentPlayer(int playerIndex, int[] boardSize, int nToConnect) {
super(playerIndex, boardSize, nToConnect);
}
/**
* @param board - the board that the players are using
* @return - an int that represents how good a move is
*/
@Override
public int step(Board board) {
int best_score = Integer.MIN_VALUE;
int best_move = board.getValidSteps().get(0);
for (int move : board.getValidSteps()) {
Board new_board = new Board(board);
new_board.step(this.AI, move);
int score = this.minimax(new_board, 5, false, Integer.MIN_VALUE, Integer.MAX_VALUE);
System.out.println(score);
if (score > best_score) {
best_score = score;
best_move = move;
}
}
return best_move;
}
/**
* @param board - the board the players are using
* @param move - the move that one of the players will make
* @param player_index - the index of the player that makes the move
* @return - returns true, if the player wins the game with the move
*/
private boolean is_winner_move(Board board, int move, int player_index) {
Board new_board = new Board(board);
new_board.step(player_index, move);
return new_board.gameEnded();
}
/**
* @param board - the board the players are using
* @param max_depth - the maximum depth the algorithm will look at
* @param is_maximizing - bool flag, signals which player is currently making the move
* @param alpha - constant for alpha-beta pruning, initizalize it as -INF
* @param beta - constant for alpha-beta pruning, initialize it as +INF
* @return - the score of the the last move
*/
private int minimax(Board board, int max_depth, boolean is_maximizing, int alpha, int beta) {
if (--max_depth == 0) {
return is_maximizing ? this.getPositionValue(board) : -this.getPositionValue(board);
}
if (board.gameEnded() && board.getWinner() == 0) {
return 0;
}
if (is_maximizing) {
// If we win with one of the next moves, return +INF
for (int move : board.getValidSteps()) {
if (is_winner_move(board, move, this.AI)) {
return 20 + max_depth;
}
}
int best_score = Integer.MIN_VALUE;
for (int move : board.getValidSteps()) {
Board new_board = new Board(board);
new_board.step(this.AI, move);
int score = minimax(new_board, max_depth, false, alpha, beta);
best_score = Math.max(score, best_score);
// alpha beta pruning
alpha = Math.max(alpha, score);
if (beta <= alpha)
break;
}
return best_score;
}
// MINIMIZING PLAYER
else {
// If we win with one of the next moves, return -INF
for (int move : board.getValidSteps()) {
if (is_winner_move(board, move, this.HUMAN)) {
return -20 - max_depth;
}
}
int best_score = Integer.MAX_VALUE;
// Check what future moves will look like
for (int move : board.getValidSteps()) {
Board new_board = new Board(board);
new_board.step(this.HUMAN, move);
int score = minimax(new_board, max_depth, true, alpha, beta);
best_score = Math.min(score, best_score);
// alpha beta pruning
beta = Math.min(beta, score);
if (beta <= alpha)
break;
}
return best_score;
}
}
// -------------------------- THESE FUNCTIONS SHOULD BE IN THE BOARD CLASS ---------------------------------------
private int getPositionValue(Board board) {
int value = 0;
for (int i = 1; i <= 4; i++) {
if (this.countInARow(board, i))
value += i;
else if (this.countInACol(board, i))
value += i;
else if (this.countNDiagonally(board, i))
value += i;
else if (this.countNSkewDiagonally(board, i))
value += i;
}
return value;
}
private boolean countInARow(Board board, int n_to_connect) {
int row = board.getLastPlayerRow();
int col = board.getLastPlayerColumn();
int player_index = board.getLastPlayerIndex();
int n_in_a_row = 0;
int startCol = max(0, col - n_to_connect + 1);
int endCol = min(boardSize[1], col + n_to_connect);
for (int c = startCol; c < endCol; c++) {
if (board.getState()[row][c] == player_index) {
n_in_a_row++;
if (n_in_a_row == n_to_connect) {
return true;
}
} else
n_in_a_row = 0;
}
return false;
}
private boolean countInACol(Board board, int n_to_connect) {
int row = board.getLastPlayerRow();
int col = board.getLastPlayerColumn();
int player_index = board.getLastPlayerIndex();
int n_in_a_col = 0;
int startRow = max(0, row - n_to_connect + 1);
int endRow = min(boardSize[0], row + n_to_connect);
for (int r = startRow; r < endRow; r++) {
if (board.getState()[r][col] == player_index) {
n_in_a_col++;
if (n_in_a_col == n_to_connect) {
return true;
}
} else
n_in_a_col = 0;
}
return false;
}
private boolean countNDiagonally(Board board, int n_to_connect) {
int row = board.getLastPlayerRow();
int col = board.getLastPlayerColumn();
int player_index = board.getLastPlayerIndex();
int n_in_a_diagonal = 0;
int stepLeftUp = min(n_to_connect - 1, min(row, col));
int stepRightDown = min(n_to_connect, min(boardSize[0] - row, boardSize[1] - col));
if ((stepLeftUp + stepRightDown) < n_to_connect)
return false;
for (int diagonalStep = -stepLeftUp; diagonalStep < stepRightDown; diagonalStep++) {
if (board.getState()[row + diagonalStep][col + diagonalStep] == player_index) {
n_in_a_diagonal++;
if (n_in_a_diagonal == n_to_connect) {
return true;
}
} else {
n_in_a_diagonal = 0;
}
}
return false;
}
private boolean countNSkewDiagonally(Board board, int n_to_connect) {
int row = board.getLastPlayerRow();
int col = board.getLastPlayerColumn();
int player_index = board.getLastPlayerIndex();
int n_in_a_skew_diagonal = 0;
int stepLeftDown = min(n_to_connect - 1, min(boardSize[0] - row - 1, col));
int stepRightUp = min(n_to_connect, min(row + 1, boardSize[1] - col));
if ((stepRightUp + stepLeftDown) < n_to_connect)
return false;
for (int skewDiagonalStep = -stepLeftDown; skewDiagonalStep < stepRightUp; skewDiagonalStep++) {
if (board.getState()[row - skewDiagonalStep][col + skewDiagonalStep] == player_index) {
n_in_a_skew_diagonal++;
if (n_in_a_skew_diagonal == n_to_connect) {
return true;
}
} else
n_in_a_skew_diagonal = 0;
}
return false;
}
}
Editor is loading...