Séparation de minimax et de l'évaluation
This commit is contained in:
parent
dbc494042b
commit
abf7f5bfd8
|
@ -5,8 +5,12 @@
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="41395b4b-3252-492c-a869-5f4dab107186" name="Changes" comment="Fixes?">
|
<list default="true" id="41395b4b-3252-492c-a869-5f4dab107186" name="Changes" comment="Fixes?">
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/BoardEvaluator.java" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/MiniMaxResult.java" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/MiniMax.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/MiniMax.java" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/MiniMax.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/MiniMax.java" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/Player.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/Player.java" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/PusherBoard.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/PusherBoard.java" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<list id="98b8a79f-2f53-42bf-96da-7af322697a0d" name="Changes by acastonguay" comment="" />
|
<list id="98b8a79f-2f53-42bf-96da-7af322697a0d" name="Changes by acastonguay" comment="" />
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
@ -17,8 +21,8 @@
|
||||||
<component name="FileTemplateManagerImpl">
|
<component name="FileTemplateManagerImpl">
|
||||||
<option name="RECENT_TEMPLATES">
|
<option name="RECENT_TEMPLATES">
|
||||||
<list>
|
<list>
|
||||||
<option value="Class" />
|
|
||||||
<option value="Interface" />
|
<option value="Interface" />
|
||||||
|
<option value="Class" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
@ -35,15 +39,8 @@
|
||||||
<component name="MarkdownSettingsMigration">
|
<component name="MarkdownSettingsMigration">
|
||||||
<option name="stateVersion" value="1" />
|
<option name="stateVersion" value="1" />
|
||||||
</component>
|
</component>
|
||||||
<component name="MavenImportPreferences">
|
|
||||||
<option name="importingSettings">
|
|
||||||
<MavenImportingSettings>
|
|
||||||
<option name="workspaceImportEnabled" value="true" />
|
|
||||||
</MavenImportingSettings>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="ProblemsViewState">
|
<component name="ProblemsViewState">
|
||||||
<option name="selectedTabId" value="ProjectErrors" />
|
<option name="selectedTabId" value="CurrentFile" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectId" id="2NFN0RGJNNJqiDmt34ixVwkIwEm" />
|
<component name="ProjectId" id="2NFN0RGJNNJqiDmt34ixVwkIwEm" />
|
||||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
|
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
|
||||||
|
@ -53,21 +50,22 @@
|
||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
<option name="showLibraryContents" value="true" />
|
<option name="showLibraryContents" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent">{
|
<component name="PropertiesComponent"><![CDATA[{
|
||||||
"keyToString": {
|
"keyToString": {
|
||||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||||
"codeWithMe.voiceChat.enabledByDefault": "false",
|
"codeWithMe.voiceChat.enabledByDefault": "false",
|
||||||
"last_opened_file_path": "/home/william/Dev/Projects",
|
"git-widget-placeholder": "william",
|
||||||
"node.js.detected.package.eslint": "true",
|
"last_opened_file_path": "/home/william/Dev/Projects",
|
||||||
"node.js.detected.package.tslint": "true",
|
"node.js.detected.package.eslint": "true",
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
"node.js.detected.package.tslint": "true",
|
||||||
"node.js.selected.package.tslint": "(autodetect)",
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
"nodejs_package_manager_path": "npm",
|
"node.js.selected.package.tslint": "(autodetect)",
|
||||||
"vue.rearranger.settings.migration": "true"
|
"nodejs_package_manager_path": "npm",
|
||||||
|
"vue.rearranger.settings.migration": "true"
|
||||||
}
|
}
|
||||||
}</component>
|
}]]></component>
|
||||||
<component name="RunManager" selected="Application.Main">
|
<component name="RunManager" selected="Application.Main">
|
||||||
<configuration name="Client" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
|
<configuration name="Client" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
|
||||||
<option name="MAIN_CLASS_NAME" value="laboratoire4.Client" />
|
<option name="MAIN_CLASS_NAME" value="laboratoire4.Client" />
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
package laboratoire4;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class BoardEvaluator {
|
||||||
|
public static int evaluate(MovingBoard game) {
|
||||||
|
MovingPawn[][] board = game.getBoard();
|
||||||
|
Collection<MovingPawn> maxPawns = game.getMaxPawns();
|
||||||
|
Collection<MovingPawn> minPawns = game.getMinPawns();
|
||||||
|
|
||||||
|
return evaluatePlayer(board, maxPawns, minPawns) - evaluatePlayer(board, minPawns, maxPawns);
|
||||||
|
}
|
||||||
|
|
||||||
|
//region Full Board
|
||||||
|
private static int evaluatePlayer(MovingPawn[][] board, Collection<MovingPawn> maxPawns, Collection<MovingPawn> minPawns) {
|
||||||
|
if (minPawns.size() == 0) {
|
||||||
|
return Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int score = evaluateMaxPawnCountScore(maxPawns, minPawns);
|
||||||
|
|
||||||
|
for (MovingPawn pawn : maxPawns) {
|
||||||
|
score += evaluatePawn(board, pawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int evaluateMaxPawnCountScore(Collection<MovingPawn> maxPawns, Collection<MovingPawn> minPawns) {
|
||||||
|
return evaluatePawnCountScore(minPawns) - evaluatePawnCountScore(maxPawns);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<MovingPawn> pawns) {
|
||||||
|
return (int) (0.001f * Math.pow(16 - pawns.size(), 4)) * 100;
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region Board
|
||||||
|
private static int evaluatePawn(MovingPawn[][] board, MovingPawn pawn) {
|
||||||
|
if (pawn.getRow() == pawn.getPlayer().getGoal()) {
|
||||||
|
return Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Favorise les pièces qui peuvent gagner au prochain tour
|
||||||
|
if (pawn.getRow() + pawn.getDirection() == pawn.getPlayer().getGoal()) {
|
||||||
|
return Integer.MAX_VALUE / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
score += evaluateHomePawnScore(pawn);
|
||||||
|
score += evaluatePushedScore(pawn);
|
||||||
|
score += evaluateValidMovesScore(board, pawn);
|
||||||
|
score += evaluateAttackScore(board, pawn);
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int evaluateHomePawnScore(MovingPawn pawn) {
|
||||||
|
return pawn.getRow() == pawn.getPlayer().getHome() ? 50 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int evaluatePushedScore(MovingPawn pawn) {
|
||||||
|
return pawn.isPusher() ? 0 : 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int evaluateValidMovesScore(MovingPawn[][] board, MovingPawn pawn) {
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
if (pawn.isMoveValid(board, Pawn.PawnMovement.LEFT_DIAGONAL)) {
|
||||||
|
score += 50;
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pawn.isMoveValid(board, Pawn.PawnMovement.RIGHT_DIAGONAL)) {
|
||||||
|
MovingPawn destPawn = board[row + pawn.getDirection()][col + 1];
|
||||||
|
|
||||||
|
if (destPawn != null && destPawn.getPlayer() != pawn.getPlayer()) {
|
||||||
|
score += 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Favorise les attaques de notre côté
|
||||||
|
if ((pawn.getPlayer() == Player.RED && pawn.getRow() < 4) ||
|
||||||
|
(pawn.getPlayer() == Player.BLACK && pawn.getRow() >= 4)) {
|
||||||
|
score *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
//endregion
|
||||||
|
}
|
|
@ -102,94 +102,7 @@ public class MiniMax {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int evaluate(MovingBoard board) {
|
private static int evaluate(MovingBoard board) {
|
||||||
return evaluate(board, board.getMaxPawns()) - evaluate(board, board.getMinPawns());
|
return BoardEvaluator.evaluate(board);
|
||||||
}
|
|
||||||
|
|
||||||
private static int evaluate(MovingBoard board, Collection<MovingPawn> pawns) {
|
|
||||||
int score = pawns.size() * 5;
|
|
||||||
|
|
||||||
for (MovingPawn pawn : pawns) {
|
|
||||||
score += evaluate(board, pawn);
|
|
||||||
}
|
|
||||||
|
|
||||||
return score;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int evaluate(MovingBoard game, MovingPawn pawn) {
|
|
||||||
if (pawn.getRow() == pawn.getPlayer().getGoal()) {
|
|
||||||
return Integer.MAX_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Favorise les pièces qui peuvent gagner au prochain tour
|
|
||||||
if (pawn.getRow() + pawn.getDirection() == pawn.getPlayer().getGoal()) {
|
|
||||||
return Integer.MAX_VALUE / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int score = 0;
|
|
||||||
score += attackScore(game, pawn);
|
|
||||||
|
|
||||||
// Favorise les attaques de notre côté
|
|
||||||
if ((pawn.getPlayer().getGoal() - pawn.getRow()) / 2f < 4) {
|
|
||||||
score *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
score += getValidMoveCount(game, pawn) * 50;
|
|
||||||
|
|
||||||
// Favorise les pushed
|
|
||||||
if (!pawn.isPusher()) {
|
|
||||||
score += 50;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Favorise les pièces qui n'ont pas encore bougées
|
|
||||||
if (pawn.getRow() == (pawn.getPlayer() == Player.RED ? 0 : 7)) {
|
|
||||||
score += 50;
|
|
||||||
}
|
|
||||||
|
|
||||||
return score;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int attackScore(MovingBoard game, MovingPawn pawn) {
|
|
||||||
int score = 0;
|
|
||||||
if (nextToOtherPlayer(game, pawn, -1)) {
|
|
||||||
score += 100;
|
|
||||||
}
|
|
||||||
if (nextToOtherPlayer(game, pawn, 1)) {
|
|
||||||
score += 100;
|
|
||||||
}
|
|
||||||
return score;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean nextToOtherPlayer(MovingBoard game, MovingPawn pawn, int colOffset) {
|
|
||||||
int row = pawn.getRow() + pawn.getDirection();
|
|
||||||
int col = pawn.getCol() + colOffset;
|
|
||||||
|
|
||||||
if (col < 0 || col > 7) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
MovingPawn dest = game.getBoard()[row][col];
|
|
||||||
return dest != null && dest.getPlayer() != pawn.getPlayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getValidMoveCount(MovingBoard game, MovingPawn pawn) {
|
|
||||||
int moveCount = 0;
|
|
||||||
|
|
||||||
// Diagonale gauche
|
|
||||||
if (pawn.getCol() > 0) {
|
|
||||||
moveCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Il n'y a pas de pièce adverse devant
|
|
||||||
if (!nextToOtherPlayer(game, pawn, 0)) {
|
|
||||||
moveCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Diagonale droite
|
|
||||||
if (pawn.getCol() < 7) {
|
|
||||||
moveCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return moveCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Action {
|
static class Action {
|
||||||
|
@ -209,44 +122,4 @@ public class MiniMax {
|
||||||
return movement;
|
return movement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MiniMaxResult {
|
|
||||||
private final int score;
|
|
||||||
private final int row;
|
|
||||||
private final int col;
|
|
||||||
private final Pawn.PawnMovement movement;
|
|
||||||
|
|
||||||
public MiniMaxResult(int score, int row, int col, Pawn.PawnMovement movement) {
|
|
||||||
this.score = score;
|
|
||||||
this.row = row;
|
|
||||||
this.col = col;
|
|
||||||
this.movement = movement;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getScore() {
|
|
||||||
return score;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRow() {
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCol() {
|
|
||||||
return col;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Pawn.PawnMovement getMovement() {
|
|
||||||
return movement;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "MiniMaxResult{" +
|
|
||||||
"score=" + score +
|
|
||||||
", col=" + col +
|
|
||||||
", row=" + row +
|
|
||||||
", movement=" + movement +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
package laboratoire4;
|
||||||
|
|
||||||
|
public class MiniMaxResult {
|
||||||
|
private final int score;
|
||||||
|
private final int row;
|
||||||
|
private final int col;
|
||||||
|
private final Pawn.PawnMovement movement;
|
||||||
|
|
||||||
|
public MiniMaxResult(int score, int row, int col, Pawn.PawnMovement movement) {
|
||||||
|
this.score = score;
|
||||||
|
this.row = row;
|
||||||
|
this.col = col;
|
||||||
|
this.movement = movement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getScore() {
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRow() {
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCol() {
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pawn.PawnMovement getMovement() {
|
||||||
|
return movement;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "MiniMaxResult{" +
|
||||||
|
"score=" + score +
|
||||||
|
", col=" + col +
|
||||||
|
", row=" + row +
|
||||||
|
", movement=" + movement +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,17 @@
|
||||||
package laboratoire4;
|
package laboratoire4;
|
||||||
|
|
||||||
public enum Player {
|
public enum Player {
|
||||||
BLACK(-1, 0),
|
BLACK(-1, 0, 7),
|
||||||
RED(1, 7);
|
RED(1, 7, 0);
|
||||||
|
|
||||||
private int direction;
|
private final int direction;
|
||||||
private int goal;
|
private final int goal;
|
||||||
|
private final int home;
|
||||||
|
|
||||||
Player(int direction, int goal) {
|
Player(int direction, int goal, int home) {
|
||||||
this.direction = direction;
|
this.direction = direction;
|
||||||
this.goal = goal;
|
this.goal = goal;
|
||||||
|
this.home = home;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDirection() {
|
public int getDirection() {
|
||||||
|
@ -19,4 +21,8 @@ public enum Player {
|
||||||
public int getGoal() {
|
public int getGoal() {
|
||||||
return goal;
|
return goal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getHome() {
|
||||||
|
return home;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class PusherBoard {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String runNextMove() {
|
public String runNextMove() {
|
||||||
MiniMax.MiniMaxResult result = MiniMax.miniMax(this);
|
MiniMaxResult result = MiniMax.miniMax(this);
|
||||||
Pawn pawn = board[result.getRow()][result.getCol()];
|
Pawn pawn = board[result.getRow()][result.getCol()];
|
||||||
System.out.println(result.getScore());
|
System.out.println(result.getScore());
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue