diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index d2d6aa8..8fa8e54 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,12 +5,14 @@
-
-
+
+
-
-
+
+
+
+
@@ -50,22 +52,22 @@
- {
+ "keyToString": {
+ "RunOnceActivity.OpenProjectViewOnStart": "true",
+ "RunOnceActivity.ShowReadmeOnStart": "true",
+ "SHARE_PROJECT_CONFIGURATION_FILES": "true",
+ "codeWithMe.voiceChat.enabledByDefault": "false",
+ "git-widget-placeholder": "william",
+ "last_opened_file_path": "/home/william/Dev/Projects",
+ "node.js.detected.package.eslint": "true",
+ "node.js.detected.package.tslint": "true",
+ "node.js.selected.package.eslint": "(autodetect)",
+ "node.js.selected.package.tslint": "(autodetect)",
+ "nodejs_package_manager_path": "npm",
+ "vue.rearranger.settings.migration": "true"
}
-}]]>
+}
@@ -132,6 +134,7 @@
+
1679263366439
diff --git a/src/main/java/laboratoire4/BoardEvaluator.java b/src/main/java/laboratoire4/BoardEvaluator.java
index a61fe15..b9b204b 100644
--- a/src/main/java/laboratoire4/BoardEvaluator.java
+++ b/src/main/java/laboratoire4/BoardEvaluator.java
@@ -4,23 +4,26 @@ import java.util.Collection;
public class BoardEvaluator {
public static int evaluate(MovingBoard game) {
- MovingPawn[][] board = game.getBoard();
Collection maxPawns = game.getMaxPawns();
Collection minPawns = game.getMinPawns();
- return evaluatePlayer(board, maxPawns, minPawns) - evaluatePlayer(board, minPawns, maxPawns);
+ return evaluatePlayer(game, maxPawns, minPawns, true) - evaluatePlayer(game, minPawns, maxPawns, false);
}
//region Full Board
- private static int evaluatePlayer(MovingPawn[][] board, Collection maxPawns, Collection minPawns) {
- if (minPawns.size() == 0) {
- return Integer.MAX_VALUE;
+ private static int evaluatePlayer(MovingBoard game, Collection maxPawns, Collection minPawns, boolean max) {
+ if (minPawns.stream().noneMatch(IPawn::isPusher)) {
+ return 50;
}
int score = evaluateMaxPawnCountScore(maxPawns, minPawns);
for (MovingPawn pawn : maxPawns) {
- score += evaluatePawn(board, pawn);
+ score += evaluatePawn(game, pawn);
+
+ if (max) {
+ score += strategy(game, pawn);
+ }
}
return score;
@@ -33,83 +36,195 @@ public class BoardEvaluator {
// Augmente beaucoup le score à partir de 10 pions capturés
// f(x) = 0.001x^4, f(1) = 0, f(10) = 10, f(16) = 65.54
private static int evaluatePawnCountScore(Collection pawns) {
- return (int) (0.001f * Math.pow(16 - pawns.size(), 4)) * 100;
+ int capturedPusherCount = (int) (8 - pawns.stream().filter(IPawn::isPusher).count());
+ return (int) (Math.pow(capturedPusherCount, 2));
}
//endregion
//region Board
- private static int evaluatePawn(MovingPawn[][] board, MovingPawn pawn) {
+ private static int evaluatePawn(MovingBoard game, MovingPawn pawn) {
if (pawn.getRow() == pawn.getPlayer().getGoal()) {
- return Integer.MAX_VALUE;
+ return 50;
}
// Favorise les pièces qui peuvent gagner au prochain tour
if (pawn.getRow() + pawn.getDirection() == pawn.getPlayer().getGoal()) {
- return Integer.MAX_VALUE / 2;
+ return 25;
}
int score = 0;
score += evaluateHomePawnScore(pawn);
- score += evaluatePushedScore(pawn);
- score += evaluateValidMovesScore(board, pawn);
- score += evaluateAttackScore(board, pawn);
+// score += evaluatePushedScore(pawn);
+ score += evaluatePusherScore(game, pawn);
+ score += evaluateValidMovesScore(game, pawn);
+ score += evaluateAttackScore(game, pawn);
+ score += evaluateDefenseScore(game, pawn);
+
+ if (Math.abs(pawn.getPlayer().getGoal() - pawn.getRow()) < 4) {
+ score += hasEasyWinPath(game, pawn, pawn.getRow(), pawn.getCol(), 0);
+ }
return score;
}
private static int evaluateHomePawnScore(MovingPawn pawn) {
- return pawn.getRow() == pawn.getPlayer().getHome() ? 50 : 0;
+ return pawn.getRow() == pawn.getPlayer().getHome() ? 1 : 0;
}
private static int evaluatePushedScore(MovingPawn pawn) {
- return pawn.isPusher() ? 0 : 50;
+ return pawn.isPusher() ? 0 : 1;
}
- private static int evaluateValidMovesScore(MovingPawn[][] board, MovingPawn pawn) {
+ private static int evaluatePusherScore(MovingBoard board, MovingPawn pawn) {
+ if (!pawn.isPusher()) return 0;
+
int score = 0;
-
- if (pawn.isMoveValid(board, Pawn.PawnMovement.LEFT_DIAGONAL)) {
- score += 50;
+ for (Pawn.PawnMovement movement : Pawn.PawnMovement.values()) {
+ MovingPawn nearPawn = board.getNextPawn(pawn, movement);
+ if (MovingPawn.areSamePlayers(pawn, nearPawn) && !nearPawn.isPusher()) {
+ score++;
+ }
}
- if (pawn.isMoveValid(board, Pawn.PawnMovement.STRAIGHT)) {
- score += 50;
- }
- if (pawn.isMoveValid(board, Pawn.PawnMovement.RIGHT_DIAGONAL)) {
- score += 50;
- }
-
return score;
}
- private static int evaluateAttackScore(MovingPawn[][] board, MovingPawn pawn) {
+ private static int evaluateValidMovesScore(MovingBoard game, MovingPawn pawn) {
int score = 0;
- int row = pawn.getRow();
- int col = pawn.getCol();
-
- if (pawn.isMoveValid(board, Pawn.PawnMovement.LEFT_DIAGONAL)) {
- MovingPawn destPawn = board[row + pawn.getDirection()][col - 1];
-
- if (destPawn != null && destPawn.getPlayer() != pawn.getPlayer()) {
- score += 100;
+ for (Pawn.PawnMovement movement : Pawn.PawnMovement.values()) {
+ if (pawn.isMoveValid(game.getBoard(), movement)) {
+ score++;
}
}
+ return score * pawn.getMoveCount();
+ }
- if (pawn.isMoveValid(board, Pawn.PawnMovement.RIGHT_DIAGONAL)) {
- MovingPawn destPawn = board[row + pawn.getDirection()][col + 1];
+ private static int evaluateAttackScore(MovingBoard game, MovingPawn pawn) {
+ int score = 0;
- if (destPawn != null && destPawn.getPlayer() != pawn.getPlayer()) {
- score += 100;
+ Pawn.PawnMovement[] validAttackMoves = new Pawn.PawnMovement[]{Pawn.PawnMovement.LEFT_DIAGONAL, Pawn.PawnMovement.RIGHT_DIAGONAL};
+ for (Pawn.PawnMovement movement : validAttackMoves) {
+ MovingPawn nearPawn = game.getNextPawn(pawn, movement);
+ if (nearPawn != null && pawn.isMoveValid(game.getBoard(), movement) && !MovingPawn.areSamePlayers(pawn, nearPawn)) {
+ score++;
}
}
// Favorise les attaques de notre côté
if ((pawn.getPlayer() == Player.RED && pawn.getRow() < 4) ||
(pawn.getPlayer() == Player.BLACK && pawn.getRow() >= 4)) {
- score *= 2;
+ score++;
+ }
+
+ return score;
+ }
+
+ private static int evaluateDefenseScore(MovingBoard game, MovingPawn pawn) {
+ int score = 0;
+
+ Pawn.PawnMovement[] validAttackMoves = new Pawn.PawnMovement[]{Pawn.PawnMovement.LEFT_DIAGONAL, Pawn.PawnMovement.RIGHT_DIAGONAL};
+ for (Pawn.PawnMovement movement : validAttackMoves) {
+ MovingPawn nearPawn = game.getNextPawn(pawn, movement);
+ Pawn.PawnMovement oppositeMovement = Pawn.PawnMovement.from(movement.getMove() * -1);
+
+ if (nearPawn != null && !MovingPawn.areSamePlayers(pawn, nearPawn) && nearPawn.isMoveValid(game.getBoard(), oppositeMovement)) {
+ score -= 50;
+ }
+ }
+
+ return score;
+ }
+
+ private static int hasEasyWinPath(MovingBoard game, MovingPawn pawn, int row, int col, int depth) {
+ if (row == pawn.getPlayer().getGoal()) {
+ return 10;
+ }
+
+ int score = 0;
+ int nextRow = row + pawn.getDirection();
+
+ Pawn.PawnMovement[] preferredMoves = new Pawn.PawnMovement[]{Pawn.PawnMovement.LEFT_DIAGONAL, Pawn.PawnMovement.RIGHT_DIAGONAL};
+ for (Pawn.PawnMovement movement : preferredMoves) {
+ int nextCol = col + movement.getMove();
+ if (nextCol < 0 || nextCol > 7) continue;
+
+ MovingPawn nearPawn = game.getBoard()[nextRow][nextCol];
+
+ if (nearPawn == null) {
+ score += 2;
+ } else if (nearPawn.getPlayer() != pawn.getPlayer()) {
+ score++;
+ } else {
+ continue;
+ }
+
+ if (depth < 3) {
+ score += hasEasyWinPath(game, pawn, nextRow, pawn.getCol() + movement.getMove(), depth + 1);
+ }
}
return score;
}
//endregion
+
+ //region Strategy
+ private static int strategy(MovingBoard game, MovingPawn pawn) {
+ int score = 0;
+
+ score += defensiveStrategy(game, pawn);
+ return score;
+ }
+
+ private static int defensiveStrategy(MovingBoard game, MovingPawn pawn) {
+ int col = pawn.getCol();
+ int row = pawn.getRow();
+
+ if (col < 2 || col > 5) {
+ return 0;
+ }
+
+ MovingPawn leftPawn = game.getBoard()[row][col - 2];
+ MovingPawn rightPawn = game.getBoard()[row][col - 2];
+ int score = 0;
+
+ if (MovingPawn.areSamePlayers(leftPawn, pawn)) {
+ score++;
+ }
+ if (MovingPawn.areSamePlayers(rightPawn, pawn)) {
+ score++;
+ }
+
+ if (hasEnemyNear(game, pawn)) {
+ score += 100;
+ }
+
+ return score;
+ }
+
+ private static boolean hasEnemyNear(MovingBoard game, MovingPawn pawn) {
+ int row = pawn.getRow();
+ int col = pawn.getCol();
+
+ for (int i = 1; i <= 2; i++) {
+ int nextRow = row + i * pawn.getDirection();
+ if (nextRow < 0 || nextRow > 7) {
+ break;
+ }
+
+ for (int j = -1; j <= 1; j++) {
+ int nextCol = col + j;
+ if (nextCol < 0 || nextCol > 7) {
+ continue;
+ }
+
+ MovingPawn nearPawn = game.getBoard()[nextRow][nextCol];
+ if (nearPawn != null && !MovingPawn.areSamePlayers(pawn, nearPawn)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+ //endregion
}
diff --git a/src/main/java/laboratoire4/Client.java b/src/main/java/laboratoire4/Client.java
index 623b983..b76468a 100644
--- a/src/main/java/laboratoire4/Client.java
+++ b/src/main/java/laboratoire4/Client.java
@@ -40,6 +40,7 @@ public class Client {
if (cmd == '5') {
stopGame();
+ break;
}
}
} catch (IOException e) {
diff --git a/src/main/java/laboratoire4/MiniMax.java b/src/main/java/laboratoire4/MiniMax.java
index f28a440..9c772b6 100644
--- a/src/main/java/laboratoire4/MiniMax.java
+++ b/src/main/java/laboratoire4/MiniMax.java
@@ -6,7 +6,8 @@ import java.util.Collections;
import java.util.List;
public class MiniMax {
- private static final int MAX_DEPTH = 4;
+ private static final int MAX_MAX_DEPTH = 6;
+ private static int MAX_DEPTH = 2;
public static MiniMaxResult miniMax(PusherBoard board) {
long startMillis = System.currentTimeMillis();
@@ -15,12 +16,15 @@ public class MiniMax {
MiniMaxResult maxResult = null;
- for (Action action : actions) {
- int score = min(game, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
+ for (int i = 0; i <= MAX_MAX_DEPTH; i += 2) {
+ MAX_DEPTH = i;
+ for (Action action : actions) {
+ int score = min(game, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
- if (maxResult == null || score > maxResult.getScore()) {
- MovingPawn pawn = action.getPawn();
- maxResult = new MiniMaxResult(score, pawn.getRow(), pawn.getCol(), action.getMovement());
+ if (maxResult == null || score > maxResult.getScore()) {
+ MovingPawn pawn = action.getPawn();
+ maxResult = new MiniMaxResult(score, pawn.getRow(), pawn.getCol(), action.getMovement());
+ }
}
}
@@ -89,6 +93,11 @@ public class MiniMax {
Collection pawns = max ? game.getMaxPawns() : game.getMinPawns();
Pawn.PawnMovement[] movements = Pawn.PawnMovement.values();
+// Collection winningPawns = pawns.stream().filter(p -> p.getRow() + p.getDirection() == p.getPlayer().getGoal()).collect(Collectors.toList());
+// if (winningPawns.size() > 0) {
+// pawns = winningPawns;
+// }
+
for (MovingPawn pawn : pawns) {
for (Pawn.PawnMovement movement : movements) {
if (pawn.isMoveValid(game.getBoard(), movement)) {
diff --git a/src/main/java/laboratoire4/MovingBoard.java b/src/main/java/laboratoire4/MovingBoard.java
index 739047a..6a9be74 100644
--- a/src/main/java/laboratoire4/MovingBoard.java
+++ b/src/main/java/laboratoire4/MovingBoard.java
@@ -41,6 +41,17 @@ public class MovingBoard {
board[pawn.getRow()][pawn.getCol()] = pawn;
}
+ public MovingPawn getNextPawn(IPawn pawn, Pawn.PawnMovement move) {
+ int nextRow = pawn.getRow() + pawn.getDirection();
+ int nextCol = pawn.getCol() + move.getMove();
+
+ if (nextCol < 0 || nextCol > 7) {
+ return null;
+ }
+
+ return board[nextRow][nextCol];
+ }
+
public MovingPawn[][] getBoard() {
return board;
}
diff --git a/src/main/java/laboratoire4/MovingPawn.java b/src/main/java/laboratoire4/MovingPawn.java
index 3d35162..bf6d0da 100644
--- a/src/main/java/laboratoire4/MovingPawn.java
+++ b/src/main/java/laboratoire4/MovingPawn.java
@@ -2,6 +2,7 @@ package laboratoire4;
public interface MovingPawn extends IPawn {
void revertMove();
+ int getMoveCount();
static MovingPawn from(Pawn pawn) {
if (pawn instanceof Pusher) {
@@ -10,5 +11,9 @@ public interface MovingPawn extends IPawn {
return new MovingPushed(pawn.getPlayer(), pawn.getRow(), pawn.getCol());
}
+
+ static boolean areSamePlayers(IPawn a, IPawn b) {
+ return a != null && b != null && a.getPlayer() == b.getPlayer();
+ }
}
diff --git a/src/main/java/laboratoire4/MovingPushed.java b/src/main/java/laboratoire4/MovingPushed.java
index b018334..f093a91 100644
--- a/src/main/java/laboratoire4/MovingPushed.java
+++ b/src/main/java/laboratoire4/MovingPushed.java
@@ -4,6 +4,7 @@ import java.util.Stack;
public class MovingPushed extends Pushed implements MovingPawn {
private final Stack previousMoves = new Stack<>();
+ private int moveCount = 0;
public MovingPushed(Player player, int row, int col) {
super(player, row, col);
@@ -13,6 +14,7 @@ public class MovingPushed extends Pushed implements MovingPawn {
public void move(PawnMovement movement) {
super.move(movement);
previousMoves.push(movement);
+ moveCount++;
}
@Override
@@ -20,6 +22,11 @@ public class MovingPushed extends Pushed implements MovingPawn {
PawnMovement move = previousMoves.pop();
setRow(row - getDirection());
setCol(col - move.getMove());
+ moveCount--;
}
+ @Override
+ public int getMoveCount() {
+ return moveCount;
+ }
}
diff --git a/src/main/java/laboratoire4/MovingPusher.java b/src/main/java/laboratoire4/MovingPusher.java
index 1a43458..30ae492 100644
--- a/src/main/java/laboratoire4/MovingPusher.java
+++ b/src/main/java/laboratoire4/MovingPusher.java
@@ -4,6 +4,7 @@ import java.util.Stack;
public class MovingPusher extends Pusher implements MovingPawn {
private final Stack previousMoves = new Stack<>();
+ private int moveCount = 0;
public MovingPusher(Player player, int row, int col) {
super(player, row, col);
@@ -13,6 +14,7 @@ public class MovingPusher extends Pusher implements MovingPawn {
public void move(PawnMovement movement) {
previousMoves.push(movement);
super.move(movement);
+ moveCount++;
}
@Override
@@ -20,5 +22,11 @@ public class MovingPusher extends Pusher implements MovingPawn {
PawnMovement move = previousMoves.pop();
setRow(row - getDirection());
setCol(col - move.getMove());
+ moveCount--;
+ }
+
+ @Override
+ public int getMoveCount() {
+ return moveCount;
}
}