diff --git a/src/main/java/State/ActionGenerator.java b/src/main/java/State/ActionGenerator.java index e7020b6..d1d82d1 100644 --- a/src/main/java/State/ActionGenerator.java +++ b/src/main/java/State/ActionGenerator.java @@ -169,4 +169,145 @@ private static ArrayList getActionsFromNewQueenPos(int oldX, int oldY, i return moves; } + + public static int generateNumberOfActions(State state, int color, int depth) { + int count = 0; + int[][] queenPos = state.getQueens(color); + for (int[] oldPos : queenPos) { + // Up + for (int y = oldPos[1] + 1; y < State.BOARD_SIZE; y++) { + if (state.getPos(oldPos[0], y) == 0) + count += getNumActionsFromNewQueenPos(oldPos[0], oldPos[1], oldPos[0], y, state); + else + break; + } + + // Down + for (int y = oldPos[1] - 1; y >= 0; y--) { + if (state.getPos(oldPos[0], y) == 0) + count += getNumActionsFromNewQueenPos(oldPos[0], oldPos[1], oldPos[0], y, state); + else + break; + } + + // Left + for (int x = oldPos[0] - 1; x >= 0; x--) { + if (state.getPos(x, oldPos[1]) == 0) + count += getNumActionsFromNewQueenPos(oldPos[0], oldPos[1], x, oldPos[1], state); + else + break; + } + + // Right + for (int x = oldPos[0] + 1; x < State.BOARD_SIZE; x++) { + if (state.getPos(x, oldPos[1]) == 0) + count += getNumActionsFromNewQueenPos(oldPos[0], oldPos[1], x, oldPos[1], state); + else + break; + } + + // Up right + for (int offset = 1; offset <= Math.min(State.BOARD_SIZE - 1 - oldPos[0], State.BOARD_SIZE - 1 - oldPos[1]); offset++) { + if (state.getPos(oldPos[0] + offset, oldPos[1] + offset) == 0) + count += getNumActionsFromNewQueenPos(oldPos[0], oldPos[1], oldPos[0] + offset, oldPos[1] + offset, state); + else + break; + } + + // Up Left + for (int offset = 1; offset <= Math.min(oldPos[0], State.BOARD_SIZE - 1 - oldPos[1]); offset++) { + if (state.getPos(oldPos[0] - offset, oldPos[1] + offset) == 0) + count += getNumActionsFromNewQueenPos(oldPos[0], oldPos[1], oldPos[0] - offset, oldPos[1] + offset, state); + else + break; + } + + + // Down left + for (int offset = 1; offset <= Math.min(oldPos[0], oldPos[1]); offset++) { + if (state.getPos(oldPos[0] - offset, oldPos[1] - offset) == 0) + count += getNumActionsFromNewQueenPos(oldPos[0], oldPos[1], oldPos[0] - offset, oldPos[1] - offset, state); + else + break; + } + + // Down right + for (int offset = 1; offset <= Math.min(State.BOARD_SIZE - 1 - oldPos[0], oldPos[1]); offset++) { + if (state.getPos(oldPos[0] + offset, oldPos[1] - offset) == 0) + count += getNumActionsFromNewQueenPos(oldPos[0], oldPos[1], oldPos[0] + offset, oldPos[1] - offset, state); + else + break; + } + } + return count; + } + + private static int getNumActionsFromNewQueenPos(int oldX, int oldY, int newX, int newY, State state) { + int count = 0; + // Up + for (int y = newY + 1; y < State.BOARD_SIZE; y++) { + if ((newX == oldX && y == oldY) || state.getPos(newX, y) == 0) + count++; + else + break; + } + + // Down + for (int y = newY - 1; y >= 0; y--) { + if ((newX == oldX && y == oldY) || state.getPos(newX, y) == 0) + count++; + else + break; + } + + // Left + for (int x = newX - 1; x >= 0; x--) { + if ((x == oldX && newY == oldY) || state.getPos(x, newY) == 0) + count++; + else + break; + } + + // Right + for (int x = newX + 1; x < State.BOARD_SIZE; x++) { + if ((x == oldX && newY == oldY) || state.getPos(x, newY) == 0) + count++; + else + break; + } + + // Up right + for (int offset = 1; offset <= Math.min(State.BOARD_SIZE - 1 - newX, State.BOARD_SIZE - 1 - newY); offset++) { + if ((newX + offset == oldX && newY + offset == oldY) || state.getPos(newX + offset, newY + offset) == 0) + count++; + else + break; + } + + // Up Left + for (int offset = 1; offset <= Math.min(newX, State.BOARD_SIZE - 1 - newY); offset++) { + if ((newX - offset == oldX && newY + offset == oldY) || state.getPos(newX - offset, newY + offset) == 0) + count++; + else + break; + } + + // Down left + for (int offset = 1; offset <= Math.min(newX, newY); offset++) { + if ((newX - offset == oldX && newY - offset == oldY) || state.getPos(newX - offset, newY - offset) == 0) + count++; + else + break; + } + + // Down right + for (int offset = 1; offset <= Math.min(State.BOARD_SIZE - 1 - newX, newY); offset++) { + if ((newX + offset == oldX && newY - offset == oldY) || state.getPos(newX + offset, newY - offset) == 0) + count++; + else + break; + } + + return count; + } } diff --git a/src/main/java/Tree/Simulate.java b/src/main/java/Tree/Simulate.java index 1649980..ea96c2a 100644 --- a/src/main/java/Tree/Simulate.java +++ b/src/main/java/Tree/Simulate.java @@ -3,6 +3,8 @@ import State.*; import java.util.ArrayList; +import java.util.Random; +import java.util.Stack; public class Simulate { @@ -13,7 +15,7 @@ public class Simulate { * @return The player that won. Either State.BLACK or State.WHITE */ public static int simulate(Node node) { - return earlyTerminationPlayout(node); + return numberOfMovesSimulation(node); } /** @@ -64,6 +66,62 @@ else if (blackControl > whiteControl) } } + private static int numberOfMovesSimulation(Node node) { + int i = 0; + final int TERMINATION_DEPTH = 20; + State state = new State(node.getState(), node.getAction()); + int color = node.getColour(); + int depth = node.getDepth(); + ArrayList actions = ActionGenerator.generateActions(state, color, depth); + Action selectedAction; + while (actions.size() != 0 && i < TERMINATION_DEPTH) { + // Try this on 20 random moves + Stack indices = new Stack<>(); + int listLength = actions.size(); + if (listLength > 100) { + Random random = new Random(); + for (int k = 0; k < 20; k++) { + indices.add(random.nextInt(listLength)); + } + } else { + for (int k = 0; k < listLength; k++) + indices.add(k); + } + // Calculate the number of moves for each action + int k = 0; + int maxScoreIndex = 0; + int maxNumberMoves = 0; + depth++; + color = (color == State.BLACK_QUEEN) ? State.WHITE_QUEEN : State.BLACK_QUEEN; + while (!indices.empty()) { + Action nextAction = actions.get(indices.pop()); + State nextState = new State(state, nextAction); + int numMoves = ActionGenerator.generateNumberOfActions(nextState, color, depth); + if (numMoves > maxNumberMoves) { + maxNumberMoves = numMoves; + maxScoreIndex = k; + } + k++; + } + selectedAction = actions.get(maxScoreIndex); + state = new State(state, selectedAction); + actions = ActionGenerator.generateActions(state, color, depth); + i++; + } + if (i < TERMINATION_DEPTH) + return color == State.BLACK_QUEEN ? State.WHITE_QUEEN : State.BLACK_QUEEN; + else { + int blackControl = boardControlHeuristic(state, State.BLACK_QUEEN); + int whiteControl = boardControlHeuristic(state, State.WHITE_QUEEN); + if (blackControl == whiteControl) + return 0; + else if (blackControl > whiteControl) + return State.BLACK_QUEEN; + else + return State.WHITE_QUEEN; + } + } + private static int boardControlHeuristic(State state, int colour) { int[][] queens = state.getQueens(colour); byte[][] board = new byte[State.BOARD_SIZE][State.BOARD_SIZE];