Untitled

 avatar
unknown
java
2 years ago
8.1 kB
1
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...