Compare commits
10 Commits
Author | SHA1 | Date |
---|---|---|
FyloZ | 48f2b72c40 | |
FyloZ | 7416df8a17 | |
FyloZ | eb0146f10a | |
william | c3cd91b199 | |
william | 648c325649 | |
william | 5f7d74e0ae | |
FyloZ | abf7f5bfd8 | |
william | dbc494042b | |
william | 02b49c9437 | |
william | bd0fc7edfd |
|
@ -0,0 +1,8 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
|
@ -8,7 +8,7 @@
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
|
@ -4,11 +4,20 @@
|
||||||
<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="Small fixes">
|
<list default="true" id="41395b4b-3252-492c-a869-5f4dab107186" name="Changes" comment="Limite la longueur d'un coup sous les 5 secondes">
|
||||||
|
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" 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/Client.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/Client.java" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/pom.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/game/PusherGame.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/game/PusherGame.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" />
|
<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/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/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/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/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/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/strategies/RandomStrategy.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" />
|
||||||
|
@ -19,6 +28,7 @@
|
||||||
<component name="FileTemplateManagerImpl">
|
<component name="FileTemplateManagerImpl">
|
||||||
<option name="RECENT_TEMPLATES">
|
<option name="RECENT_TEMPLATES">
|
||||||
<list>
|
<list>
|
||||||
|
<option value="Interface" />
|
||||||
<option value="Class" />
|
<option value="Class" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
|
@ -26,9 +36,10 @@
|
||||||
<component name="Git.Settings">
|
<component name="Git.Settings">
|
||||||
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||||
<map>
|
<map>
|
||||||
<entry key="$PROJECT_DIR$" value="alexis" />
|
<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" />
|
||||||
|
@ -36,12 +47,8 @@
|
||||||
<component name="MarkdownSettingsMigration">
|
<component name="MarkdownSettingsMigration">
|
||||||
<option name="stateVersion" value="1" />
|
<option name="stateVersion" value="1" />
|
||||||
</component>
|
</component>
|
||||||
<component name="MavenImportPreferences">
|
<component name="ProblemsViewState">
|
||||||
<option name="importingSettings">
|
<option name="selectedTabId" value="CurrentFile" />
|
||||||
<MavenImportingSettings>
|
|
||||||
<option name="workspaceImportEnabled" value="true" />
|
|
||||||
</MavenImportingSettings>
|
|
||||||
</option>
|
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectId" id="2NFN0RGJNNJqiDmt34ixVwkIwEm" />
|
<component name="ProjectId" id="2NFN0RGJNNJqiDmt34ixVwkIwEm" />
|
||||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
|
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
|
||||||
|
@ -57,12 +64,17 @@
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||||
"codeWithMe.voiceChat.enabledByDefault": "false",
|
"codeWithMe.voiceChat.enabledByDefault": "false",
|
||||||
|
"git-widget-placeholder": "william",
|
||||||
"last_opened_file_path": "/home/william/Dev/Projects",
|
"last_opened_file_path": "/home/william/Dev/Projects",
|
||||||
"node.js.detected.package.eslint": "true",
|
"node.js.detected.package.eslint": "true",
|
||||||
"node.js.detected.package.tslint": "true",
|
"node.js.detected.package.tslint": "true",
|
||||||
"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",
|
||||||
|
"project.structure.last.edited": "Libraries",
|
||||||
|
"project.structure.proportion": "0.15",
|
||||||
|
"project.structure.side.proportion": "0.2",
|
||||||
|
"settings.editor.selected.configurable": "reference.projectsettings.compiler.javacompiler",
|
||||||
"vue.rearranger.settings.migration": "true"
|
"vue.rearranger.settings.migration": "true"
|
||||||
}
|
}
|
||||||
}]]></component>
|
}]]></component>
|
||||||
|
@ -72,7 +84,7 @@
|
||||||
<module name="Lab4" />
|
<module name="Lab4" />
|
||||||
<extension name="coverage">
|
<extension name="coverage">
|
||||||
<pattern>
|
<pattern>
|
||||||
<option name="PATTERN" value="laboratoire4.*" />
|
<option name="PATTERN" value="laboratoire4.pawns.*" />
|
||||||
<option name="ENABLED" value="true" />
|
<option name="ENABLED" value="true" />
|
||||||
</pattern>
|
</pattern>
|
||||||
</extension>
|
</extension>
|
||||||
|
@ -85,7 +97,7 @@
|
||||||
<module name="Lab4" />
|
<module name="Lab4" />
|
||||||
<extension name="coverage">
|
<extension name="coverage">
|
||||||
<pattern>
|
<pattern>
|
||||||
<option name="PATTERN" value="laboratoire4.*" />
|
<option name="PATTERN" value="laboratoire4.pawns.*" />
|
||||||
<option name="ENABLED" value="true" />
|
<option name="ENABLED" value="true" />
|
||||||
</pattern>
|
</pattern>
|
||||||
</extension>
|
</extension>
|
||||||
|
@ -98,7 +110,7 @@
|
||||||
<module name="Lab4" />
|
<module name="Lab4" />
|
||||||
<extension name="coverage">
|
<extension name="coverage">
|
||||||
<pattern>
|
<pattern>
|
||||||
<option name="PATTERN" value="laboratoire4.*" />
|
<option name="PATTERN" value="laboratoire4.pawns.*" />
|
||||||
<option name="ENABLED" value="true" />
|
<option name="ENABLED" value="true" />
|
||||||
</pattern>
|
</pattern>
|
||||||
</extension>
|
</extension>
|
||||||
|
@ -128,6 +140,19 @@
|
||||||
<workItem from="1679344371350" duration="4138000" />
|
<workItem from="1679344371350" duration="4138000" />
|
||||||
<workItem from="1679365557789" duration="21000" />
|
<workItem from="1679365557789" duration="21000" />
|
||||||
<workItem from="1679424430928" duration="11764000" />
|
<workItem from="1679424430928" duration="11764000" />
|
||||||
|
<workItem from="1679593788411" duration="10753000" />
|
||||||
|
<workItem from="1679672719638" duration="8340000" />
|
||||||
|
<workItem from="1679779362814" duration="5912000" />
|
||||||
|
<workItem from="1679787823160" duration="2189000" />
|
||||||
|
<workItem from="1680198283785" duration="8256000" />
|
||||||
|
<workItem from="1680580123067" duration="326000" />
|
||||||
|
<workItem from="1680750346503" duration="2118000" />
|
||||||
|
<workItem from="1680821970713" duration="10363000" />
|
||||||
|
<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>
|
||||||
|
@ -150,7 +175,49 @@
|
||||||
<option name="project" value="LOCAL" />
|
<option name="project" value="LOCAL" />
|
||||||
<updated>1679490100944</updated>
|
<updated>1679490100944</updated>
|
||||||
</task>
|
</task>
|
||||||
<option name="localTasksCounter" value="4" />
|
<task id="LOCAL-00004" summary="Fixes?">
|
||||||
|
<created>1679682974611</created>
|
||||||
|
<option name="number" value="00004" />
|
||||||
|
<option name="presentableId" value="LOCAL-00004" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1679682974611</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00005" summary="Fixes?">
|
||||||
|
<created>1679786894920</created>
|
||||||
|
<option name="number" value="00005" />
|
||||||
|
<option name="presentableId" value="LOCAL-00005" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1679786894920</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00006" summary="Plus d'heuristiques">
|
||||||
|
<created>1680580135038</created>
|
||||||
|
<option name="number" value="00006" />
|
||||||
|
<option name="presentableId" value="LOCAL-00006" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1680580135038</updated>
|
||||||
|
</task>
|
||||||
|
<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>
|
||||||
|
<task id="LOCAL-00008" summary="Gitignore">
|
||||||
|
<created>1681237323963</created>
|
||||||
|
<option name="number" value="00008" />
|
||||||
|
<option name="presentableId" value="LOCAL-00008" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1681237323963</updated>
|
||||||
|
</task>
|
||||||
|
<task id="LOCAL-00009" summary="Limite la longueur d'un coup sous les 5 secondes">
|
||||||
|
<created>1681238632769</created>
|
||||||
|
<option name="number" value="00009" />
|
||||||
|
<option name="presentableId" value="LOCAL-00009" />
|
||||||
|
<option name="project" value="LOCAL" />
|
||||||
|
<updated>1681238632769</updated>
|
||||||
|
</task>
|
||||||
|
<option name="localTasksCounter" value="10" />
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
<component name="TypeScriptGeneratedFilesManager">
|
||||||
|
@ -160,17 +227,11 @@
|
||||||
<MESSAGE value="MiniMax" />
|
<MESSAGE value="MiniMax" />
|
||||||
<MESSAGE value="Movement logic" />
|
<MESSAGE value="Movement logic" />
|
||||||
<MESSAGE value="Small fixes" />
|
<MESSAGE value="Small fixes" />
|
||||||
<option name="LAST_COMMIT_MESSAGE" value="Small fixes" />
|
<MESSAGE value="Fixes?" />
|
||||||
</component>
|
<MESSAGE value="Plus d'heuristiques" />
|
||||||
<component name="XDebuggerManager">
|
<MESSAGE value="Beaucoup de changements" />
|
||||||
<breakpoint-manager>
|
<MESSAGE value="Gitignore" />
|
||||||
<breakpoints>
|
<MESSAGE value="Limite la longueur d'un coup sous les 5 secondes" />
|
||||||
<line-breakpoint enabled="true" type="java-line">
|
<option name="LAST_COMMIT_MESSAGE" value="Limite la longueur d'un coup sous les 5 secondes" />
|
||||||
<url>file://$PROJECT_DIR$/src/main/java/laboratoire4/PusherBoard.java</url>
|
|
||||||
<line>60</line>
|
|
||||||
<option name="timeStamp" value="7" />
|
|
||||||
</line-breakpoint>
|
|
||||||
</breakpoints>
|
|
||||||
</breakpoint-manager>
|
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
19
pom.xml
19
pom.xml
|
@ -9,9 +9,24 @@
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>11</maven.compiler.source>
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
<maven.compiler.target>11</maven.compiler.target>
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jar-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>laboratoire4.Main</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
</project>
|
</project>
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
package laboratoire4;
|
||||||
|
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
|
||||||
|
public class Action<T extends IPawn> {
|
||||||
|
private final T pawn;
|
||||||
|
private final PawnMovement movement;
|
||||||
|
|
||||||
|
public Action(T pawn, PawnMovement movement) {
|
||||||
|
this.pawn = pawn;
|
||||||
|
this.movement = movement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getPawn() {
|
||||||
|
return pawn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PawnMovement getMovement() {
|
||||||
|
return movement;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
package laboratoire4;
|
package laboratoire4;
|
||||||
|
|
||||||
|
import laboratoire4.game.PusherGame;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -9,7 +11,7 @@ public class Client {
|
||||||
private final Socket socket;
|
private final Socket socket;
|
||||||
private final BufferedInputStream input;
|
private final BufferedInputStream input;
|
||||||
private final BufferedOutputStream output;
|
private final BufferedOutputStream output;
|
||||||
private PusherBoard board;
|
private PusherGame board;
|
||||||
|
|
||||||
public Client(String host, int port) throws IOException {
|
public Client(String host, int port) throws IOException {
|
||||||
socket = new Socket(host, port);
|
socket = new Socket(host, port);
|
||||||
|
@ -60,7 +62,7 @@ public class Client {
|
||||||
String s = new String(aBuffer).trim();
|
String s = new String(aBuffer).trim();
|
||||||
String[] boardValues = s.split(" ");
|
String[] boardValues = s.split(" ");
|
||||||
|
|
||||||
board = new PusherBoard(player, boardValues);
|
board = new PusherGame(player, boardValues);
|
||||||
|
|
||||||
return player == Player.RED;
|
return player == Player.RED;
|
||||||
}
|
}
|
||||||
|
@ -76,24 +78,27 @@ public class Client {
|
||||||
board.move(previousMove);
|
board.move(previousMove);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thread.sleep(1000);
|
Thread.sleep(200);
|
||||||
|
|
||||||
String nextMove = board.runNextMove();
|
String nextMove = board.runNextMove();
|
||||||
System.out.println("Prochain mouvement: " + nextMove);
|
System.out.printf("Prochain mouvement: %s\n\n", nextMove);
|
||||||
|
|
||||||
output.write(nextMove.getBytes(), 0, nextMove.length());
|
output.write(nextMove.getBytes(), 0, nextMove.length());
|
||||||
output.flush();
|
output.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleInvalidMove() throws InterruptedException {
|
private void handleInvalidMove() throws InterruptedException, IOException {
|
||||||
System.err.println("Mouvement invalide!");
|
System.err.println("Mouvement invalide!");
|
||||||
Thread.sleep(500);
|
Thread.sleep(500);
|
||||||
board.printBoard();
|
|
||||||
|
PusherGame.printBoard(board.getBoard());
|
||||||
|
|
||||||
|
// play();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopGame() throws IOException {
|
private void stopGame() throws IOException {
|
||||||
System.out.println("GG well played!");
|
System.out.println("GG well played!");
|
||||||
socket.close();
|
// socket.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
package laboratoire4;
|
package laboratoire4;
|
||||||
|
|
||||||
|
import laboratoire4.game.PusherGame;
|
||||||
|
import laboratoire4.pawns.Pawn;
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
public class GameTree {
|
public class GameTree {
|
||||||
private Node root;
|
private Node root;
|
||||||
|
|
||||||
public Node buildTree(PusherBoard board){
|
public Node buildTree(PusherGame board){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,9 +20,9 @@ public class GameTree {
|
||||||
static class Node {
|
static class Node {
|
||||||
private final Collection<Node> childs;
|
private final Collection<Node> childs;
|
||||||
private final Pawn pawn;
|
private final Pawn pawn;
|
||||||
private final Pawn.PawnMovement movement;
|
private final PawnMovement movement;
|
||||||
|
|
||||||
Node(Collection<Node> childs, Pawn pawn, Pawn.PawnMovement movement) {
|
Node(Collection<Node> childs, Pawn pawn, PawnMovement movement) {
|
||||||
this.childs = childs;
|
this.childs = childs;
|
||||||
this.pawn = pawn;
|
this.pawn = pawn;
|
||||||
this.movement = movement;
|
this.movement = movement;
|
||||||
|
@ -32,7 +36,7 @@ public class GameTree {
|
||||||
return pawn;
|
return pawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Pawn.PawnMovement getMovement() {
|
public PawnMovement getMovement() {
|
||||||
return movement;
|
return movement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package laboratoire4;
|
||||||
|
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
|
||||||
|
public interface IPawn {
|
||||||
|
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);
|
||||||
|
void move(PawnMovement movement);
|
||||||
|
boolean isPusher();
|
||||||
|
int getDirection();
|
||||||
|
Player getPlayer();
|
||||||
|
int getRow();
|
||||||
|
int getCol();
|
||||||
|
void setRow(int row);
|
||||||
|
void setCol(int col);
|
||||||
|
}
|
|
@ -1,9 +1,27 @@
|
||||||
package laboratoire4;
|
package laboratoire4;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.util.Scanner;
|
||||||
|
|
||||||
public class Main {
|
public class Main {
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) {
|
||||||
|
Scanner scanner = new Scanner(System.in);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
new Client("localhost", 8888).listen();
|
new Client("localhost", 8888).listen();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.print("Recommencer? (Y/n) ");
|
||||||
|
|
||||||
|
if (scanner.hasNextLine()) {
|
||||||
|
String nextLine = scanner.nextLine();
|
||||||
|
|
||||||
|
if (nextLine.equals("n")) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,147 +0,0 @@
|
||||||
package laboratoire4;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
public class MiniMax {
|
|
||||||
private static final int MAX_DEPTH = 2;
|
|
||||||
private static Random random = new Random();
|
|
||||||
|
|
||||||
public static MiniMaxResult miniMax(PusherBoard board) {
|
|
||||||
return miniMax(board, true, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MiniMaxResult miniMax(PusherBoard board, boolean max, int depth, int alphaBeta) {
|
|
||||||
int limScore = max ? Integer.MIN_VALUE : Integer.MAX_VALUE;
|
|
||||||
List<Pawn> pawns = max ?
|
|
||||||
board.getMaxPawns() :
|
|
||||||
board.getMinPawns();
|
|
||||||
// Collections.shuffle(pawns);
|
|
||||||
|
|
||||||
List<MiniMaxResult> results = new ArrayList<>();
|
|
||||||
|
|
||||||
for (Pawn pawn : pawns) {
|
|
||||||
int originalRow = pawn.getRow();
|
|
||||||
int originalCol = pawn.getCol();
|
|
||||||
|
|
||||||
for (Pawn.PawnMovement movement : Pawn.PawnMovement.values()) {
|
|
||||||
if (pawn.isMoveValid(board, movement)) {
|
|
||||||
pawn.move(movement);
|
|
||||||
|
|
||||||
int nextAlphaBeta = max ? Math.max(limScore, alphaBeta) : Math.min(limScore, alphaBeta);
|
|
||||||
|
|
||||||
int score = evaluate(pawn, board, max);
|
|
||||||
if (depth < MAX_DEPTH) {
|
|
||||||
score = miniMax(board, !max, depth + 1, nextAlphaBeta).getScore();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((max && score > limScore) ||
|
|
||||||
(!max && score < limScore)) {
|
|
||||||
limScore = score;
|
|
||||||
}
|
|
||||||
|
|
||||||
MiniMaxResult result = new MiniMaxResult(limScore, pawn, movement);
|
|
||||||
|
|
||||||
//elagage alphaBeta
|
|
||||||
// if ((max && limScore > alphaBeta) ||
|
|
||||||
// (!max && limScore < alphaBeta)) {
|
|
||||||
// pawn.setRow(originalRow);
|
|
||||||
// pawn.setCol(originalCol);
|
|
||||||
//
|
|
||||||
// return result;
|
|
||||||
// }
|
|
||||||
|
|
||||||
results.add(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
pawn.setRow(originalRow);
|
|
||||||
pawn.setCol(originalCol);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Choisir aléatoirement
|
|
||||||
int index = random.nextInt(results.size());
|
|
||||||
return results.get(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int evaluate(Pawn pawn, PusherBoard board, boolean max) {
|
|
||||||
int score = didWin(pawn, max) + didCapture(pawn, board, max) + isPushed(pawn);
|
|
||||||
|
|
||||||
int homeRow = pawn.getPlayer() == Player.RED ? 0 : 7;
|
|
||||||
if (pawn.getRow() != homeRow) {
|
|
||||||
score += 50;
|
|
||||||
}
|
|
||||||
|
|
||||||
int direction = max ? 1 : -1;
|
|
||||||
return score * direction;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int isPushed(Pawn pawn) {
|
|
||||||
if (pawn instanceof Pushed) {
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int didWin(Pawn pawn, boolean max) {
|
|
||||||
int goal = pawn.getPlayer() == Player.RED ? 7 : 0;
|
|
||||||
|
|
||||||
if (pawn.getRow() == goal) {
|
|
||||||
return max ? 1000 : 100000;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int didCapture(Pawn pawn, PusherBoard board, boolean max) {
|
|
||||||
Pawn capturedPawn = board.getBoard()[pawn.getRow()][pawn.getCol()];
|
|
||||||
|
|
||||||
if (capturedPawn != null) {
|
|
||||||
if (capturedPawn.getPlayer() != pawn.getPlayer()) {
|
|
||||||
if (max) {
|
|
||||||
return capturedPawn instanceof Pusher ? 100 : 50;
|
|
||||||
} else {
|
|
||||||
return capturedPawn instanceof Pusher ? 10000 : 5000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static class MiniMaxResult {
|
|
||||||
private final int score;
|
|
||||||
private final Pawn pawn;
|
|
||||||
private final Pawn.PawnMovement movement;
|
|
||||||
|
|
||||||
public MiniMaxResult(int score, Pawn pawn, Pawn.PawnMovement movement) {
|
|
||||||
this.score = score;
|
|
||||||
this.pawn = pawn;
|
|
||||||
this.movement = movement;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getScore() {
|
|
||||||
return score;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Pawn getPawn() {
|
|
||||||
return pawn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Pawn.PawnMovement getMovement() {
|
|
||||||
return movement;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "MiniMaxResult{" +
|
|
||||||
"score=" + score +
|
|
||||||
", pawn=" + pawn +
|
|
||||||
", movement=" + movement +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
package laboratoire4;
|
|
||||||
|
|
||||||
public abstract class Pawn {
|
|
||||||
protected final Player player;
|
|
||||||
protected int row;
|
|
||||||
protected int col;
|
|
||||||
protected int direction;
|
|
||||||
|
|
||||||
public Pawn(Player player, int row, int col) {
|
|
||||||
this.player = player;
|
|
||||||
this.row = row;
|
|
||||||
this.col = col;
|
|
||||||
this.direction = player == Player.RED ? 1 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void move(PawnMovement movement) {
|
|
||||||
setRow(row + direction);
|
|
||||||
setCol(col + movement.move);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPosition() {
|
|
||||||
char colStr = (char)(col + 65);
|
|
||||||
return String.format("%s%d", colStr, row + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Player getPlayer() {
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCol() {
|
|
||||||
return col;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRow() {
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCol(int col) {
|
|
||||||
this.col = col;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRow(int row) {
|
|
||||||
this.row = row;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDirection() {
|
|
||||||
return direction;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isMoveValid(PusherBoard game, PawnMovement movement) {
|
|
||||||
Pawn[][] board = game.getBoard();
|
|
||||||
|
|
||||||
int nextRow = row + getDirection();
|
|
||||||
if (nextRow < 0 || nextRow >= board.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int nextCol = col + movement.move;
|
|
||||||
if (nextCol < 0 || nextCol >= board.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isMoveValid(board, movement);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract boolean isMoveValid(Pawn[][] board, PawnMovement movement);
|
|
||||||
|
|
||||||
enum PawnMovement {
|
|
||||||
STRAIGHT(0),
|
|
||||||
LEFT_DIAGONAL(-1),
|
|
||||||
RIGHT_DIAGONAL(1);
|
|
||||||
|
|
||||||
private final int move;
|
|
||||||
|
|
||||||
PawnMovement(int move) {
|
|
||||||
this.move = move;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMove() {
|
|
||||||
return move;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PawnMovement from(int move) {
|
|
||||||
if (move == 0) {
|
|
||||||
return STRAIGHT;
|
|
||||||
}
|
|
||||||
if (move == 1) {
|
|
||||||
return RIGHT_DIAGONAL;
|
|
||||||
}
|
|
||||||
return LEFT_DIAGONAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,28 @@
|
||||||
package laboratoire4;
|
package laboratoire4;
|
||||||
|
|
||||||
public enum Player {
|
public enum Player {
|
||||||
BLACK,
|
BLACK(-1, 0, 7),
|
||||||
RED
|
RED(1, 7, 0);
|
||||||
|
|
||||||
|
private final int direction;
|
||||||
|
private final int goal;
|
||||||
|
private final int home;
|
||||||
|
|
||||||
|
Player(int direction, int goal, int home) {
|
||||||
|
this.direction = direction;
|
||||||
|
this.goal = goal;
|
||||||
|
this.home = home;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDirection() {
|
||||||
|
return direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGoal() {
|
||||||
|
return goal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHome() {
|
||||||
|
return home;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
package laboratoire4;
|
|
||||||
|
|
||||||
public class Pushed extends Pawn {
|
|
||||||
public Pushed(Player player, int row, int col) {
|
|
||||||
super(player, row, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isMoveValid(Pawn[][] board, PawnMovement movement) {
|
|
||||||
Pawn pusher = null;
|
|
||||||
Pawn to = board[row + direction][col + movement.getMove()];
|
|
||||||
|
|
||||||
if (col > 0 && movement == PawnMovement.RIGHT_DIAGONAL) {
|
|
||||||
pusher = board[row - direction][col - 1];
|
|
||||||
} else if (col < board.length - 1 && movement == PawnMovement.LEFT_DIAGONAL) {
|
|
||||||
pusher = board[row - direction][col + 1];
|
|
||||||
} else if (movement == PawnMovement.STRAIGHT) {
|
|
||||||
pusher = board[row - direction][col];
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean pusherValid = pusher instanceof Pusher && pusher.player == player;
|
|
||||||
boolean destinationValid = to == null || (movement != PawnMovement.STRAIGHT && to.player != this.player);
|
|
||||||
return pusherValid && destinationValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Pushed{" +
|
|
||||||
player +
|
|
||||||
", " + col +
|
|
||||||
", " + row +
|
|
||||||
"} ";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
package laboratoire4;
|
|
||||||
|
|
||||||
public class Pusher extends Pawn {
|
|
||||||
public Pusher(Player player, int row, int col) {
|
|
||||||
super(player, row, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isMoveValid(Pawn[][] board, PawnMovement movement) {
|
|
||||||
Pawn to = board[row + direction][col + movement.getMove()];
|
|
||||||
|
|
||||||
if (to == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return to.player != this.player && movement != PawnMovement.STRAIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "Pusher{" +
|
|
||||||
player +
|
|
||||||
", " + col +
|
|
||||||
", " + row +
|
|
||||||
"} ";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,144 +0,0 @@
|
||||||
package laboratoire4;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class PusherBoard {
|
|
||||||
private final Player player;
|
|
||||||
private Pawn[][] board;
|
|
||||||
|
|
||||||
private final List<Pawn> maxPawns = new ArrayList<>();
|
|
||||||
private final List<Pawn> minPawns = new ArrayList<>();
|
|
||||||
|
|
||||||
public PusherBoard(Player player, String[] boardValues) {
|
|
||||||
this.player = player;
|
|
||||||
|
|
||||||
newGame(boardValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void newGame(String[] boardValues) {
|
|
||||||
this.board = new Pawn[8][8];
|
|
||||||
|
|
||||||
int col = 0, row = 0;
|
|
||||||
for (String boardValue : boardValues) {
|
|
||||||
int v = Integer.parseInt(boardValue);
|
|
||||||
if (v != 0) {
|
|
||||||
Player pawnPlayer = (v == 1 || v == 2) ? Player.RED : Player.BLACK;
|
|
||||||
Pawn pawn;
|
|
||||||
if (v % 2 == 0) { // 2 et 4 sont les pushers
|
|
||||||
pawn = new Pusher(pawnPlayer, row, col);
|
|
||||||
} else {
|
|
||||||
pawn = new Pushed(pawnPlayer, row, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pawnPlayer == player) {
|
|
||||||
maxPawns.add(pawn);
|
|
||||||
} else {
|
|
||||||
minPawns.add(pawn);
|
|
||||||
}
|
|
||||||
|
|
||||||
board[row][col] = pawn;
|
|
||||||
}
|
|
||||||
|
|
||||||
col++;
|
|
||||||
if (col == board.length) {
|
|
||||||
col = 0;
|
|
||||||
row++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String runNextMove() {
|
|
||||||
MiniMax.MiniMaxResult result = MiniMax.miniMax(this);
|
|
||||||
Pawn pawn = result.getPawn();
|
|
||||||
String initialPosition = pawn.getPosition();
|
|
||||||
|
|
||||||
System.out.println(result.getScore());
|
|
||||||
|
|
||||||
move(pawn, result.getMovement());
|
|
||||||
|
|
||||||
|
|
||||||
return initialPosition + "-" + pawn.getPosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void move(String move) {
|
|
||||||
//FORMAT ex : D2-D3
|
|
||||||
String[] split = move.trim().split(" - ");
|
|
||||||
move(split[0], split[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void move(Pawn pawn, Pawn.PawnMovement movement) {
|
|
||||||
move(pawn.getCol(), pawn.getRow(), pawn.getCol() + movement.getMove(), pawn.getRow() + pawn.getDirection());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void move(String from, String to) {
|
|
||||||
//FORMAT ex : from {D2}, to {D3}
|
|
||||||
int from_col = (int) from.charAt(0) - 65;
|
|
||||||
int from_row = Integer.parseInt(String.valueOf(from.charAt(1))) - 1;
|
|
||||||
int to_col = (int) to.charAt(0) - 65;
|
|
||||||
int to_row = Integer.parseInt(String.valueOf(to.charAt(1))) - 1;
|
|
||||||
|
|
||||||
move(from_col, from_row, to_col, to_row);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void move(int from_col, int from_row, int to_col, int to_row) {
|
|
||||||
if (!isValid(from_col, from_row, to_col)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pawn pawn = board[from_row][from_col];
|
|
||||||
Pawn destPawn = board[to_row][to_col];
|
|
||||||
|
|
||||||
if (destPawn != null) {
|
|
||||||
if (destPawn.getPlayer() == player) {
|
|
||||||
maxPawns.remove(destPawn);
|
|
||||||
} else {
|
|
||||||
minPawns.remove(destPawn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
board[from_row][from_col] = null;
|
|
||||||
board[to_row][to_col] = pawn;
|
|
||||||
|
|
||||||
pawn.setRow(to_row);
|
|
||||||
pawn.setCol(to_col);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private boolean isValid(int from_col, int from_row, int to_col) {
|
|
||||||
Pawn pawn = getBoard()[from_row][from_col];
|
|
||||||
Pawn.PawnMovement move = Pawn.PawnMovement.from(to_col - from_col);
|
|
||||||
|
|
||||||
if (pawn == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pawn.isMoveValid(this, move);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Pawn[][] getBoard() {
|
|
||||||
return board;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Pawn> getMaxPawns() {
|
|
||||||
return maxPawns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Pawn> getMinPawns() {
|
|
||||||
return minPawns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void printBoard() {
|
|
||||||
for (int i = 7; i >= 0; i--) {
|
|
||||||
for (int j = 0; j < this.board.length; j++) {
|
|
||||||
if (this.board[i][j] != null) {
|
|
||||||
System.out.print(this.board[i][j] + " | ");
|
|
||||||
} else {
|
|
||||||
System.out.print(" | ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
System.out.println();
|
|
||||||
System.out.println("----------------------------------------------------------------------------------------");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package laboratoire4.game;
|
||||||
|
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.Player;
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
|
||||||
|
public interface Game {
|
||||||
|
void move(IPawn pawn, PawnMovement movement);
|
||||||
|
|
||||||
|
IPawn[][] getBoard();
|
||||||
|
|
||||||
|
Player getPlayer();
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package laboratoire4.game;
|
||||||
|
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.Player;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class GameUtils {
|
||||||
|
public static <T extends IPawn> Stream<T> getPawnsAsStream(T[][] board) {
|
||||||
|
return Arrays.stream(board)
|
||||||
|
.flatMap(Arrays::stream)
|
||||||
|
.filter(Objects::nonNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends IPawn> Collection<IPawn> getPawns(T[][] board) {
|
||||||
|
return getPawnsAsStream(board).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends IPawn> Stream<T> getMaxPawnsAsStream(T[][] board, Player player) {
|
||||||
|
return getPawnsAsStream(board).filter(p -> p.getPlayer() == player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends IPawn> Collection<T> getMaxPawns(T[][] board, Player player) {
|
||||||
|
return getMaxPawnsAsStream(board, player).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends IPawn> Stream<T> getMinPawnsAsStream(T[][] board, Player player) {
|
||||||
|
return getPawnsAsStream(board).filter(p -> p.getPlayer() != player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends IPawn> Collection<T> getMinPawns(T[][] board, Player player) {
|
||||||
|
return getMinPawnsAsStream(board, player).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
package laboratoire4.game;
|
||||||
|
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.Player;
|
||||||
|
import laboratoire4.pawns.Pawn;
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
import laboratoire4.pawns.Pushed;
|
||||||
|
import laboratoire4.pawns.Pusher;
|
||||||
|
import laboratoire4.strategies.EvaluationResult;
|
||||||
|
import laboratoire4.strategies.MasterStrategy;
|
||||||
|
|
||||||
|
public class PusherGame implements Game {
|
||||||
|
private final Player player;
|
||||||
|
private Pawn[][] board;
|
||||||
|
|
||||||
|
public PusherGame(Player player, String[] boardValues) {
|
||||||
|
this.player = player;
|
||||||
|
|
||||||
|
newGame(boardValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void newGame(String[] boardValues) {
|
||||||
|
this.board = new Pawn[8][8];
|
||||||
|
|
||||||
|
int col = 0, row = 0;
|
||||||
|
for (String boardValue : boardValues) {
|
||||||
|
int v = Integer.parseInt(boardValue);
|
||||||
|
if (v != 0) {
|
||||||
|
Player pawnPlayer = (v == 1 || v == 2) ? Player.RED : Player.BLACK;
|
||||||
|
Pawn pawn;
|
||||||
|
if (v % 2 == 0) { // 2 et 4 sont les pushers
|
||||||
|
pawn = new Pusher(pawnPlayer, row, col);
|
||||||
|
} else {
|
||||||
|
pawn = new Pushed(pawnPlayer, row, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
board[row][col] = pawn;
|
||||||
|
}
|
||||||
|
|
||||||
|
col++;
|
||||||
|
if (col == board.length) {
|
||||||
|
col = 0;
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String runNextMove() {
|
||||||
|
EvaluationResult result = MasterStrategy.getInstance(this).getNextMove();
|
||||||
|
if (result == null) {
|
||||||
|
// Ce n'est pas censé arriver, on réessaie
|
||||||
|
System.err.println("Aucune résultat n'a été retourné!");
|
||||||
|
result = MasterStrategy.getInstance(this).getNextMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
Pawn pawn = board[result.getRow()][result.getCol()];
|
||||||
|
|
||||||
|
String initialPosition = pawn.getPosition();
|
||||||
|
move(pawn, result.getMovement());
|
||||||
|
String nextPosition = pawn.getPosition();
|
||||||
|
|
||||||
|
return initialPosition + "-" + nextPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void move(String move) {
|
||||||
|
String[] split = move.trim().split(" - ");
|
||||||
|
String from = split[0];
|
||||||
|
String to = split[1];
|
||||||
|
|
||||||
|
int fromCol = (int) from.charAt(0) - 65;
|
||||||
|
int fromRow = Integer.parseInt(String.valueOf(from.charAt(1))) - 1;
|
||||||
|
int toCol = (int) to.charAt(0) - 65;
|
||||||
|
|
||||||
|
PawnMovement movement = PawnMovement.from(toCol - fromCol);
|
||||||
|
move(fromRow, fromCol, movement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void move(int row, int col, PawnMovement movement) {
|
||||||
|
Pawn pawn = board[row][col];
|
||||||
|
if (pawn == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
move(pawn, movement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void move(IPawn pawn, PawnMovement movement) {
|
||||||
|
int toRow = pawn.getRow() + pawn.getDirection();
|
||||||
|
int toCol = pawn.getCol() + movement.getMove();
|
||||||
|
|
||||||
|
board[pawn.getRow()][pawn.getCol()] = null;
|
||||||
|
board[toRow][toCol] = (Pawn) pawn;
|
||||||
|
pawn.move(movement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pawn[][] getBoard() {
|
||||||
|
return board;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void printBoard(Pawn[][] board) {
|
||||||
|
for (int i = 7; i >= 0; i--) {
|
||||||
|
for (int j = 0; j < board.length; j++) {
|
||||||
|
if (board[i][j] != null) {
|
||||||
|
System.out.print(board[i][j] + " | ");
|
||||||
|
} else {
|
||||||
|
System.out.print(" | ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("----------------------------------------------------------------------------------------");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
package laboratoire4.game;
|
||||||
|
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.Player;
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
import laboratoire4.pawns.SimulatedPawn;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Stack;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
public class SimulatedGame implements Game {
|
||||||
|
private final SimulatedPawn[][] board;
|
||||||
|
private final Player player;
|
||||||
|
|
||||||
|
private final Stack<SimulatedPawn> removedPawns = new Stack<>();
|
||||||
|
private final Stack<SimulatedPawn> previousMovedPawns = new Stack<>();
|
||||||
|
|
||||||
|
public SimulatedGame(IPawn[][] board, Player player) {
|
||||||
|
this.board = asMovingPawns(board);
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void move(IPawn pawn, PawnMovement movement) {
|
||||||
|
int toRow = pawn.getRow() + pawn.getDirection();
|
||||||
|
int toCol = pawn.getCol() + movement.getMove();
|
||||||
|
SimulatedPawn capturedPawn = board[toRow][toCol];
|
||||||
|
|
||||||
|
previousMovedPawns.push((SimulatedPawn) pawn);
|
||||||
|
removedPawns.push(capturedPawn);
|
||||||
|
|
||||||
|
board[pawn.getRow()][pawn.getCol()] = null;
|
||||||
|
board[toRow][toCol] = (SimulatedPawn) pawn;
|
||||||
|
pawn.move(movement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void revertMove() {
|
||||||
|
SimulatedPawn pawn = previousMovedPawns.pop();
|
||||||
|
SimulatedPawn capturedPawn = removedPawns.pop();
|
||||||
|
|
||||||
|
board[pawn.getRow()][pawn.getCol()] = capturedPawn;
|
||||||
|
|
||||||
|
pawn.revertMove();
|
||||||
|
board[pawn.getRow()][pawn.getCol()] = pawn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimulatedPawn getNextPawn(IPawn 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 SimulatedPawn[][] getBoard() {
|
||||||
|
return board;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasCaptured() {
|
||||||
|
return removedPawns.peek() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Collection<SimulatedPawn> getPawns(Predicate<SimulatedPawn> predicate) {
|
||||||
|
List<SimulatedPawn> pawns = new ArrayList<>();
|
||||||
|
for (SimulatedPawn[] row : board) {
|
||||||
|
for (SimulatedPawn pawn : row) {
|
||||||
|
if (pawn != null && predicate.test(pawn)) {
|
||||||
|
pawns.add(pawn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pawns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SimulatedPawn[][] asMovingPawns(IPawn[][] board) {
|
||||||
|
SimulatedPawn[][] to = new SimulatedPawn[board.length][board.length];
|
||||||
|
for (int row = 0; row < board.length; row++) {
|
||||||
|
for (int col = 0; col < board.length; col++) {
|
||||||
|
if (board[row][col] == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SimulatedPawn pawn = SimulatedPawn.from(board[row][col]);
|
||||||
|
to[row][col] = pawn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
package laboratoire4.pawns;
|
||||||
|
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.Player;
|
||||||
|
|
||||||
|
public abstract class Pawn implements IPawn {
|
||||||
|
protected final Player player;
|
||||||
|
protected int row;
|
||||||
|
protected int col;
|
||||||
|
|
||||||
|
public Pawn(Player player, int row, int col) {
|
||||||
|
this.player = player;
|
||||||
|
this.row = row;
|
||||||
|
this.col = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void move(PawnMovement movement) {
|
||||||
|
setRow(row + player.getDirection());
|
||||||
|
setCol(col + movement.getMove());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPosition() {
|
||||||
|
char colStr = (char) (col + 65);
|
||||||
|
return String.format("%s%d", colStr, row + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCol() {
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRow() {
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCol(int col) {
|
||||||
|
this.col = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRow(int row) {
|
||||||
|
this.row = row;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDirection() {
|
||||||
|
return player.getDirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMoveValid(IPawn[][] board, PawnMovement movement) {
|
||||||
|
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
|
||||||
|
public boolean isMoveValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol, boolean ignorePlayers) {
|
||||||
|
int nextRow = fromRow + getDirection();
|
||||||
|
if (nextRow < 0 || nextRow >= board.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nextCol = fromCol + movement.getMove();
|
||||||
|
if (nextCol < 0 || nextCol >= board.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isMoveReallyValid(board, movement, fromRow, fromCol, ignorePlayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol, boolean ignorePlayers);
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package laboratoire4.pawns;
|
||||||
|
|
||||||
|
public enum PawnMovement {
|
||||||
|
STRAIGHT(0),
|
||||||
|
LEFT_DIAGONAL(-1),
|
||||||
|
RIGHT_DIAGONAL(1);
|
||||||
|
|
||||||
|
private final int move;
|
||||||
|
|
||||||
|
PawnMovement(int move) {
|
||||||
|
this.move = move;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMove() {
|
||||||
|
return move;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PawnMovement getOpposite() {
|
||||||
|
return from(move * -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PawnMovement from(int move) {
|
||||||
|
if (move == 0) {
|
||||||
|
return STRAIGHT;
|
||||||
|
}
|
||||||
|
if (move == 1) {
|
||||||
|
return RIGHT_DIAGONAL;
|
||||||
|
}
|
||||||
|
return LEFT_DIAGONAL;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,185 @@
|
||||||
|
package laboratoire4.pawns;
|
||||||
|
|
||||||
|
import laboratoire4.Action;
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.Player;
|
||||||
|
import laboratoire4.game.Game;
|
||||||
|
import laboratoire4.game.GameUtils;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Queue;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class PawnUtils {
|
||||||
|
public static int distanceFromGoal(IPawn pawn) {
|
||||||
|
return Math.abs(pawn.getPlayer().getGoal() - pawn.getRow());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int distanceFromHome(IPawn pawn) {
|
||||||
|
return Math.abs(pawn.getRow() - pawn.getPlayer().getHome());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean areSamePlayers(IPawn a, IPawn b) {
|
||||||
|
return a != null && b != null && a.getPlayer() == b.getPlayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean hasEasyWinPath(IPawn[][] board, IPawn initialPawn) {
|
||||||
|
Queue<Point> positionsToVisit = new ArrayDeque<>();
|
||||||
|
positionsToVisit.add(new Point(initialPawn.getRow(), initialPawn.getCol()));
|
||||||
|
|
||||||
|
while (!positionsToVisit.isEmpty()) {
|
||||||
|
Point pos = positionsToVisit.poll();
|
||||||
|
|
||||||
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
|
if (!initialPawn.isMoveValid(board, movement, pos.x, pos.y, false)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nextRow = pos.x + initialPawn.getDirection();
|
||||||
|
int nextCol = pos.y + movement.getMove();
|
||||||
|
|
||||||
|
IPawn pawn = board[nextRow][nextCol];
|
||||||
|
if (pawn != null && pawn.getPlayer() != initialPawn.getPlayer() && pawn.isMoveValid(board, movement.getOpposite())) {
|
||||||
|
// On peut se faire capturer en allant là !
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextRow == initialPawn.getPlayer().getGoal()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
positionsToVisit.add(new Point(nextRow, nextCol));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends IPawn> Collection<Action<T>> getActions(Game game, boolean max, boolean excludeDefense, boolean excludeDanger) {
|
||||||
|
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)) {
|
||||||
|
if (excludeDanger && PawnUtils.canBeCaptured(game, pawn.getRow() + pawn.getDirection(), pawn.getCol() + movement.getMove(), pawn.getPlayer())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
actions.add(new Action<>(pawn, movement));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actions.isEmpty()) {
|
||||||
|
if (excludeDanger && excludeDefense) {
|
||||||
|
return getActions(game, max, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (excludeDefense) {
|
||||||
|
return getActions(game, max, false, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.shuffle(actions);
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package laboratoire4.pawns;
|
||||||
|
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.Player;
|
||||||
|
|
||||||
|
public class Pushed extends Pawn {
|
||||||
|
public Pushed(Player player, int row, int col) {
|
||||||
|
super(player, row, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPusher() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol, boolean ignorePlayers) {
|
||||||
|
int direction = getDirection();
|
||||||
|
IPawn pusher = null;
|
||||||
|
IPawn to = board[fromRow + direction][fromCol + movement.getMove()];
|
||||||
|
|
||||||
|
if (fromCol > 0 && movement == PawnMovement.RIGHT_DIAGONAL) {
|
||||||
|
pusher = board[fromRow - direction][fromCol - movement.getMove()];
|
||||||
|
} else if (fromCol < board.length - 1 && movement == PawnMovement.LEFT_DIAGONAL) {
|
||||||
|
pusher = board[fromRow - direction][fromCol - movement.getMove()];
|
||||||
|
} else if (movement == PawnMovement.STRAIGHT) {
|
||||||
|
pusher = board[fromRow - direction][fromCol];
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean pusherValid = pusher != null && pusher.isPusher() && pusher.getPlayer() == player;
|
||||||
|
boolean destinationValid = to == null || (movement != PawnMovement.STRAIGHT && (ignorePlayers || to.getPlayer() != this.player));
|
||||||
|
return pusherValid && destinationValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("Pushed{%s, %s}", player, getPosition());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package laboratoire4.pawns;
|
||||||
|
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.Player;
|
||||||
|
|
||||||
|
public class Pusher extends Pawn {
|
||||||
|
public Pusher(Player player, int row, int col) {
|
||||||
|
super(player, row, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPusher() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement, int fromRow, int fromCol, boolean ignorePlayers) {
|
||||||
|
IPawn to = board[fromRow + getDirection()][fromCol + movement.getMove()];
|
||||||
|
|
||||||
|
if (to == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ignorePlayers && to.getPlayer() == player) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return movement != PawnMovement.STRAIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("Pusher{%s, %s}", player, getPosition());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package laboratoire4.pawns;
|
||||||
|
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
|
||||||
|
public interface SimulatedPawn extends IPawn {
|
||||||
|
void revertMove();
|
||||||
|
int getMoveCount();
|
||||||
|
int getOriginalRow();
|
||||||
|
int getOriginalCol();
|
||||||
|
|
||||||
|
static SimulatedPawn from(IPawn pawn) {
|
||||||
|
if (pawn instanceof Pusher) {
|
||||||
|
return new SimulatedPusher(pawn.getPlayer(), pawn.getRow(), pawn.getCol());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SimulatedPushed(pawn.getPlayer(), pawn.getRow(), pawn.getCol());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package laboratoire4.pawns;
|
||||||
|
|
||||||
|
import laboratoire4.Player;
|
||||||
|
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
public class SimulatedPushed extends Pushed implements SimulatedPawn {
|
||||||
|
private final int originalRow;
|
||||||
|
private final int originalCol;
|
||||||
|
private final Stack<PawnMovement> previousMoves = new Stack<>();
|
||||||
|
private int moveCount = 0;
|
||||||
|
|
||||||
|
public SimulatedPushed(Player player, int row, int col) {
|
||||||
|
super(player, row, col);
|
||||||
|
|
||||||
|
originalRow = row;
|
||||||
|
originalCol = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void move(PawnMovement movement) {
|
||||||
|
super.move(movement);
|
||||||
|
previousMoves.push(movement);
|
||||||
|
moveCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void revertMove() {
|
||||||
|
PawnMovement move = previousMoves.pop();
|
||||||
|
setRow(row - getDirection());
|
||||||
|
setCol(col - move.getMove());
|
||||||
|
moveCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOriginalRow() {
|
||||||
|
return originalRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOriginalCol() {
|
||||||
|
return originalCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMoveCount() {
|
||||||
|
return moveCount;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package laboratoire4.pawns;
|
||||||
|
|
||||||
|
import laboratoire4.Player;
|
||||||
|
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
public class SimulatedPusher extends Pusher implements SimulatedPawn {
|
||||||
|
private final int originalRow;
|
||||||
|
private final int originalCol;
|
||||||
|
private final Stack<PawnMovement> previousMoves = new Stack<>();
|
||||||
|
private int moveCount = 0;
|
||||||
|
|
||||||
|
public SimulatedPusher(Player player, int row, int col) {
|
||||||
|
super(player, row, col);
|
||||||
|
|
||||||
|
originalRow = row;
|
||||||
|
originalCol = col;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void move(PawnMovement movement) {
|
||||||
|
previousMoves.push(movement);
|
||||||
|
super.move(movement);
|
||||||
|
moveCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void revertMove() {
|
||||||
|
PawnMovement move = previousMoves.pop();
|
||||||
|
setRow(row - getDirection());
|
||||||
|
setCol(col - move.getMove());
|
||||||
|
moveCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOriginalRow() {
|
||||||
|
return originalRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOriginalCol() {
|
||||||
|
return originalCol;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMoveCount() {
|
||||||
|
return moveCount;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,136 @@
|
||||||
|
package laboratoire4.strategies;
|
||||||
|
|
||||||
|
import laboratoire4.Action;
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.game.Game;
|
||||||
|
import laboratoire4.game.GameUtils;
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
import laboratoire4.pawns.PawnUtils;
|
||||||
|
import laboratoire4.pawns.SimulatedPawn;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class AttackStrategy extends MiniMaxStrategy {
|
||||||
|
private static final int ATTACK_DISTANCE_FROM_GOAL = 4;
|
||||||
|
|
||||||
|
private long originalMinPushedCount;
|
||||||
|
private long originalMinPusherCount;
|
||||||
|
private long originalMaxPusherCount;
|
||||||
|
|
||||||
|
protected AttackStrategy(Game game) {
|
||||||
|
super(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EvaluationResult getNextMove() {
|
||||||
|
originalMinPushedCount = GameUtils.getMinPawnsAsStream(game.getBoard(), game.getPlayer()).filter(p -> !p.isPusher()).count();
|
||||||
|
originalMinPusherCount = GameUtils.getMinPawnsAsStream(game.getBoard(), game.getPlayer()).filter(IPawn::isPusher).count();
|
||||||
|
originalMaxPusherCount = GameUtils.getMaxPawnsAsStream(game.getBoard(), game.getPlayer())
|
||||||
|
.filter(IPawn::isPusher)
|
||||||
|
.count();
|
||||||
|
|
||||||
|
return super.getNextMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int evaluateSimulation() {
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
if (getMinPawns().stream().anyMatch(p -> p.getRow() == p.getPlayer().getGoal())) {
|
||||||
|
return Integer.MIN_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// region Pions max perdus
|
||||||
|
Collection<SimulatedPawn> maxPawns = getMaxPawns();
|
||||||
|
long pusherCount = maxPawns.stream().filter(IPawn::isPusher).count();
|
||||||
|
score -= Math.pow((originalMaxPusherCount - pusherCount) * 10, 2);
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Pions min capturés
|
||||||
|
long minPusherCount = getMinPawns().stream().filter(IPawn::isPusher).count();
|
||||||
|
long minPushedCount = getMinPawns().stream().filter(p -> !p.isPusher()).count();
|
||||||
|
score += (originalMinPushedCount - minPushedCount) * 5;
|
||||||
|
score += (originalMinPusherCount - minPusherCount) * 10;
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
for (SimulatedPawn pawn : maxPawns) {
|
||||||
|
int distanceFromGoal = PawnUtils.distanceFromGoal(pawn);
|
||||||
|
if (distanceFromGoal <= ATTACK_DISTANCE_FROM_GOAL) {
|
||||||
|
score += ATTACK_DISTANCE_FROM_GOAL - distanceFromGoal + 1;
|
||||||
|
|
||||||
|
if (PawnUtils.hasEasyWinPath(game.getBoard(), pawn)) {
|
||||||
|
score += Integer.MAX_VALUE / distanceFromGoal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int row = pawn.getRow();
|
||||||
|
int col = pawn.getCol();
|
||||||
|
|
||||||
|
if (row > 0 && row < 7) {
|
||||||
|
IPawn facingPawn = game.getBoard()[row + pawn.getDirection()][col];
|
||||||
|
if (facingPawn != null && !PawnUtils.areSamePlayers(pawn, facingPawn)) {
|
||||||
|
// On bloque potentiellement un pion adverse, qui ne peut pas nous attaquer
|
||||||
|
score += 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (col > 0) {
|
||||||
|
// IPawn leftPawn = game.getBoard()[row][col - 1];
|
||||||
|
// if (leftPawn != null && !PawnUtils.areSamePlayers(pawn, leftPawn)) {
|
||||||
|
// score += 5;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// if (col < 7) {
|
||||||
|
// IPawn rightPawn = game.getBoard()[row][col + 1];
|
||||||
|
// if (rightPawn != null && !PawnUtils.areSamePlayers(pawn, rightPawn)) {
|
||||||
|
// score += 5;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWeight() {
|
||||||
|
Collection<IPawn> maxPawns = GameUtils.getMaxPawns(game.getBoard(), game.getPlayer());
|
||||||
|
|
||||||
|
int maxWeight = 0;
|
||||||
|
for (IPawn pawn : maxPawns) {
|
||||||
|
int weight = 0;
|
||||||
|
|
||||||
|
int distanceFromGoal = PawnUtils.distanceFromGoal(pawn);
|
||||||
|
if (distanceFromGoal <= 1) {
|
||||||
|
return WEIGHT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distanceFromGoal == 2) {
|
||||||
|
if (PawnUtils.hasEasyWinPath(game.getBoard(), pawn)) {
|
||||||
|
weight = 8;
|
||||||
|
} else {
|
||||||
|
weight = 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distanceFromGoal > 2 && distanceFromGoal <= ATTACK_DISTANCE_FROM_GOAL) {
|
||||||
|
weight = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weight > maxWeight) {
|
||||||
|
maxWeight = weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,178 @@
|
||||||
|
package laboratoire4.strategies;
|
||||||
|
|
||||||
|
import laboratoire4.Action;
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.game.Game;
|
||||||
|
import laboratoire4.game.GameUtils;
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
import laboratoire4.pawns.PawnUtils;
|
||||||
|
import laboratoire4.pawns.SimulatedPawn;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class DefenseStrategy extends MiniMaxStrategy {
|
||||||
|
private static final int DEFENSE_DISTANCE_FROM_HOME = 2;
|
||||||
|
private static final int PAWN_DEFENSE_DISTANCE = 3;
|
||||||
|
|
||||||
|
private final Map<IPawn, Integer> dangerousPawns;
|
||||||
|
|
||||||
|
public DefenseStrategy(Game game) {
|
||||||
|
super(game);
|
||||||
|
|
||||||
|
dangerousPawns = getDangerousPawns(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EvaluationResult getNextMove() {
|
||||||
|
if (dangerousPawns.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.getNextMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWeight() {
|
||||||
|
if (dangerousPawns.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<IPawn> minPawns = GameUtils.getMinPawns(game.getBoard(), game.getPlayer());
|
||||||
|
Collection<IPawn> maxPawns = GameUtils.getMaxPawns(game.getBoard(), game.getPlayer());
|
||||||
|
int maxWeight = 0;
|
||||||
|
|
||||||
|
for (IPawn pawn : minPawns) {
|
||||||
|
int weight = 0;
|
||||||
|
|
||||||
|
int distanceFromGoal = PawnUtils.distanceFromGoal(pawn);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
weight = 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distanceFromGoal > 2 && distanceFromGoal <= DEFENSE_DISTANCE_FROM_HOME) {
|
||||||
|
weight = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weight > maxWeight) {
|
||||||
|
maxWeight = weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int evaluateSimulation() {
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
Collection<SimulatedPawn> maxPawns = getMaxPawns();
|
||||||
|
Collection<SimulatedPawn> minPawns = getMinPawns();
|
||||||
|
|
||||||
|
for (SimulatedPawn pawn : minPawns) {
|
||||||
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
|
if (PawnUtils.canBeCaptured(game, pawn.getRow() + pawn.getDirection(), pawn.getCol() + movement.getMove(), pawn.getPlayer())) {
|
||||||
|
// Ce pion ennemi est aussi en danger s'il bouge !
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (IPawn dangerousPawn : dangerousPawns.keySet()) {
|
||||||
|
Optional<SimulatedPawn> simulated = GameUtils.getMinPawnsAsStream(game.getBoard(), game.getPlayer())
|
||||||
|
.filter(p -> p.getOriginalRow() == dangerousPawn.getRow() && p.getOriginalCol() == dangerousPawn.getCol())
|
||||||
|
.findFirst();
|
||||||
|
|
||||||
|
if (!simulated.isPresent()) {
|
||||||
|
// Le pion a été capturé !
|
||||||
|
score += Math.pow(dangerousPawns.get(dangerousPawn), 3);
|
||||||
|
} else {
|
||||||
|
// On est toujours en danger
|
||||||
|
int distance = PawnUtils.distanceFromGoal(simulated.get());
|
||||||
|
score -= Math.pow(DEFENSE_DISTANCE_FROM_HOME - distance + 1, 3);
|
||||||
|
|
||||||
|
for (SimulatedPawn pawn : maxPawns) {
|
||||||
|
if (PawnUtils.distanceFromHome(pawn) <= DEFENSE_DISTANCE_FROM_HOME) { // On ne veut pas que nos attaquants s'approchent des pions ennemis
|
||||||
|
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()[row][col - 1])) {
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
if (col < 7 && PawnUtils.areSamePlayers(pawn, game.getBoard()[row][col + 1])) {
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
if (row > 0 && PawnUtils.areSamePlayers(pawn, game.getBoard()[row - 1][col])) {
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
if (row < 7 && PawnUtils.areSamePlayers(pawn, game.getBoard()[row + 1][col])) {
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<IPawn, Integer> getDangerousPawns(Game game) {
|
||||||
|
Map<IPawn, Integer> dangerousPawns = new HashMap<>();
|
||||||
|
|
||||||
|
for (IPawn pawn : GameUtils.getMinPawns(game.getBoard(), game.getPlayer())) {
|
||||||
|
int distance = PawnUtils.distanceFromGoal(pawn);
|
||||||
|
|
||||||
|
if (distance <= DEFENSE_DISTANCE_FROM_HOME) {
|
||||||
|
// Les pions proches de nous qui ne peuvent pas bouger peuvent être ignorés
|
||||||
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
|
if (pawn.isMoveValid(game.getBoard(), movement)) {
|
||||||
|
dangerousPawns.put(pawn, DEFENSE_DISTANCE_FROM_HOME - distance + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dangerousPawns;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package laboratoire4.strategies;
|
||||||
|
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
|
||||||
|
public class EvaluationResult {
|
||||||
|
private final int row;
|
||||||
|
private final int col;
|
||||||
|
private final PawnMovement movement;
|
||||||
|
|
||||||
|
public EvaluationResult(int row, int col, PawnMovement movement) {
|
||||||
|
this.row = row;
|
||||||
|
this.col = col;
|
||||||
|
this.movement = movement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRow() {
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCol() {
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PawnMovement getMovement() {
|
||||||
|
return movement;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
package laboratoire4.strategies;
|
||||||
|
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.game.Game;
|
||||||
|
import laboratoire4.game.GameUtils;
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
import laboratoire4.pawns.PawnUtils;
|
||||||
|
|
||||||
|
public class ImmediateDefenseStrategy implements Strategy {
|
||||||
|
private static final int IMM_DEFENSE_DISTANCE_FROM_HOME = 2;
|
||||||
|
|
||||||
|
private final Game game;
|
||||||
|
|
||||||
|
public ImmediateDefenseStrategy(Game game) {
|
||||||
|
this.game = game;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EvaluationResult getNextMove() {
|
||||||
|
// On n'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())) {
|
||||||
|
if (PawnUtils.distanceFromHome(pawn) > IMM_DEFENSE_DISTANCE_FROM_HOME) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
|
if (pawn.isMoveValid(game.getBoard(), movement)) {
|
||||||
|
int nextRow = pawn.getRow() + pawn.getDirection();
|
||||||
|
int nextCol = pawn.getCol() + movement.getMove();
|
||||||
|
IPawn nextPawn = game.getBoard()[nextRow][nextCol];
|
||||||
|
|
||||||
|
if (nextPawn == null || PawnUtils.areSamePlayers(pawn, nextPawn)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new EvaluationResult(pawn.getRow(), pawn.getCol(), movement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWeight() {
|
||||||
|
for (IPawn pawn : GameUtils.getMaxPawns(game.getBoard(), game.getPlayer())) {
|
||||||
|
if (PawnUtils.distanceFromHome(pawn) > IMM_DEFENSE_DISTANCE_FROM_HOME) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
|
if (pawn.isMoveValid(game.getBoard(), movement)) {
|
||||||
|
int nextRow = pawn.getRow() + pawn.getDirection();
|
||||||
|
int nextCol = pawn.getCol() + movement.getMove();
|
||||||
|
IPawn nextPawn = game.getBoard()[nextRow][nextCol];
|
||||||
|
|
||||||
|
if (nextPawn == null || PawnUtils.areSamePlayers(pawn, nextPawn)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WEIGHT_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
package laboratoire4.strategies;
|
||||||
|
|
||||||
|
import laboratoire4.game.Game;
|
||||||
|
|
||||||
|
public class MasterStrategy implements Strategy {
|
||||||
|
private static Strategy instance;
|
||||||
|
|
||||||
|
public static Strategy getInstance(Game game) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new MasterStrategy(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Game game;
|
||||||
|
|
||||||
|
private MasterStrategy(Game game) {
|
||||||
|
this.game = game;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EvaluationResult getNextMove() {
|
||||||
|
long startMs = System.currentTimeMillis();
|
||||||
|
|
||||||
|
Strategy strategy = getBestStrategy();
|
||||||
|
System.out.println(strategy.getClass().getSimpleName());
|
||||||
|
|
||||||
|
EvaluationResult result = strategy.getNextMove();
|
||||||
|
|
||||||
|
long endMs = System.currentTimeMillis();
|
||||||
|
System.out.printf("Temps: %d ms\n", endMs - startMs);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Strategy getBestStrategy() {
|
||||||
|
Strategy[] strategies = new Strategy[]{
|
||||||
|
new ImmediateDefenseStrategy(game),
|
||||||
|
new WinningStrategy(game),
|
||||||
|
new DefenseStrategy(game),
|
||||||
|
new AttackStrategy(game)
|
||||||
|
};
|
||||||
|
|
||||||
|
int maxWeight = 0;
|
||||||
|
Strategy bestStrategy = null;
|
||||||
|
|
||||||
|
for (Strategy strategy : strategies) {
|
||||||
|
int weight = strategy.getWeight();
|
||||||
|
if (weight == WEIGHT_MAX) {
|
||||||
|
return strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weight > maxWeight) {
|
||||||
|
maxWeight = weight;
|
||||||
|
bestStrategy = strategy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxWeight > 0) {
|
||||||
|
return bestStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RandomStrategy(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWeight() {
|
||||||
|
return WEIGHT_MAX;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,172 @@
|
||||||
|
package laboratoire4.strategies;
|
||||||
|
|
||||||
|
import laboratoire4.Action;
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.game.Game;
|
||||||
|
import laboratoire4.game.GameUtils;
|
||||||
|
import laboratoire4.game.SimulatedGame;
|
||||||
|
import laboratoire4.pawns.Pawn;
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
import laboratoire4.pawns.PawnUtils;
|
||||||
|
import laboratoire4.pawns.SimulatedPawn;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public abstract class MiniMaxStrategy implements Strategy {
|
||||||
|
private static final int MAX_DEPTH = 6;
|
||||||
|
private static final long MAX_TIME_MS = 4800; // Moins de 5 secondes, car le tour n'est pas complètement fini
|
||||||
|
|
||||||
|
protected SimulatedGame game;
|
||||||
|
protected long startTimeMs;
|
||||||
|
|
||||||
|
protected MiniMaxStrategy(Game game) {
|
||||||
|
this.game = new SimulatedGame(game.getBoard(), game.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EvaluationResult getNextMove() {
|
||||||
|
return miniMax();
|
||||||
|
}
|
||||||
|
|
||||||
|
private EvaluationResult miniMax() {
|
||||||
|
EvaluationResult maxResult = null;
|
||||||
|
int maxScore = Integer.MIN_VALUE;
|
||||||
|
startTimeMs = System.currentTimeMillis();
|
||||||
|
|
||||||
|
for (Action<IPawn> action : getActions(true)) {
|
||||||
|
int score = min(0, Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||||
|
|
||||||
|
if (maxResult == null || score > maxScore) {
|
||||||
|
IPawn pawn = action.getPawn();
|
||||||
|
maxResult = new EvaluationResult(pawn.getRow(), pawn.getCol(), action.getMovement());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int max(int depth, int alpha, int beta) {
|
||||||
|
if (depth >= MAX_DEPTH) {
|
||||||
|
return evaluate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.currentTimeMillis() - startTimeMs > MAX_TIME_MS) {
|
||||||
|
return Integer.MIN_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxScore = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
for (Action<IPawn> action : getActions(true)) {
|
||||||
|
IPawn pawn = action.getPawn();
|
||||||
|
PawnMovement movement = action.getMovement();
|
||||||
|
|
||||||
|
game.move(pawn, movement);
|
||||||
|
int score = min(depth + 1, Math.max(alpha, maxScore), beta);
|
||||||
|
game.revertMove();
|
||||||
|
|
||||||
|
if (score > maxScore) {
|
||||||
|
maxScore = score;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxScore >= beta) {
|
||||||
|
return maxScore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int min(int depth, int alpha, int beta) {
|
||||||
|
if (depth >= MAX_DEPTH) {
|
||||||
|
return evaluate();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (System.currentTimeMillis() - startTimeMs > MAX_TIME_MS) {
|
||||||
|
return Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minScore = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
for (Action<IPawn> action : getActions(false)) {
|
||||||
|
IPawn pawn = action.getPawn();
|
||||||
|
PawnMovement movement = action.getMovement();
|
||||||
|
|
||||||
|
game.move(pawn, movement);
|
||||||
|
int score = max(depth + 1, alpha, Math.min(beta, minScore));
|
||||||
|
game.revertMove();
|
||||||
|
|
||||||
|
if (score < minScore) {
|
||||||
|
minScore = score;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minScore <= alpha) {
|
||||||
|
return minScore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return minScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Collection<SimulatedPawn> getMaxPawns() {
|
||||||
|
return GameUtils.getMaxPawns(game.getBoard(), game.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Collection<SimulatedPawn> getMinPawns() {
|
||||||
|
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();
|
||||||
|
|
||||||
|
Collection<SimulatedPawn> maxPawns = getMaxPawns();
|
||||||
|
|
||||||
|
if (maxPawns.stream().noneMatch(IPawn::isPusher)) {
|
||||||
|
return Integer.MIN_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getMinPawns().stream().anyMatch(p -> p.getRow() == p.getPlayer().getGoal())) {
|
||||||
|
return Integer.MIN_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (IPawn pawn : maxPawns) {
|
||||||
|
if (pawn.getRow() == pawn.getPlayer().getGoal()) {
|
||||||
|
return Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PawnUtils.canBeCaptured(game, pawn)) {
|
||||||
|
// On peut être capturé
|
||||||
|
score -= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
|
if (pawn.isMoveValid(game.getBoard(), movement) && !PawnUtils.canBeCaptured(game, pawn.getRow() + pawn.getDirection(), pawn.getCol() + movement.getMove(), pawn.getPlayer())) {
|
||||||
|
// On ne peut pas être capturé en faisant ce mouvement
|
||||||
|
score += 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// region Lignes ennemies
|
||||||
|
for (IPawn pawn : getMinPawns()) {
|
||||||
|
int row = pawn.getRow();
|
||||||
|
int col = pawn.getCol();
|
||||||
|
|
||||||
|
if (row > 0 && PawnUtils.areSamePlayers(pawn, game.getBoard()[row - 1][col])) {
|
||||||
|
score -= 5;
|
||||||
|
}
|
||||||
|
if (row < 0 && PawnUtils.areSamePlayers(pawn, game.getBoard()[row + 1][col])) {
|
||||||
|
score -= 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract int evaluateSimulation();
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package laboratoire4.strategies;
|
||||||
|
|
||||||
|
import laboratoire4.Action;
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.game.Game;
|
||||||
|
import laboratoire4.game.GameUtils;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
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).
|
||||||
|
* Alors, on avance quelques pions (pas tous) aléatoirement.
|
||||||
|
*/
|
||||||
|
public class RandomStrategy implements Strategy {
|
||||||
|
private static final int PAWN_TO_MOVE = 2;
|
||||||
|
|
||||||
|
private final Random random = new Random();
|
||||||
|
private final Game game;
|
||||||
|
|
||||||
|
public RandomStrategy(Game game) {
|
||||||
|
this.game = game;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EvaluationResult getNextMove() {
|
||||||
|
Collection<IPawn> outsideHomePushers = GameUtils.getMaxPawnsAsStream(game.getBoard(), game.getPlayer())
|
||||||
|
.filter(IPawn::isPusher)
|
||||||
|
.filter(p -> p.getRow() != p.getPlayer().getHome())
|
||||||
|
.filter(p -> p.getRow() != p.getPlayer().getHome() + p.getDirection())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (outsideHomePushers.size() >= PAWN_TO_MOVE) {
|
||||||
|
List<Action<IPawn>> validActions = Strategy.getValidActions(game.getBoard(), outsideHomePushers);
|
||||||
|
if (!validActions.isEmpty()) {
|
||||||
|
return getRandomMove(validActions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Action<IPawn>> validActions = Strategy.getValidActions(game);
|
||||||
|
return getRandomMove(validActions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWeight() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EvaluationResult getRandomMove(List<Action<IPawn>> actions) {
|
||||||
|
int randomIndex = random.nextInt(actions.size());
|
||||||
|
Action<IPawn> nextAction = actions.get(randomIndex);
|
||||||
|
IPawn nextPawn = nextAction.getPawn();
|
||||||
|
|
||||||
|
return new EvaluationResult(nextPawn.getRow(), nextPawn.getCol(), nextAction.getMovement());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package laboratoire4.strategies;
|
||||||
|
|
||||||
|
import laboratoire4.Action;
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.game.Game;
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public interface Strategy {
|
||||||
|
int WEIGHT_MAX = 10;
|
||||||
|
|
||||||
|
EvaluationResult getNextMove();
|
||||||
|
|
||||||
|
int getWeight();
|
||||||
|
|
||||||
|
static List<Action<IPawn>> getValidActions(Game game) {
|
||||||
|
List<IPawn> maxPawns = Arrays.stream(game.getBoard())
|
||||||
|
.flatMap(Arrays::stream)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.filter(p -> p.getPlayer() == game.getPlayer())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return getValidActions(game.getBoard(), maxPawns);
|
||||||
|
}
|
||||||
|
|
||||||
|
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<>();
|
||||||
|
|
||||||
|
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()) {
|
||||||
|
if (pawn.isMoveValid(board, movement)) {
|
||||||
|
validActions.add(new Action<>(pawn, movement));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (excludeDefense && validActions.isEmpty()) {
|
||||||
|
return getValidActions(board, pawns, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return validActions;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
package laboratoire4.strategies;
|
||||||
|
|
||||||
|
import laboratoire4.Action;
|
||||||
|
import laboratoire4.IPawn;
|
||||||
|
import laboratoire4.game.Game;
|
||||||
|
import laboratoire4.game.GameUtils;
|
||||||
|
import laboratoire4.pawns.PawnMovement;
|
||||||
|
import laboratoire4.pawns.PawnUtils;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class WinningStrategy implements Strategy {
|
||||||
|
private Action<IPawn> winningAction;
|
||||||
|
|
||||||
|
public WinningStrategy(Game game) {
|
||||||
|
winningAction = findImmediateWinningAction(game);
|
||||||
|
if (winningAction == null) {
|
||||||
|
// On cherche un chemin où on peut gagner quoi qu'il arrive
|
||||||
|
winningAction = findWinningPath(game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EvaluationResult getNextMove() {
|
||||||
|
if (winningAction == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPawn winningPawn = winningAction.getPawn();
|
||||||
|
return new EvaluationResult(winningPawn.getRow(), winningPawn.getCol(), winningAction.getMovement());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWeight() {
|
||||||
|
if (winningAction != null) {
|
||||||
|
return WEIGHT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Action<IPawn> findImmediateWinningAction(Game game) {
|
||||||
|
Collection<IPawn> nearPawns = GameUtils.getMaxPawnsAsStream(game.getBoard(), game.getPlayer())
|
||||||
|
.filter(p -> p.getRow() + p.getDirection() == p.getPlayer().getGoal())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
for (IPawn pawn : nearPawns) {
|
||||||
|
for (PawnMovement movement : PawnMovement.values()) {
|
||||||
|
if (pawn.isMoveValid(game.getBoard(), movement)) {
|
||||||
|
return new Action<>(pawn, movement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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