Skip to content

Commit

Permalink
Critical states are found, doesnt let opponent get to a critical state
Browse files Browse the repository at this point in the history
  • Loading branch information
vaquierm committed Apr 19, 2019
1 parent 7c6ac38 commit dd2e783
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 32 deletions.
12 changes: 6 additions & 6 deletions src/student_player/Agent.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ public class Agent {

public static PentagoMove findBestMove(PentagoBoardState pentagoBoardState) {

System.out.println("Player " + pentagoBoardState.getTurnPlayer() + " playing.");

// Convert the PentagoBoardState to a bitboard
PentagoBitBoard boardState = new PentagoBitBoard(pentagoBoardState);

long[] winMove = boardState.getWinMove(boardState.getTurnPlayer());
System.out.println("Player " + pentagoBoardState.getTurnPlayer() + " playing move " + boardState.getTurnPlayer());

long winMove = boardState.getWinMove(boardState.getTurnPlayer());

if (winMove[0] > 0) {
System.out.println("Win move found: " + PentagoBitMove.toPrettyString(winMove[0]));
return PentagoBitMove.bitMoveToPentagoMove(winMove[0]);
if (winMove > 0) {
System.out.println("Win move found: " + PentagoBitMove.toPrettyString(winMove));
return PentagoBitMove.bitMoveToPentagoMove(winMove);
}

List<Long> moves = MoveFilter.getNonDangerousMoves(boardState);
Expand Down
35 changes: 28 additions & 7 deletions src/student_player/MoveFilter.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package student_player;

import java.util.ArrayList;
import java.util.List;
import java.util.*;

public class MoveFilter {

private static List<Long> firstLayerElimination;
private static List<Long> secondLayerElimination;
private static List<Long> criticalStateMoves;
private static List<Long> potentialWinMoves;
private static List<Long> opponentCriticalStateMove;

public static List<Long> getNonDangerousMoves(PentagoBitBoard boardState) {

Expand All @@ -16,6 +17,8 @@ public static List<Long> getNonDangerousMoves(PentagoBitBoard boardState) {
firstLayerElimination = new ArrayList<>(moves.size());
secondLayerElimination = new ArrayList<>(moves.size());
criticalStateMoves = new ArrayList<>(moves.size());
potentialWinMoves = new ArrayList<>(moves.size());
opponentCriticalStateMove = new ArrayList<>(moves.size());

firstLayerFilter(moves, boardState);

Expand All @@ -38,8 +41,19 @@ public static List<Long> getNonDangerousMoves(PentagoBitBoard boardState) {
moves.add(criticalStateMoves.get(criticalStateMoves.size() - 1));
break;
}
else {
criticalStateMoves.remove(criticalStateMoves.get(criticalStateMoves.size() - 1));
}
}

moves.removeAll(opponentCriticalStateMove);
if (moves.isEmpty()) {
System.out.println("The opponent could put the agent in a critical state...");
return opponentCriticalStateMove;
}

moves.sort(Comparator.comparingInt(PentagoBitMove::getPriority));

return moves;
}

Expand All @@ -52,19 +66,23 @@ private static void firstLayerFilter(List<Long> moves, PentagoBitBoard boardStat

boardState.processMove(move);

long[] winMove = boardState.getWinMove(player);

if (winMove[1] > 1) {
if (boardState.isCriticalState()) {
criticalStateMoves.add(move);
}

long winMove = boardState.getWinMove(player);

if (winMove > 1) {
potentialWinMoves.add(PentagoBitMove.setPriority(move, PentagoBitMove.getPriority(winMove)));
}

// This move makes the opponent win. Remove it
if (boardState.getWinner() == 1 - player) {
firstLayerElimination.add(move);
firstLayerElimination.add(PentagoBitMove.setPriority(move, PentagoBitMove.getPriority(winMove)));
}
// Check further in the tree
else {
secondLayerFilter(player, move, boardState);
secondLayerFilter(player, PentagoBitMove.setPriority(move, PentagoBitMove.getPriority(winMove)), boardState);
}

boardState.undoMove(move);
Expand All @@ -86,6 +104,9 @@ private static void secondLayerFilter(int player, long rootMove, PentagoBitBoard
}
else {
// Check if the opponent is has put us in a critical state
if (boardState.isCriticalState()) {
opponentCriticalStateMove.add(rootMove);
}
}

boardState.undoMove(secondMove);
Expand Down
91 changes: 72 additions & 19 deletions src/student_player/PentagoBitBoard.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package student_player;

import boardgame.Board;
import com.sun.org.apache.bcel.internal.generic.SWAP;
import pentago_swap.PentagoBoardState;

import java.util.*;
Expand Down Expand Up @@ -73,33 +72,30 @@ public class PentagoBitBoard {
long baseRowMask = 0b111110000000000000000000000000000000L;
int i = 0;
WINNING_MASKS[i++] = baseRowMask;
for(; i < 6; i++) {
baseRowMask = baseRowMask >> 6;
WINNING_MASKS[i] = baseRowMask;
}
baseRowMask = baseRowMask >> 1;
WINNING_MASKS[i++] = baseRowMask;
for(; i < 12; i++) {
baseRowMask = baseRowMask << 6;
int shift = (i%2 == 0) ? 5 : 1;
baseRowMask = baseRowMask >> shift;
WINNING_MASKS[i] = baseRowMask;
}

// Generate the columns
long baseColumnMask = 0b100000100000100000100000100000000000L;
WINNING_MASKS[i++] = baseColumnMask;
for(; i < 24; i++) {
for(; i < 24; i+=2) {
baseColumnMask = baseColumnMask >> 1;
WINNING_MASKS[i] = baseColumnMask;
WINNING_MASKS[i+1] = (baseColumnMask >> 6);
}

// Diagonal masks (hardcoded since the logic to generate them would be too complex)
WINNING_MASKS[24] = 0b100000010000001000000100000010000000L;
WINNING_MASKS[25] = 0b010000001000000100000010000001000000L;
WINNING_MASKS[26] = 0b000000010000001000000100000010000001L;
WINNING_MASKS[27] = 0b000000100000010000001000000100000010L;
WINNING_MASKS[28] = 0b000001000010000100001000010000000000L;
WINNING_MASKS[29] = 0b000010000100001000010000100000000000L;
WINNING_MASKS[30] = 0b000000000010000100001000010000100000L;
WINNING_MASKS[25] = 0b000000010000001000000100000010000001L;
WINNING_MASKS[26] = 0b000001000010000100001000010000000000L;
WINNING_MASKS[27] = 0b000000000010000100001000010000100000L;

WINNING_MASKS[28] = 0b010000001000000100000010000001000000L;
WINNING_MASKS[29] = 0b000000100000010000001000000100000010L;
WINNING_MASKS[30] = 0b000010000100001000010000100000000000L;
WINNING_MASKS[31] = 0b000000000001000010000100001000010000L;

}
Expand Down Expand Up @@ -344,7 +340,7 @@ ArrayList<Long> getAllLegalNonSymmetricMoves() {
byte[][] swapsQ0 = new byte[4][2];
int initialCapacityQ0 = (QUAD_SIZE * QUAD_SIZE) * swaps.length;

Q0 = equalQuadrants.get(0).get(0);
Q0 = uniqueQuadrant.get(0);

// Generate first 3 swaps
for(int i = 0; i < identicalQuadrants.size(); i++) {
Expand Down Expand Up @@ -566,12 +562,67 @@ private boolean checkWin(byte turnPlayer) {
return false;
}

public boolean isCriticalState() {

int player = 1 - turnPlayer;

for (int i = 0; i < 28; i+=2) {
// If the opponent is already blocking this win continue
if ((WINNING_MASKS[i] & pieces[1 - player]) > 0)
continue;
if ((WINNING_MASKS[i+1] & pieces[1 - player]) > 0)
continue;

long masked = (~(pieces[player] & WINNING_MASKS[i])) & WINNING_MASKS[i];

if ((masked & (masked - 1)) != 0)
continue;

masked = (~(pieces[player] & WINNING_MASKS[i+1])) & WINNING_MASKS[i+1];

if ((masked & (masked - 1)) != 0)
continue;

boolean clear = true;
for (Long otherMove : getAllLegalNonSymmetricMoves()) {

processMove(otherMove);

if (winner == 1 - player) {
undoMove(otherMove);
clear = false;
break;
}

undoMove(otherMove);
}

if (clear) {
return true;
}
}

for (Long otherMove : getAllLegalNonSymmetricMoves()) {

processMove(otherMove);

if (winner == 1 - player || getWinMove(player) == 0) {
undoMove(otherMove);
return false;
}

undoMove(otherMove);
}

return true;
}

/**
* Returns a win move if it exists
* @param player player to check for
* @return return[0]: Win BitMove if it exists, 0 if none exists. return[1]: number of ways that leads to win
* @return Win BitMove if it exists, 0 if none exists.
*/
public long[] getWinMove(int player) {
public long getWinMove(int player) {

long[] winMove = new long[2];

Expand All @@ -590,7 +641,8 @@ public long[] getWinMove(int player) {
}
}

return winMove;
winMove[0] = PentagoBitMove.setPriority(winMove[0], (int) winMove[1]);
return winMove[0];
}

private static long[] getWinMoveForSwap(long[] swappedBoard, int player) {
Expand Down Expand Up @@ -628,6 +680,7 @@ else if ((masked & (masked - 1)) == 0) {
}
}

//winMove[1] = (winMove[1]) << winMove[1];
return winMove;
}

Expand Down
12 changes: 12 additions & 0 deletions src/student_player/PentagoBitMove.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,18 @@ public static long getBitCoord(long move) {
return move & 0b111111111111111111111111111111111111L;
}

public static long setPriority(long move, int priority) {
return move | (((long) (priority & 0b11111)) << 42);
}

public static int getPriority(long move) {
return (int) ((move >> 42) & 0b11111);
}

public static long getBitMoveNoPriority(long move) {
return move & 0b11111111111111111111111111111111111111111L;
}

/**
* Coverts a move long to a PentagoMove object
* @param move The move long to convert
Expand Down

0 comments on commit dd2e783

Please sign in to comment.