port to java

This commit is contained in:
nora 2023-01-15 15:36:54 +01:00
parent 50f4f7edd7
commit c235e4ec65
3 changed files with 97 additions and 6 deletions

View file

@ -17,7 +17,7 @@ public class Connect4ArenaMain {
static final int NOMOVE = -1;
public static void main(String[] args) {
new Connect4ArenaMain().play(new RustPlayer(), new GreedyPlayer());
new Connect4ArenaMain().play(new HumanPlayer(), new PerfectPlayer());
}
static String toDebugString(Stone[] board) {
@ -66,7 +66,7 @@ public class Connect4ArenaMain {
return null; // null implies a draw
}
boolean isWinning(Stone[] board, Stone forColor) {
public static boolean isWinning(Stone[] board, Stone forColor) {
return RustPlayer.isWinning(board, forColor);
}

View file

@ -0,0 +1,76 @@
package ch.bbw.m411.connect4;
import java.util.ArrayList;
import java.util.List;
public class PerfectPlayer extends Connect4ArenaMain.DefaultPlayer {
private static final int MAX_DEPTH = 8;
private static final int WON = 1000;
private static final int LOST = -1000;
private int bestMove = -1;
private List<Integer> possibleMoves() {
var moves = new ArrayList<Integer>();
// for all columns
for (int i = 0; i < 7; i++) {
// walk up
for (int j = 0; j < 4; j++) {
var position = i + (j * 7);
if (board[position] == null) {
moves.add(position);
break;
}
}
}
return moves;
}
private int minmax(Connect4ArenaMain.Stone maximizingPlayer, int alpha, int beta, int depth) {
if (depth >= MAX_DEPTH) {
// FIXME rate
return 0;
}
if (Connect4ArenaMain.isWinning(board, maximizingPlayer)) {
return WON;
}
if (Connect4ArenaMain.isWinning(board, maximizingPlayer.opponent())) {
return LOST;
}
var moves = possibleMoves();
if (moves.isEmpty()) {
return 0;
}
var maxValue = alpha;
for (var move : moves) {
board[move] = maximizingPlayer;
var value = -minmax(maximizingPlayer.opponent(), -beta, -maxValue, depth + 1);
board[move] = null;
if (value > maxValue) {
maxValue = value;
if (depth == 0) {
bestMove = move;
}
if (maxValue >= beta) {
break;
}
}
}
return maxValue;
}
@Override
protected int play() {
bestMove = -1;
minmax(myColor, LOST, WON, 0);
return this.bestMove;
}
}

View file

@ -1,14 +1,28 @@
package ch.bbw.m411.connect4;
import java.io.File;
import java.io.IOException;
public class RustPlayer extends Connect4ArenaMain.DefaultPlayer {
private static native int rustPlay(byte player, byte[] board);
private static native int rustBoardWinner(byte[] board);
static {
// This actually loads the shared object that we'll be creating.
// The actual location of the .so or .dll may differ based on your
// platform.
System.loadLibrary("minmax_wrapper");
if (System.getProperty("os.name").toLowerCase().contains("windows")) {
var path = "target/release/" + System.mapLibraryName("minmax_wrapper");
try {
System.load(new File(path).getCanonicalPath());
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
// This actually loads the shared object that we 'll be creating.
// The actual location of the .so or .dll may differ based on your
// platform.
System.loadLibrary("minmax_wrapper");
}
}
static byte[] encodeBoard(Connect4ArenaMain.Stone[] board) {
@ -29,6 +43,7 @@ public class RustPlayer extends Connect4ArenaMain.DefaultPlayer {
}
public static boolean isWinning(Connect4ArenaMain.Stone[] board, Connect4ArenaMain.Stone forColor) {
byte[] boardBuf = RustPlayer.encodeBoard(board);
byte expectedPlayer = switch (forColor) {
case BLUE -> 1;