Meilleures heuristiques
This commit is contained in:
parent
648c325649
commit
c3cd91b199
|
@ -4,36 +4,22 @@
|
||||||
<option name="autoReloadType" value="SELECTIVE" />
|
<option name="autoReloadType" value="SELECTIVE" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="41395b4b-3252-492c-a869-5f4dab107186" name="Changes" comment="Plus d'heuristiques">
|
<list default="true" id="41395b4b-3252-492c-a869-5f4dab107186" name="Changes" comment="Beaucoup de changements">
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/Action.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/game/Game.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/game/GameUtils.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/PawnMovement.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/PawnUtils.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/AttackStrategy.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/DefenseStrategy.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/EvaluationResult.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/ImmediateDefenseStrategy.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/MasterStrategy.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/MiniMaxStrategy.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/StartingStrategy.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/Strategy.java" afterDir="false" />
|
|
||||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/WinningStrategy.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/BoardEvaluator.java" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/Client.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/Client.java" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/Client.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/Client.java" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/GameTree.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/GameTree.java" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/IPawn.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/IPawn.java" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/IPawn.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/IPawn.java" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/MiniMax.java" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/Pawn.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/Pawn.java" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/MiniMaxResult.java" beforeDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/PawnUtils.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/PawnUtils.java" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/MovingBoard.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/game/SimulatedGame.java" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/Pushed.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/Pushed.java" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/MovingPawn.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/SimulatedPawn.java" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/Pusher.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/Pusher.java" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/MovingPushed.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/SimulatedPushed.java" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/AttackStrategy.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/AttackStrategy.java" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/MovingPusher.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/SimulatedPusher.java" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/DefenseStrategy.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/DefenseStrategy.java" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/Pawn.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/Pawn.java" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/ImmediateDefenseStrategy.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/ImmediateDefenseStrategy.java" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/Pushed.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/Pushed.java" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/MasterStrategy.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/MasterStrategy.java" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/Pusher.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/pawns/Pusher.java" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/MiniMaxStrategy.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/MiniMaxStrategy.java" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/PusherBoard.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/game/PusherGame.java" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/StartingStrategy.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/RandomStrategy.java" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/Strategy.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/Strategy.java" afterDir="false" />
|
||||||
|
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/WinningStrategy.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/strategies/WinningStrategy.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" />
|
||||||
|
@ -55,6 +41,7 @@
|
||||||
<entry key="$PROJECT_DIR$" value="master" />
|
<entry key="$PROJECT_DIR$" value="master" />
|
||||||
</map>
|
</map>
|
||||||
</option>
|
</option>
|
||||||
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||||
</component>
|
</component>
|
||||||
<component name="MacroExpansionManager">
|
<component name="MacroExpansionManager">
|
||||||
<option name="directoryName" value="x0367gi2" />
|
<option name="directoryName" value="x0367gi2" />
|
||||||
|
@ -86,6 +73,7 @@
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
"node.js.selected.package.tslint": "(autodetect)",
|
"node.js.selected.package.tslint": "(autodetect)",
|
||||||
"nodejs_package_manager_path": "npm",
|
"nodejs_package_manager_path": "npm",
|
||||||
|
"settings.editor.selected.configurable": "reference.settings.ide.settings.new.ui",
|
||||||
"vue.rearranger.settings.migration": "true"
|
"vue.rearranger.settings.migration": "true"
|
||||||
}
|
}
|
||||||
}</component>
|
}</component>
|
||||||
|
@ -159,7 +147,11 @@
|
||||||
<workItem from="1680580123067" duration="326000" />
|
<workItem from="1680580123067" duration="326000" />
|
||||||
<workItem from="1680750346503" duration="2118000" />
|
<workItem from="1680750346503" duration="2118000" />
|
||||||
<workItem from="1680821970713" duration="10363000" />
|
<workItem from="1680821970713" duration="10363000" />
|
||||||
<workItem from="1680914341116" duration="16558000" />
|
<workItem from="1680914341116" duration="19656000" />
|
||||||
|
<workItem from="1681078101864" duration="10646000" />
|
||||||
|
<workItem from="1681099446755" duration="28000" />
|
||||||
|
<workItem from="1681099484843" duration="9035000" />
|
||||||
|
<workItem from="1681145055287" duration="4569000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00001" summary="MiniMax">
|
<task id="LOCAL-00001" summary="MiniMax">
|
||||||
<created>1679263366439</created>
|
<created>1679263366439</created>
|
||||||
|
@ -203,7 +195,14 @@
|
||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1680580135038</updated>
|
<updated>1680580135038</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="7" />
|
<task id="LOCAL-00007" summary="Beaucoup de changements">
|
||||||
|
<created>1681061194018</created>
|
||||||
|
<option name="number" value="00007" />
|
||||||
|
<option name="presentableId" value="LOCAL-00007" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1681061194019</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="8" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
@ -215,14 +214,18 @@
|
||||||
<MESSAGE value="Small fixes" />
|
<MESSAGE value="Small fixes" />
|
||||||
<MESSAGE value="Fixes?" />
|
<MESSAGE value="Fixes?" />
|
||||||
<MESSAGE value="Plus d'heuristiques" />
|
<MESSAGE value="Plus d'heuristiques" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="Plus d'heuristiques" />
|
<MESSAGE value="Beaucoup de changements" />
|
||||||
|
<option name="LAST_COMMIT_MESSAGE" value="Beaucoup de changements" />
|
||||||
</component>
|
</component>
|
||||||
<component name="XDebuggerManager">
|
<component name="XDebuggerManager">
|
||||||
<breakpoint-manager>
|
<breakpoint-manager>
|
||||||
<default-breakpoints>
|
<breakpoints>
|
||||||
<breakpoint enabled="true" type="CidrExceptionBreakpoint" />
|
<line-breakpoint enabled="true" type="java-line">
|
||||||
<breakpoint enabled="true" type="java-exception" />
|
<url>file://$PROJECT_DIR$/src/main/java/laboratoire4/strategies/MasterStrategy.java</url>
|
||||||
</default-breakpoints>
|
<line>20</line>
|
||||||
|
<option name="timeStamp" value="2" />
|
||||||
|
</line-breakpoint>
|
||||||
|
</breakpoints>
|
||||||
</breakpoint-manager>
|
</breakpoint-manager>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
|
@ -78,7 +78,7 @@ public class Client {
|
||||||
board.move(previousMove);
|
board.move(previousMove);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thread.sleep(500);
|
Thread.sleep(200);
|
||||||
|
|
||||||
String nextMove = board.runNextMove();
|
String nextMove = board.runNextMove();
|
||||||
System.out.printf("Prochain mouvement: %s\n\n", nextMove);
|
System.out.printf("Prochain mouvement: %s\n\n", nextMove);
|
||||||
|
|
|
@ -4,6 +4,8 @@ import laboratoire4.pawns.PawnMovement;
|
||||||
|
|
||||||
public interface IPawn {
|
public interface IPawn {
|
||||||
boolean isMoveValid(IPawn[][] board, PawnMovement movement);
|
boolean isMoveValid(IPawn[][] board, PawnMovement movement);
|
||||||
|
boolean isMoveValid(IPawn[][] board, PawnMovement movement, boolean ignorePlayers);
|
||||||
|
boolean isMoveValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol, boolean ignorePlayer);
|
||||||
boolean isMoveValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol);
|
boolean isMoveValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol);
|
||||||
void move(PawnMovement movement);
|
void move(PawnMovement movement);
|
||||||
boolean isPusher();
|
boolean isPusher();
|
||||||
|
|
|
@ -49,11 +49,19 @@ public abstract class Pawn implements IPawn {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMoveValid(IPawn[][] board, PawnMovement movement) {
|
public boolean isMoveValid(IPawn[][] board, PawnMovement movement) {
|
||||||
return isMoveValid(board, movement, row, col);
|
return isMoveValid(board, movement, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMoveValid(IPawn[][] board, PawnMovement movement, boolean ignorePlayers) {
|
||||||
|
return isMoveValid(board, movement, row, col, ignorePlayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMoveValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol) {
|
||||||
|
return isMoveValid(board, movement, fromRow, fromCol, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMoveValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol) {
|
public boolean isMoveValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol, boolean ignorePlayers) {
|
||||||
int nextRow = fromRow + getDirection();
|
int nextRow = fromRow + getDirection();
|
||||||
if (nextRow < 0 || nextRow >= board.length) {
|
if (nextRow < 0 || nextRow >= board.length) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -64,8 +72,8 @@ public abstract class Pawn implements IPawn {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isMoveReallyValid(board, movement, fromRow, fromCol);
|
return isMoveReallyValid(board, movement, fromRow, fromCol, ignorePlayers);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol);
|
protected abstract boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol, boolean ignorePlayers);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
package laboratoire4.pawns;
|
package laboratoire4.pawns;
|
||||||
|
|
||||||
|
import laboratoire4.Action;
|
||||||
import laboratoire4.IPawn;
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.Player;
|
||||||
|
import laboratoire4.game.Game;
|
||||||
|
import laboratoire4.game.GameUtils;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.ArrayDeque;
|
import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
public class PawnUtils {
|
public class PawnUtils {
|
||||||
public static int distanceFromGoal(IPawn pawn) {
|
public static int distanceFromGoal(IPawn pawn) {
|
||||||
|
@ -27,7 +32,7 @@ public class PawnUtils {
|
||||||
Point pos = positionsToVisit.poll();
|
Point pos = positionsToVisit.poll();
|
||||||
|
|
||||||
for (PawnMovement movement : PawnMovement.values()) {
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
if (!initialPawn.isMoveValid(board, movement, pos.x, pos.y)) {
|
if (!initialPawn.isMoveValid(board, movement, pos.x, pos.y, false)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,4 +55,121 @@ public class PawnUtils {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean canBeCaptured(Game game, IPawn pawn) {
|
||||||
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
|
int nextRow = pawn.getRow() + pawn.getDirection();
|
||||||
|
int nextCol = pawn.getCol() + movement.getMove();
|
||||||
|
|
||||||
|
if (nextRow < 0 || nextRow > 7 || nextCol < 0 || nextCol > 7) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPawn nearPawn = game.getBoard()[nextRow][nextCol];
|
||||||
|
if (nearPawn == null || PawnUtils.areSamePlayers(pawn, nearPawn)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nearPawn.isMoveValid(game.getBoard(), movement.getOpposite())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canBeCaptured(Game game, int row, int col, Player player) {
|
||||||
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
|
int nextRow = row + player.getDirection();
|
||||||
|
int nextCol = col + movement.getMove();
|
||||||
|
|
||||||
|
if (nextRow < 0 || nextRow > 7 || nextCol < 0 || nextCol > 7) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPawn nearPawn = game.getBoard()[nextRow][nextCol];
|
||||||
|
if (nearPawn == null || player == nearPawn.getPlayer()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nearPawn.isMoveValid(game.getBoard(), movement.getOpposite(), true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canCapture(Game game, IPawn max, IPawn min) {
|
||||||
|
int rowDistance = Math.abs(min.getRow() - max.getRow());
|
||||||
|
int colDistance = Math.abs(min.getCol() - max.getCol());
|
||||||
|
|
||||||
|
if (colDistance > rowDistance) {
|
||||||
|
// Le pion ne pourra jamais être atteint
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PawnUtils.canCapture(game, max, min, max.getRow(), max.getCol(), 0, rowDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canCapture(Game game, IPawn max, IPawn min, int row, int col, int depth, int maxDepth) {
|
||||||
|
if (min.getRow() == row && min.getCol() == col) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depth >= maxDepth) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
|
if (max.isMoveValid(game.getBoard(), movement, row, col, false)) {
|
||||||
|
int nextRow = row + max.getDirection();
|
||||||
|
int nextCol = col + movement.getMove();
|
||||||
|
|
||||||
|
if (canCapture(game, max, min, nextRow, nextCol, depth + 1, maxDepth)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends IPawn> Collection<Action<T>> getActions(Game game, boolean max) {
|
||||||
|
return getActions(game, max, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends IPawn> Collection<Action<T>> getActions(Game game, boolean max, boolean excludeDefense) {
|
||||||
|
List<Action<T>> actions = new ArrayList<>();
|
||||||
|
PawnMovement[] movements = PawnMovement.values();
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
Collection<T> pawns = (Collection<T>) (max ?
|
||||||
|
GameUtils.getMaxPawns(game.getBoard(), game.getPlayer()) :
|
||||||
|
GameUtils.getMinPawns(game.getBoard(), game.getPlayer()));
|
||||||
|
|
||||||
|
for (T pawn : pawns) {
|
||||||
|
if (excludeDefense && pawn.getRow() == pawn.getPlayer().getHome()) {
|
||||||
|
int col = pawn.getCol();
|
||||||
|
|
||||||
|
// Si possible, on ne bouge pas ces pushers, comme ça on a une défense d'urgence totale
|
||||||
|
if (col == 1 || col == 2 || col == 5 || col == 6) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PawnMovement movement : movements) {
|
||||||
|
if (pawn.isMoveValid(game.getBoard(), movement)) {
|
||||||
|
actions.add(new Action<>(pawn, movement));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (excludeDefense && actions.isEmpty()) {
|
||||||
|
return getActions(game, max, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.shuffle(actions);
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public class Pushed extends Pawn {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol) {
|
public boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol, boolean ignorePlayers) {
|
||||||
int direction = getDirection();
|
int direction = getDirection();
|
||||||
IPawn pusher = null;
|
IPawn pusher = null;
|
||||||
IPawn to = board[fromRow + direction][fromCol + movement.getMove()];
|
IPawn to = board[fromRow + direction][fromCol + movement.getMove()];
|
||||||
|
@ -28,7 +28,7 @@ public class Pushed extends Pawn {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean pusherValid = pusher != null && pusher.isPusher() && pusher.getPlayer() == player;
|
boolean pusherValid = pusher != null && pusher.isPusher() && pusher.getPlayer() == player;
|
||||||
boolean destinationValid = to == null || (movement != PawnMovement.STRAIGHT && to.getPlayer() != this.player);
|
boolean destinationValid = to == null || (movement != PawnMovement.STRAIGHT && (ignorePlayers || to.getPlayer() != this.player));
|
||||||
return pusherValid && destinationValid;
|
return pusherValid && destinationValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,14 +14,14 @@ public class Pusher extends Pawn {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol) {
|
public boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol, boolean ignorePlayers) {
|
||||||
IPawn to = board[fromRow + getDirection()][fromCol + movement.getMove()];
|
IPawn to = board[fromRow + getDirection()][fromCol + movement.getMove()];
|
||||||
|
|
||||||
if (to == null) {
|
if (to == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to.getPlayer() == player) {
|
if (!ignorePlayers && to.getPlayer() == player) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,34 +1,64 @@
|
||||||
package laboratoire4.strategies;
|
package laboratoire4.strategies;
|
||||||
|
|
||||||
|
import laboratoire4.Action;
|
||||||
import laboratoire4.IPawn;
|
import laboratoire4.IPawn;
|
||||||
import laboratoire4.game.Game;
|
import laboratoire4.game.Game;
|
||||||
import laboratoire4.game.GameUtils;
|
import laboratoire4.game.GameUtils;
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
import laboratoire4.pawns.PawnUtils;
|
import laboratoire4.pawns.PawnUtils;
|
||||||
import laboratoire4.pawns.SimulatedPawn;
|
import laboratoire4.pawns.SimulatedPawn;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class AttackStrategy extends MiniMaxStrategy {
|
public class AttackStrategy extends MiniMaxStrategy {
|
||||||
private static final int ATTACK_DISTANCE_FROM_GOAL = 4;
|
private static final int ATTACK_DISTANCE_FROM_GOAL = 4;
|
||||||
|
|
||||||
private long originalMinPawnCount;
|
private long originalMinPawnCount;
|
||||||
|
private long originalMaxPusherCount;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EvaluationResult getNextMove(Game game) {
|
public EvaluationResult getNextMove(Game game) {
|
||||||
originalMinPawnCount = GameUtils.getMinPawnsAsStream(game.getBoard(), game.getPlayer()).count();
|
originalMinPawnCount = GameUtils.getMinPawnsAsStream(game.getBoard(), game.getPlayer()).count();
|
||||||
|
originalMaxPusherCount = GameUtils.getMaxPawnsAsStream(game.getBoard(), game.getPlayer())
|
||||||
|
.filter(IPawn::isPusher)
|
||||||
|
.count();
|
||||||
|
|
||||||
return super.getNextMove(game);
|
return super.getNextMove(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int evaluateSimulation() {
|
protected int evaluateSimulation() {
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
if (getMinPawns().stream().anyMatch(p -> p.getRow() == p.getPlayer().getGoal())) {
|
||||||
|
return Integer.MIN_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
long pusherCount = getMaxPawns().stream().filter(IPawn::isPusher).count();
|
||||||
|
if (pusherCount == 0) {
|
||||||
|
return Integer.MIN_VALUE;
|
||||||
|
}
|
||||||
|
score -= Math.pow(originalMaxPusherCount - pusherCount, 2);
|
||||||
|
|
||||||
for (SimulatedPawn pawn : getMaxPawns()) {
|
for (SimulatedPawn pawn : getMaxPawns()) {
|
||||||
if (pawn.getRow() == pawn.getPlayer().getGoal()) {
|
if (pawn.getRow() == pawn.getPlayer().getGoal()) {
|
||||||
return Integer.MAX_VALUE;
|
return Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PawnUtils.hasEasyWinPath(game.getBoard(), pawn)) {
|
||||||
|
return Integer.MAX_VALUE / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int score = 0;
|
// int distanceFromGoal = PawnUtils.distanceFromGoal(pawn);
|
||||||
|
// if (distanceFromGoal <= ATTACK_DISTANCE_FROM_GOAL) {
|
||||||
|
// score += ATTACK_DISTANCE_FROM_GOAL - distanceFromGoal + 1;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (pawn.isPusher() && PawnUtils.canBeCaptured(game, pawn)) {
|
||||||
|
score -= 10; // On ne veut pas nécessairement bouger où on peut être capturé facilement
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int minPawnCount = getMinPawns().size();
|
int minPawnCount = getMinPawns().size();
|
||||||
long capturedPawnCount = originalMinPawnCount - minPawnCount;
|
long capturedPawnCount = originalMinPawnCount - minPawnCount;
|
||||||
|
@ -51,7 +81,11 @@ public class AttackStrategy extends MiniMaxStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (distanceFromGoal == 2) {
|
if (distanceFromGoal == 2) {
|
||||||
weight = PawnUtils.hasEasyWinPath(game.getBoard(), pawn) ? 8 : 5;
|
if (PawnUtils.hasEasyWinPath(game.getBoard(), pawn)) {
|
||||||
|
weight = 8;
|
||||||
|
} else {
|
||||||
|
weight = 5;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (distanceFromGoal > 2 && distanceFromGoal <= ATTACK_DISTANCE_FROM_GOAL) {
|
if (distanceFromGoal > 2 && distanceFromGoal <= ATTACK_DISTANCE_FROM_GOAL) {
|
||||||
|
@ -65,4 +99,14 @@ public class AttackStrategy extends MiniMaxStrategy {
|
||||||
|
|
||||||
return maxWeight;
|
return maxWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean cantBeCaptured(Action<IPawn> action) {
|
||||||
|
IPawn pawn = action.getPawn();
|
||||||
|
PawnMovement movement = action.getMovement();
|
||||||
|
|
||||||
|
int row = pawn.getRow() + pawn.getDirection();
|
||||||
|
int col = pawn.getCol() + movement.getMove();
|
||||||
|
|
||||||
|
return !PawnUtils.canBeCaptured(game, row, col, pawn.getPlayer());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package laboratoire4.strategies;
|
package laboratoire4.strategies;
|
||||||
|
|
||||||
|
import laboratoire4.Action;
|
||||||
import laboratoire4.IPawn;
|
import laboratoire4.IPawn;
|
||||||
import laboratoire4.game.Game;
|
import laboratoire4.game.Game;
|
||||||
import laboratoire4.game.GameUtils;
|
import laboratoire4.game.GameUtils;
|
||||||
|
@ -13,6 +14,7 @@ import java.util.Optional;
|
||||||
|
|
||||||
public class DefenseStrategy extends MiniMaxStrategy {
|
public class DefenseStrategy extends MiniMaxStrategy {
|
||||||
private static final int DEFENSE_DISTANCE_FROM_HOME = 3;
|
private static final int DEFENSE_DISTANCE_FROM_HOME = 3;
|
||||||
|
private static final int PAWN_DEFENSE_DISTANCE = 3;
|
||||||
|
|
||||||
private final Map<IPawn, Integer> dangerousPawns = new HashMap<>();
|
private final Map<IPawn, Integer> dangerousPawns = new HashMap<>();
|
||||||
|
|
||||||
|
@ -31,23 +33,35 @@ public class DefenseStrategy extends MiniMaxStrategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.getNextMove(game);
|
return super.getNextMove(game);
|
||||||
|
// EvaluationResult result = super.getNextMove(game);
|
||||||
|
// if (Math.abs(result.getRow() - game.getPlayer().getHome()) > DEFENSE_DISTANCE_FROM_HOME) {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getWeight(Game game) {
|
public int getWeight(Game game) {
|
||||||
Collection<IPawn> minPawns = GameUtils.getMinPawns(game.getBoard(), game.getPlayer());
|
Collection<IPawn> minPawns = GameUtils.getMinPawns(game.getBoard(), game.getPlayer());
|
||||||
|
Collection<IPawn> maxPawns = GameUtils.getMaxPawns(game.getBoard(), game.getPlayer());
|
||||||
int maxWeight = 0;
|
int maxWeight = 0;
|
||||||
|
|
||||||
for (IPawn pawn : minPawns) {
|
for (IPawn pawn : minPawns) {
|
||||||
int weight = 0;
|
int weight = 0;
|
||||||
|
|
||||||
int distanceFromGoal = PawnUtils.distanceFromGoal(pawn);
|
int distanceFromGoal = PawnUtils.distanceFromGoal(pawn);
|
||||||
if (distanceFromGoal <= 1) {
|
if (distanceFromGoal <= 2) {
|
||||||
|
if (PawnUtils.hasEasyWinPath(game.getBoard(), pawn)) {
|
||||||
|
if (maxPawns.stream().noneMatch(p -> PawnUtils.canCapture(game, p, pawn))) {
|
||||||
|
// Le pion ne peut pas être arrêté, on doit attaquer !
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
return WEIGHT_MAX;
|
return WEIGHT_MAX;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if (distanceFromGoal == 2) {
|
weight = 5;
|
||||||
weight = PawnUtils.hasEasyWinPath(game.getBoard(), pawn) ? 8 : 5;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (distanceFromGoal > 2 && distanceFromGoal <= DEFENSE_DISTANCE_FROM_HOME) {
|
if (distanceFromGoal > 2 && distanceFromGoal <= DEFENSE_DISTANCE_FROM_HOME) {
|
||||||
|
@ -64,15 +78,17 @@ public class DefenseStrategy extends MiniMaxStrategy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int evaluateSimulation() {
|
protected int evaluateSimulation() {
|
||||||
for (SimulatedPawn pawn : getMinPawns()) {
|
int score = 0;
|
||||||
|
|
||||||
|
Collection<SimulatedPawn> maxPawns = getMaxPawns();
|
||||||
|
Collection<SimulatedPawn> minPawns = getMinPawns();
|
||||||
|
|
||||||
|
for (SimulatedPawn pawn : minPawns) {
|
||||||
if (pawn.getRow() == pawn.getPlayer().getGoal()) {
|
if (pawn.getRow() == pawn.getPlayer().getGoal()) {
|
||||||
return Integer.MIN_VALUE;
|
return Integer.MIN_VALUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int score = 0;
|
|
||||||
|
|
||||||
for (IPawn dangerousPawn : dangerousPawns.keySet()) {
|
for (IPawn dangerousPawn : dangerousPawns.keySet()) {
|
||||||
Optional<SimulatedPawn> simulated = GameUtils.getMinPawnsAsStream(game.getBoard(), game.getPlayer())
|
Optional<SimulatedPawn> simulated = GameUtils.getMinPawnsAsStream(game.getBoard(), game.getPlayer())
|
||||||
.filter(p -> p.getOriginalRow() == dangerousPawn.getRow() && p.getOriginalCol() == dangerousPawn.getCol())
|
.filter(p -> p.getOriginalRow() == dangerousPawn.getRow() && p.getOriginalCol() == dangerousPawn.getCol())
|
||||||
|
@ -85,9 +101,65 @@ public class DefenseStrategy extends MiniMaxStrategy {
|
||||||
// On est toujours en danger
|
// On est toujours en danger
|
||||||
int distance = PawnUtils.distanceFromGoal(simulated.get());
|
int distance = PawnUtils.distanceFromGoal(simulated.get());
|
||||||
score -= Math.pow(DEFENSE_DISTANCE_FROM_HOME - distance + 1, 3);
|
score -= Math.pow(DEFENSE_DISTANCE_FROM_HOME - distance + 1, 3);
|
||||||
|
|
||||||
|
for (SimulatedPawn pawn : maxPawns) {
|
||||||
|
score += PAWN_DEFENSE_DISTANCE - distanceFromCapture(pawn, simulated.get()) * 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SimulatedPawn pawn : maxPawns) {
|
||||||
|
if (PawnUtils.canBeCaptured(game, pawn)) {
|
||||||
|
score -= 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On préfère les groupes de 2 pushers, puisqu'ils ont une meilleure surface de défense
|
||||||
|
if (!pawn.isPusher()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int col = pawn.getCol();
|
||||||
|
int row = pawn.getRow();
|
||||||
|
|
||||||
|
if (col > 0 && PawnUtils.areSamePlayers(pawn, game.getBoard()[col - 1][row])) {
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
if (col < 7 && PawnUtils.areSamePlayers(pawn, game.getBoard()[col + 1][row])) {
|
||||||
|
score += 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Collection<Action<IPawn>> getActions(boolean max) {
|
||||||
|
Collection<SimulatedPawn> pawns = max ? getMaxPawns() : getMinPawns();
|
||||||
|
|
||||||
|
long defensivePawnCount = pawns.stream()
|
||||||
|
.filter(IPawn::isPusher)
|
||||||
|
.filter(p -> p.getRow() != p.getPlayer().getHome())
|
||||||
|
.filter(p -> PawnUtils.distanceFromHome(p) <= DEFENSE_DISTANCE_FROM_HOME)
|
||||||
|
.count();
|
||||||
|
|
||||||
|
return PawnUtils.getActions(game, max, defensivePawnCount > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int distanceFromCapture(IPawn max, IPawn min) {
|
||||||
|
int rowDistance = Math.abs(min.getRow() - max.getRow());
|
||||||
|
int colDistance = Math.abs(min.getCol() - max.getCol());
|
||||||
|
|
||||||
|
if (colDistance > rowDistance) {
|
||||||
|
// Le pion ne pourra jamais être atteint
|
||||||
|
return PAWN_DEFENSE_DISTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PawnUtils.canCapture(game, max, min, max.getRow(), max.getCol(), 0, rowDistance)) {
|
||||||
|
return PAWN_DEFENSE_DISTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rowDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ public class ImmediateDefenseStrategy implements Strategy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EvaluationResult getNextMove(Game game) {
|
public EvaluationResult getNextMove(Game game) {
|
||||||
|
// On utilise pas la méthode utilitaire, car on veut bouger la ligne de défense si nécessaire
|
||||||
for (IPawn pawn : GameUtils.getMaxPawns(game.getBoard(), game.getPlayer())) {
|
for (IPawn pawn : GameUtils.getMaxPawns(game.getBoard(), game.getPlayer())) {
|
||||||
if (PawnUtils.distanceFromHome(pawn) > IMM_DEFENSE_DISTANCE_FROM_HOME) {
|
if (PawnUtils.distanceFromHome(pawn) > IMM_DEFENSE_DISTANCE_FROM_HOME) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -13,8 +13,6 @@ public class MasterStrategy implements Strategy {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean starting = true;
|
|
||||||
|
|
||||||
private MasterStrategy() {
|
private MasterStrategy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,8 +33,8 @@ public class MasterStrategy implements Strategy {
|
||||||
|
|
||||||
private Strategy getBestStrategy(Game game) {
|
private Strategy getBestStrategy(Game game) {
|
||||||
Strategy[] strategies = new Strategy[]{
|
Strategy[] strategies = new Strategy[]{
|
||||||
new WinningStrategy(),
|
|
||||||
new ImmediateDefenseStrategy(),
|
new ImmediateDefenseStrategy(),
|
||||||
|
new WinningStrategy(),
|
||||||
new DefenseStrategy(),
|
new DefenseStrategy(),
|
||||||
new AttackStrategy()
|
new AttackStrategy()
|
||||||
};
|
};
|
||||||
|
@ -57,17 +55,10 @@ public class MasterStrategy implements Strategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxWeight > 0) {
|
if (maxWeight > 0) {
|
||||||
starting = false;
|
|
||||||
return bestStrategy;
|
return bestStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
//noinspection IfStatementWithIdenticalBranches
|
return new RandomStrategy();
|
||||||
if (starting) {
|
|
||||||
return new StartingStrategy();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO WN: Default strategy
|
|
||||||
return new StartingStrategy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
package laboratoire4.strategies;
|
package laboratoire4.strategies;
|
||||||
|
|
||||||
import laboratoire4.Action;
|
import laboratoire4.Action;
|
||||||
|
import laboratoire4.IPawn;
|
||||||
import laboratoire4.game.Game;
|
import laboratoire4.game.Game;
|
||||||
import laboratoire4.game.GameUtils;
|
import laboratoire4.game.GameUtils;
|
||||||
import laboratoire4.game.SimulatedGame;
|
import laboratoire4.game.SimulatedGame;
|
||||||
import laboratoire4.pawns.PawnMovement;
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
import laboratoire4.pawns.PawnUtils;
|
||||||
import laboratoire4.pawns.SimulatedPawn;
|
import laboratoire4.pawns.SimulatedPawn;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public abstract class MiniMaxStrategy implements Strategy {
|
public abstract class MiniMaxStrategy implements Strategy {
|
||||||
private static final int MAX_DEPTH = 4;
|
private static final int MAX_DEPTH = 6;
|
||||||
|
|
||||||
protected SimulatedGame game;
|
protected SimulatedGame game;
|
||||||
|
|
||||||
|
@ -28,11 +27,11 @@ public abstract class MiniMaxStrategy implements Strategy {
|
||||||
EvaluationResult maxResult = null;
|
EvaluationResult maxResult = null;
|
||||||
int maxScore = Integer.MIN_VALUE;
|
int maxScore = Integer.MIN_VALUE;
|
||||||
|
|
||||||
for (Action<SimulatedPawn> action : getActions(true)) {
|
for (Action<IPawn> action : getActions(true)) {
|
||||||
int score = min(0, Integer.MIN_VALUE, Integer.MAX_VALUE);
|
int score = min(0, Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||||
|
|
||||||
if (maxResult == null || score > maxScore) {
|
if (maxResult == null || score > maxScore) {
|
||||||
SimulatedPawn pawn = action.getPawn();
|
IPawn pawn = action.getPawn();
|
||||||
maxResult = new EvaluationResult(pawn.getRow(), pawn.getCol(), action.getMovement());
|
maxResult = new EvaluationResult(pawn.getRow(), pawn.getCol(), action.getMovement());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,13 +41,13 @@ public abstract class MiniMaxStrategy implements Strategy {
|
||||||
|
|
||||||
private int max(int depth, int alpha, int beta) {
|
private int max(int depth, int alpha, int beta) {
|
||||||
if (depth >= MAX_DEPTH) {
|
if (depth >= MAX_DEPTH) {
|
||||||
return evaluateSimulation();
|
return evaluate();
|
||||||
}
|
}
|
||||||
|
|
||||||
int maxScore = Integer.MIN_VALUE;
|
int maxScore = Integer.MIN_VALUE;
|
||||||
|
|
||||||
for (Action<SimulatedPawn> action : getActions(true)) {
|
for (Action<IPawn> action : getActions(true)) {
|
||||||
SimulatedPawn pawn = action.getPawn();
|
IPawn pawn = action.getPawn();
|
||||||
PawnMovement movement = action.getMovement();
|
PawnMovement movement = action.getMovement();
|
||||||
|
|
||||||
game.move(pawn, movement);
|
game.move(pawn, movement);
|
||||||
|
@ -69,13 +68,13 @@ public abstract class MiniMaxStrategy implements Strategy {
|
||||||
|
|
||||||
private int min(int depth, int alpha, int beta) {
|
private int min(int depth, int alpha, int beta) {
|
||||||
if (depth >= MAX_DEPTH) {
|
if (depth >= MAX_DEPTH) {
|
||||||
return evaluateSimulation();
|
return evaluate();
|
||||||
}
|
}
|
||||||
|
|
||||||
int minScore = Integer.MAX_VALUE;
|
int minScore = Integer.MAX_VALUE;
|
||||||
|
|
||||||
for (Action<SimulatedPawn> action : getActions(false)) {
|
for (Action<IPawn> action : getActions(false)) {
|
||||||
SimulatedPawn pawn = action.getPawn();
|
IPawn pawn = action.getPawn();
|
||||||
PawnMovement movement = action.getMovement();
|
PawnMovement movement = action.getMovement();
|
||||||
|
|
||||||
game.move(pawn, movement);
|
game.move(pawn, movement);
|
||||||
|
@ -94,23 +93,6 @@ public abstract class MiniMaxStrategy implements Strategy {
|
||||||
return minScore;
|
return minScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Collection<Action<SimulatedPawn>> getActions(boolean max) {
|
|
||||||
List<Action<SimulatedPawn>> actions = new ArrayList<>();
|
|
||||||
Collection<SimulatedPawn> pawns = max ? getMaxPawns() : getMinPawns();
|
|
||||||
PawnMovement[] movements = PawnMovement.values();
|
|
||||||
|
|
||||||
for (SimulatedPawn pawn : pawns) {
|
|
||||||
for (PawnMovement movement : movements) {
|
|
||||||
if (pawn.isMoveValid(game.getBoard(), movement)) {
|
|
||||||
actions.add(new Action<>(pawn, movement));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Collections.shuffle(actions);
|
|
||||||
return actions;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Collection<SimulatedPawn> getMaxPawns() {
|
protected Collection<SimulatedPawn> getMaxPawns() {
|
||||||
return GameUtils.getMaxPawns(game.getBoard(), game.getPlayer());
|
return GameUtils.getMaxPawns(game.getBoard(), game.getPlayer());
|
||||||
}
|
}
|
||||||
|
@ -119,5 +101,17 @@ public abstract class MiniMaxStrategy implements Strategy {
|
||||||
return GameUtils.getMinPawns(game.getBoard(), game.getPlayer());
|
return GameUtils.getMinPawns(game.getBoard(), game.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Collection<Action<IPawn>> getActions(boolean max) {
|
||||||
|
return PawnUtils.getActions(game, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int evaluate() {
|
||||||
|
int score = evaluateSimulation();
|
||||||
|
|
||||||
|
// Logique générale
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract int evaluateSimulation();
|
protected abstract int evaluateSimulation();
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,18 +14,20 @@ import java.util.stream.Collectors;
|
||||||
* Au début du jeu, il n'y a pas d'attaques, de défense ou de possibilités de gagner (pas besoin de minimax).
|
* Au début du jeu, il n'y a pas d'attaques, de défense ou de possibilités de gagner (pas besoin de minimax).
|
||||||
* Alors, on avance quelques pions (pas tous) aléatoirement.
|
* Alors, on avance quelques pions (pas tous) aléatoirement.
|
||||||
*/
|
*/
|
||||||
public class StartingStrategy implements Strategy {
|
public class RandomStrategy implements Strategy {
|
||||||
private static final int PAWN_TO_MOVE = 3;
|
private static final int PAWN_TO_MOVE = 2;
|
||||||
private final Random random = new Random();
|
private final Random random = new Random();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EvaluationResult getNextMove(Game game) {
|
public EvaluationResult getNextMove(Game game) {
|
||||||
Collection<IPawn> outsideHomePawns = GameUtils.getMaxPawnsAsStream(game.getBoard(), game.getPlayer())
|
Collection<IPawn> outsideHomePushers = GameUtils.getMaxPawnsAsStream(game.getBoard(), game.getPlayer())
|
||||||
.filter(p -> p.getRow() != p.getPlayer().getHome() && p.getRow() != p.getPlayer().getHome() + p.getDirection())
|
.filter(IPawn::isPusher)
|
||||||
|
.filter(p -> p.getRow() != p.getPlayer().getHome())
|
||||||
|
.filter(p -> p.getRow() != p.getPlayer().getHome() + p.getDirection())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
if (outsideHomePawns.size() > PAWN_TO_MOVE) {
|
if (outsideHomePushers.size() >= PAWN_TO_MOVE) {
|
||||||
List<Action<IPawn>> validActions = Strategy.getValidActions(game.getBoard(), outsideHomePawns);
|
List<Action<IPawn>> validActions = Strategy.getValidActions(game.getBoard(), outsideHomePushers);
|
||||||
if (!validActions.isEmpty()) {
|
if (!validActions.isEmpty()) {
|
||||||
return getRandomMove(validActions);
|
return getRandomMove(validActions);
|
||||||
}
|
}
|
|
@ -12,6 +12,7 @@ public interface Strategy {
|
||||||
public static final int WEIGHT_MAX = 10;
|
public static final int WEIGHT_MAX = 10;
|
||||||
|
|
||||||
EvaluationResult getNextMove(Game game);
|
EvaluationResult getNextMove(Game game);
|
||||||
|
|
||||||
int getWeight(Game game);
|
int getWeight(Game game);
|
||||||
|
|
||||||
static List<Action<IPawn>> getValidActions(Game game) {
|
static List<Action<IPawn>> getValidActions(Game game) {
|
||||||
|
@ -25,9 +26,22 @@ public interface Strategy {
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<Action<IPawn>> getValidActions(IPawn[][] board, Collection<IPawn> pawns) {
|
static List<Action<IPawn>> getValidActions(IPawn[][] board, Collection<IPawn> pawns) {
|
||||||
|
return getValidActions(board, pawns, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Action<IPawn>> getValidActions(IPawn[][] board, Collection<IPawn> pawns, boolean excludeDefense) {
|
||||||
List<Action<IPawn>> validActions = new ArrayList<>();
|
List<Action<IPawn>> validActions = new ArrayList<>();
|
||||||
|
|
||||||
for (IPawn pawn : pawns) {
|
for (IPawn pawn : pawns) {
|
||||||
|
if (excludeDefense && pawn.getRow() == pawn.getPlayer().getHome()) {
|
||||||
|
int col = pawn.getCol();
|
||||||
|
|
||||||
|
// Si possible, on ne bouge pas ces pushers, comme ça on a une défense d'urgence totale
|
||||||
|
if (col == 1 || col == 2 || col == 5 || col == 6) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (PawnMovement movement : PawnMovement.values()) {
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
if (pawn.isMoveValid(board, movement)) {
|
if (pawn.isMoveValid(board, movement)) {
|
||||||
validActions.add(new Action<>(pawn, movement));
|
validActions.add(new Action<>(pawn, movement));
|
||||||
|
@ -35,6 +49,10 @@ public interface Strategy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (excludeDefense && validActions.isEmpty()) {
|
||||||
|
return getValidActions(board, pawns, false);
|
||||||
|
}
|
||||||
|
|
||||||
return validActions;
|
return validActions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,16 @@ import laboratoire4.IPawn;
|
||||||
import laboratoire4.game.Game;
|
import laboratoire4.game.Game;
|
||||||
import laboratoire4.game.GameUtils;
|
import laboratoire4.game.GameUtils;
|
||||||
import laboratoire4.pawns.PawnMovement;
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
import laboratoire4.pawns.PawnUtils;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class WinningStrategy implements Strategy {
|
public class WinningStrategy implements Strategy {
|
||||||
|
private Action<IPawn> winningAction;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EvaluationResult getNextMove(Game game) {
|
public EvaluationResult getNextMove(Game game) {
|
||||||
Action<IPawn> winningAction = getWinningAction(game);
|
|
||||||
|
|
||||||
if (winningAction == null) {
|
if (winningAction == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -24,16 +25,20 @@ public class WinningStrategy implements Strategy {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getWeight(Game game) {
|
public int getWeight(Game game) {
|
||||||
Action<IPawn> winningAction = getWinningAction(game);
|
winningAction = findImmediateWinningAction(game);
|
||||||
|
|
||||||
if (winningAction == null) {
|
if (winningAction == null) {
|
||||||
|
// On cherche un chemin où on peut gagner quoi qu'il arrive
|
||||||
|
winningAction = findWinningPath(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (winningAction != null) {
|
||||||
|
return WEIGHT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return WEIGHT_MAX + 1;
|
private static Action<IPawn> findImmediateWinningAction(Game game) {
|
||||||
}
|
|
||||||
|
|
||||||
private static Action<IPawn> getWinningAction(Game game) {
|
|
||||||
Collection<IPawn> nearPawns = GameUtils.getMaxPawnsAsStream(game.getBoard(), game.getPlayer())
|
Collection<IPawn> nearPawns = GameUtils.getMaxPawnsAsStream(game.getBoard(), game.getPlayer())
|
||||||
.filter(p -> p.getRow() + p.getDirection() == p.getPlayer().getGoal())
|
.filter(p -> p.getRow() + p.getDirection() == p.getPlayer().getGoal())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
@ -41,11 +46,60 @@ public class WinningStrategy implements Strategy {
|
||||||
for (IPawn pawn : nearPawns) {
|
for (IPawn pawn : nearPawns) {
|
||||||
for (PawnMovement movement : PawnMovement.values()) {
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
if (pawn.isMoveValid(game.getBoard(), movement)) {
|
if (pawn.isMoveValid(game.getBoard(), movement)) {
|
||||||
return new Action(pawn, movement);
|
return new Action<>(pawn, movement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Action<IPawn> findWinningPath(Game game) {
|
||||||
|
for (IPawn pawn : GameUtils.getMaxPawns(game.getBoard(), game.getPlayer())) {
|
||||||
|
if (PawnUtils.distanceFromGoal(pawn) > 4) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
|
int nextRow = pawn.getRow() + pawn.getDirection();
|
||||||
|
int nextCol = pawn.getCol() + movement.getMove();
|
||||||
|
|
||||||
|
if (pawn.isMoveValid(game.getBoard(), movement) &&
|
||||||
|
!PawnUtils.canBeCaptured(game, nextRow, nextCol, game.getPlayer()) &&
|
||||||
|
hasWinningPath(game, pawn, nextRow, nextCol)) {
|
||||||
|
return new Action<>(pawn, movement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasWinningPath(Game game, IPawn initialPawn, int row, int col) {
|
||||||
|
if (row == initialPawn.getPlayer().getGoal()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
|
int nextRow = row + initialPawn.getDirection();
|
||||||
|
int nextCol = col + movement.getMove();
|
||||||
|
|
||||||
|
if (!initialPawn.isMoveValid(game.getBoard(), movement, row, col)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPawn nextPawn = game.getBoard()[nextRow][nextCol];
|
||||||
|
if (nextPawn == null && hasWinningPath(game, initialPawn, nextRow, nextCol)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextPawn != null && !PawnUtils.areSamePlayers(initialPawn, nextPawn) &&
|
||||||
|
!PawnUtils.canBeCaptured(game, row, col, initialPawn.getPlayer()) &&
|
||||||
|
hasWinningPath(game, initialPawn, nextRow, nextCol)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue