package jordan.game;

import java.util.List;

public class AIPlayer extends Player {
    static int playerCounter = 1;
    private final static int DEPTH = 2;
    private Player opponent;
    private final BoardStateEvaluator evaluator;

    public AIPlayer(Side side, BoardStateEvaluator boardStateEvaluator) {
        // TODO: is there a nicer way of getting int->char in Java without some annoying ascii offset addition?
        super(side, String.valueOf(playerCounter).charAt(0));
        this.evaluator = boardStateEvaluator;
        playerCounter++;
    }

    public AIPlayer(Side side, Player opponent, BoardStateEvaluator boardStateEvaluator) {
        this(side, boardStateEvaluator);
        this.opponent = opponent;
    }

    @Override
    public String toString() {
        return "AI #" + getPrintCharacter();
    }

    @Override
    public Move getMove(BoardState boardState) {
        List<Move> availableMoves = boardState.getAvailableMoves();
        Move bestMove = availableMoves.get(0);
        int bestValue = Integer.MIN_VALUE;
        for (Move move : availableMoves)
        {
            int val = minMaxTree(boardState.stateAfter(move, this, opponent.getSide()), DEPTH, true);
            if (val > bestValue)
            {
                bestMove = move;
                bestValue = val;
            }
        }
        return bestMove;
    }

    // TODO: Clean up all this horrendous duplication - it's 1:17 AM so it's not my fault
    private int minMaxTree(BoardState boardState, int depth, boolean maximising) {
        if (depth == 0) {
            return evaluateBoardState(boardState);
        }

        List<Move> availableMoves = boardState.getAvailableMoves();
        if (availableMoves.isEmpty()) {
            return evaluateBoardState(boardState);
        }

        if (maximising) {
            int bestValue = Integer.MIN_VALUE;
            for (Move move : availableMoves)
            {
                int val = minMaxTree(boardState.stateAfter(move, this, opponent.getSide()), depth - 1, false);
                bestValue = Math.max(bestValue, val);
            }
            return bestValue;
        }
        else
        {
            int bestValue = Integer.MAX_VALUE;
            for (Move move : availableMoves)
            {
                int val = minMaxTree(boardState.stateAfter(move, opponent, this.getSide()), depth - 1, true);
                bestValue = Math.min(bestValue, val);
            }
            return bestValue;
        }
    }

    private int evaluateBoardState(BoardState boardState) {
        if (boardState.getAvailableMoves().isEmpty())
        {
            if (boardState.getNextSideToPlay() == getSide()) {
                return Integer.MIN_VALUE;
            }
            return Integer.MAX_VALUE;
        }

        return evaluator.evaluate(boardState, this, opponent);
    }

    // TODO: ew
    public void setOpponent(AIPlayer opponent) {
        this.opponent = opponent;
    }
}

@@ -43,16 +43,88 @@
 ist;%0D%0A%0D%0A
+import static java.lang.Math.max;%0D%0Aimport static java.lang.Math.min;%0D%0A%0D%0A
 public c
@@ -1299,16 +1299,54 @@
 , DEPTH,
+ Integer.MIN_VALUE, Integer.MAX_VALUE,
  true);%0D
@@ -1675,16 +1675,37 @@
 t depth,
+ int alpha, int beta,
  boolean
@@ -2225,16 +2225,29 @@
 pth - 1,
+ alpha, beta,
  false);
@@ -2276,21 +2276,16 @@
 Value = 
-Math.
 max(best
@@ -2288,32 +2288,165 @@
 bestValue, val);
+%0D%0A                alpha = max(alpha, bestValue);%0D%0A                if (beta %3C= alpha) %7B%0D%0A                    break;%0D%0A                %7D
 %0D%0A            %7D%0D
@@ -2724,16 +2724,29 @@
 pth - 1,
+ alpha, beta,
  true);%0D
@@ -2774,21 +2774,16 @@
 Value = 
-Math.
 min(best
@@ -2786,32 +2786,163 @@
 bestValue, val);
+%0D%0A                beta = min(beta, bestValue);%0D%0A                if (beta %3C= alpha) %7B%0D%0A                    break;%0D%0A                %7D
 %0D%0A            %7D%0D
@@ -3412,18 +3412,16 @@
 pponent(
-AI
 Player o

Add basic and ugly ab-pruning