From 51b383364541fd6bd995046c5460861efd26a40a Mon Sep 17 00:00:00 2001 From: Hedgemon4 Date: Fri, 3 Mar 2023 15:52:47 -0800 Subject: [PATCH 1/3] Started implementing changes to simulate policy --- src/main/java/State/ActionGenerator.java | 141 +++++++++++++++++++++++ src/main/java/Tree/Simulate.java | 16 ++- 2 files changed, 155 insertions(+), 2 deletions(-) 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..6b60253 100644 --- a/src/main/java/Tree/Simulate.java +++ b/src/main/java/Tree/Simulate.java @@ -42,9 +42,20 @@ private static int earlyTerminationPlayout(Node node) { int color = node.getColour(); int depth = node.getDepth(); ArrayList actions = ActionGenerator.generateActions(state, color, depth); - Action selectedAction; while (actions.size() != 0 && i < TERMINATION_DEPTH) { - selectedAction = actions.get((int) (Math.random() * actions.size())); + int k = 0; + int maxActions = 0; + int maxIndex = 0; + for (Action action : actions) { + state = new State(state, action); + color = (color == State.BLACK_QUEEN) ? State.WHITE_QUEEN : State.BLACK_QUEEN; + int numActions = ActionGenerator.generateNumberOfActions(state, color, ++depth); + if (maxActions < numActions) { + maxIndex = k; + } + k++; + } + Action selectedAction = actions.get(maxIndex); state = new State(state, selectedAction); color = (color == State.BLACK_QUEEN) ? State.WHITE_QUEEN : State.BLACK_QUEEN; actions = ActionGenerator.generateActions(state, color, ++depth); @@ -64,6 +75,7 @@ else if (blackControl > whiteControl) } } + private static int boardControlHeuristic(State state, int colour) { int[][] queens = state.getQueens(colour); byte[][] board = new byte[State.BOARD_SIZE][State.BOARD_SIZE]; From 6fcc0ca577079627f7f78f581e042617f6725757 Mon Sep 17 00:00:00 2001 From: Hedgemon4 Date: Sat, 4 Mar 2023 09:52:56 -0800 Subject: [PATCH 2/3] Added improvements to simulation --- src/main/java/Tree/Simulate.java | 40 ++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/main/java/Tree/Simulate.java b/src/main/java/Tree/Simulate.java index 6b60253..32a8a1b 100644 --- a/src/main/java/Tree/Simulate.java +++ b/src/main/java/Tree/Simulate.java @@ -36,6 +36,35 @@ private static int randomPlayout(Node node) { } private static int earlyTerminationPlayout(Node node) { + int i = 0; + final int TERMINATION_DEPTH = 30; + 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) { + selectedAction = actions.get((int) (Math.random() * actions.size())); + state = new State(state, selectedAction); + color = (color == State.BLACK_QUEEN) ? State.WHITE_QUEEN : State.BLACK_QUEEN; + 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 improvedSimulation(Node node) { int i = 0; final int TERMINATION_DEPTH = 30; State state = new State(node.getState(), node.getAction()); @@ -46,12 +75,16 @@ private static int earlyTerminationPlayout(Node node) { int k = 0; int maxActions = 0; int maxIndex = 0; + State nextState = state; + int simulationColour = color; + int simulateDepth = depth; for (Action action : actions) { - state = new State(state, action); - color = (color == State.BLACK_QUEEN) ? State.WHITE_QUEEN : State.BLACK_QUEEN; - int numActions = ActionGenerator.generateNumberOfActions(state, color, ++depth); + nextState = new State(nextState, action); + simulationColour = (simulationColour == State.BLACK_QUEEN) ? State.WHITE_QUEEN : State.BLACK_QUEEN; + int numActions = ActionGenerator.generateNumberOfActions(nextState, simulationColour, ++simulateDepth); if (maxActions < numActions) { maxIndex = k; + maxActions = numActions; } k++; } @@ -75,7 +108,6 @@ else if (blackControl > whiteControl) } } - private static int boardControlHeuristic(State state, int colour) { int[][] queens = state.getQueens(colour); byte[][] board = new byte[State.BOARD_SIZE][State.BOARD_SIZE]; From 6fb3590ffe224aa2cb2192bd6a02982e7d688311 Mon Sep 17 00:00:00 2001 From: Hedgemon4 Date: Sat, 4 Mar 2023 11:11:18 -0800 Subject: [PATCH 3/3] Implemented simulation heuristic --- src/main/java/Tree/Simulate.java | 50 ++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/main/java/Tree/Simulate.java b/src/main/java/Tree/Simulate.java index 32a8a1b..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,34 +66,46 @@ else if (blackControl > whiteControl) } } - private static int improvedSimulation(Node node) { + private static int numberOfMovesSimulation(Node node) { int i = 0; - final int TERMINATION_DEPTH = 30; + 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 maxActions = 0; - int maxIndex = 0; - State nextState = state; - int simulationColour = color; - int simulateDepth = depth; - for (Action action : actions) { - nextState = new State(nextState, action); - simulationColour = (simulationColour == State.BLACK_QUEEN) ? State.WHITE_QUEEN : State.BLACK_QUEEN; - int numActions = ActionGenerator.generateNumberOfActions(nextState, simulationColour, ++simulateDepth); - if (maxActions < numActions) { - maxIndex = k; - maxActions = numActions; + 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++; } - Action selectedAction = actions.get(maxIndex); + selectedAction = actions.get(maxScoreIndex); state = new State(state, selectedAction); - color = (color == State.BLACK_QUEEN) ? State.WHITE_QUEEN : State.BLACK_QUEEN; - actions = ActionGenerator.generateActions(state, color, ++depth); + actions = ActionGenerator.generateActions(state, color, depth); i++; } if (i < TERMINATION_DEPTH)