Compare commits
4 Commits
faecae0822
...
bd0fc7edfd
Author | SHA1 | Date |
---|---|---|
william | bd0fc7edfd | |
william | 0b528baa8b | |
william | 39051a8fdd | |
William Nolin | 0ff8d6f057 |
|
@ -8,7 +8,7 @@
|
|||
</list>
|
||||
</option>
|
||||
</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_18" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
|
@ -4,25 +4,23 @@
|
|||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="41395b4b-3252-492c-a869-5f4dab107186" name="Changes" comment="Movement logic">
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/Main.java" afterDir="false" />
|
||||
<list default="true" id="41395b4b-3252-492c-a869-5f4dab107186" name="Changes" comment="AI">
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/IPawn.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/MovingBoard.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/MovingPawn.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/MovingPushed.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/MovingPusher.java" afterDir="false" />
|
||||
<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$/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/pom.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$/src/main/java/laboratoire4/GameTree.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/GameTree.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/MiniMax.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/MiniMax.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/Pawn.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/Pawn.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/Player.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/Player.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/Pushed.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/Pushed.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/Pusher.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/Pusher.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/Test.java" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/TestPusherBoard.java" beforeDir="false" />
|
||||
</list>
|
||||
<list id="98b8a79f-2f53-42bf-96da-7af322697a0d" name="Changes by acastonguay" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/GameTree.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/GameTree.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/laboratoire4/MiniMax.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/MiniMax.java" afterDir="false" />
|
||||
</list>
|
||||
<list id="98b8a79f-2f53-42bf-96da-7af322697a0d" name="Changes by acastonguay" comment="" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
|
@ -32,44 +30,17 @@
|
|||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Class" />
|
||||
<option value="Interface" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||
<map>
|
||||
<entry key="$PROJECT_DIR$" value="alexis" />
|
||||
<entry key="$PROJECT_DIR$" value="master" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="LineStatusTrackerManager">
|
||||
<file path="$PROJECT_DIR$/src/main/java/laboratoire4/MiniMax.java">
|
||||
<ranges>
|
||||
<range start1="2" end1="2" start2="2" end2="6" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
<range start1="4" end1="4" start2="8" end2="9" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
<range start1="5" end1="7" start2="10" end2="12" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
<range start1="9" end1="13" start2="14" end2="19" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
<range start1="14" end1="18" start2="20" end2="21" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
<range start1="19" end1="21" start2="22" end2="25" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
<range start1="22" end1="28" start2="26" end2="39" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
<range start1="29" end1="31" start2="40" end2="50" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
<range start1="32" end1="34" start2="51" end2="53" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
<range start1="35" end1="39" start2="54" end2="56" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
<range start1="42" end1="43" start2="59" end2="62" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
<range start1="45" end1="46" start2="64" end2="67" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
<range start1="47" end1="48" start2="68" end2="69" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
<range start1="49" end1="49" start2="70" end2="125" changelist="98b8a79f-2f53-42bf-96da-7af322697a0d" />
|
||||
</ranges>
|
||||
</file>
|
||||
<file path="$PROJECT_DIR$/src/main/java/laboratoire4/GameTree.java">
|
||||
<ranges>
|
||||
<range start1="17" end1="17" start2="17" end2="19" changelist="98b8a79f-2f53-42bf-96da-7af322697a0d" />
|
||||
<range start1="18" end1="19" start2="20" end2="21" changelist="98b8a79f-2f53-42bf-96da-7af322697a0d" />
|
||||
<range start1="20" end1="20" start2="22" end2="24" changelist="98b8a79f-2f53-42bf-96da-7af322697a0d" />
|
||||
<range start1="25" end1="25" start2="29" end2="37" changelist="41395b4b-3252-492c-a869-5f4dab107186" />
|
||||
</ranges>
|
||||
</file>
|
||||
</component>
|
||||
<component name="MacroExpansionManager">
|
||||
<option name="directoryName" value="x0367gi2" />
|
||||
</component>
|
||||
|
@ -83,6 +54,9 @@
|
|||
</MavenImportingSettings>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProblemsViewState">
|
||||
<option name="selectedTabId" value="ProjectErrors" />
|
||||
</component>
|
||||
<component name="ProjectId" id="2NFN0RGJNNJqiDmt34ixVwkIwEm" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
|
||||
<ConfirmationsSetting value="2" id="Add" />
|
||||
|
@ -91,20 +65,21 @@
|
|||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"codeWithMe.voiceChat.enabledByDefault": "false",
|
||||
"last_opened_file_path": "/home/william/Dev/Projects",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"codeWithMe.voiceChat.enabledByDefault": "false",
|
||||
"last_opened_file_path": "/home/william/Dev/Projects",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
}
|
||||
}]]></component>
|
||||
}</component>
|
||||
<component name="RunManager" selected="Application.Main">
|
||||
<configuration name="Client" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
|
||||
<option name="MAIN_CLASS_NAME" value="laboratoire4.Client" />
|
||||
|
@ -167,6 +142,8 @@
|
|||
<workItem from="1679344371350" duration="4138000" />
|
||||
<workItem from="1679365557789" duration="21000" />
|
||||
<workItem from="1679424430928" duration="11764000" />
|
||||
<workItem from="1679593788411" duration="10753000" />
|
||||
<workItem from="1679672719638" duration="7700000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="MiniMax">
|
||||
<created>1679263366439</created>
|
||||
|
@ -182,7 +159,14 @@
|
|||
<option name="project" value="LOCAL" />
|
||||
<updated>1679348475071</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="3" />
|
||||
<task id="LOCAL-00003" summary="Small fixes">
|
||||
<created>1679490100944</created>
|
||||
<option name="number" value="00003" />
|
||||
<option name="presentableId" value="LOCAL-00003" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1679490100944</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="4" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
|
@ -191,6 +175,15 @@
|
|||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="MiniMax" />
|
||||
<MESSAGE value="Movement logic" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="Movement logic" />
|
||||
<MESSAGE value="Small fixes" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="Small fixes" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<default-breakpoints>
|
||||
<breakpoint enabled="true" type="CidrExceptionBreakpoint" />
|
||||
<breakpoint enabled="true" type="java-exception" />
|
||||
</default-breakpoints>
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
</project>
|
|
@ -65,7 +65,7 @@ public class Client {
|
|||
return player == Player.RED;
|
||||
}
|
||||
|
||||
private void play() throws IOException {
|
||||
private void play() throws IOException, InterruptedException {
|
||||
byte[] aBuffer = new byte[16];
|
||||
int size = input.available();
|
||||
if (size > 0) {
|
||||
|
@ -76,6 +76,8 @@ public class Client {
|
|||
board.move(previousMove);
|
||||
}
|
||||
|
||||
Thread.sleep(500);
|
||||
|
||||
String nextMove = board.runNextMove();
|
||||
System.out.println("Prochain mouvement: " + nextMove);
|
||||
|
||||
|
@ -83,15 +85,18 @@ public class Client {
|
|||
output.flush();
|
||||
}
|
||||
|
||||
private void handleInvalidMove() throws InterruptedException {
|
||||
private void handleInvalidMove() throws InterruptedException, IOException {
|
||||
System.err.println("Mouvement invalide!");
|
||||
Thread.sleep(500);
|
||||
board.printBoard();
|
||||
|
||||
PusherBoard.printBoard(board.getBoard());
|
||||
|
||||
// play();
|
||||
}
|
||||
|
||||
private void stopGame() throws IOException {
|
||||
System.out.println("GG well played!");
|
||||
socket.close();
|
||||
// socket.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package laboratoire4;
|
||||
|
||||
public interface IPawn {
|
||||
boolean isMoveValid(IPawn[][] board, Pawn.PawnMovement movement);
|
||||
void move(Pawn.PawnMovement movement);
|
||||
boolean isPusher();
|
||||
int getDirection();
|
||||
Player getPlayer();
|
||||
int getRow();
|
||||
int getCol();
|
||||
void setRow(int row);
|
||||
void setCol(int col);
|
||||
}
|
|
@ -1,91 +1,141 @@
|
|||
package laboratoire4;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class MiniMax {
|
||||
private static final int MAX_DEPTH = 4;
|
||||
private static Random random = new Random();
|
||||
private static final int MAX_DEPTH = 1;
|
||||
|
||||
public static MiniMaxResult miniMax(PusherBoard board) {
|
||||
return miniMax(board, true, 0, Integer.MIN_VALUE);
|
||||
MovingBoard game = new MovingBoard(board.getBoard(), board.getPlayer());
|
||||
return miniMax(game, true, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
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();
|
||||
private static MiniMaxResult miniMax(MovingBoard game, boolean max, int depth, int alpha, int beta) {
|
||||
depth += 1;
|
||||
|
||||
List<MiniMaxResult> results = new ArrayList<>();
|
||||
if (max) {
|
||||
return max(game, depth, alpha, beta);
|
||||
}
|
||||
|
||||
for (Pawn pawn : pawns) {
|
||||
int originalRow = pawn.getRow();
|
||||
int originalCol = pawn.getCol();
|
||||
return min(game, depth, alpha, beta);
|
||||
}
|
||||
|
||||
private static MiniMaxResult max(MovingBoard game, int depth, int alpha, int beta) {
|
||||
int alphaT = Integer.MIN_VALUE;
|
||||
MovingPawn lastPawn = null;
|
||||
Pawn.PawnMovement lastMovement = null;
|
||||
|
||||
for (MovingPawn pawn : game.getMaxPawns()) {
|
||||
for (Pawn.PawnMovement movement : Pawn.PawnMovement.values()) {
|
||||
if (pawn.isMoveValid(board, movement)) {
|
||||
pawn.move(movement);
|
||||
|
||||
int score = depth < MAX_DEPTH ?
|
||||
miniMax(board, !max, depth + 1, limScore).getScore() :
|
||||
evaluate(pawn, board);
|
||||
score *= pawn.getDirection();
|
||||
|
||||
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);
|
||||
if (!pawn.isMoveValid(game.getBoard(), movement)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pawn.setRow(originalRow);
|
||||
pawn.setCol(originalCol);
|
||||
lastPawn = pawn;
|
||||
lastMovement = movement;
|
||||
|
||||
game.move(pawn, movement);
|
||||
|
||||
int score = evaluate(pawn, game, depth);
|
||||
if (depth < MAX_DEPTH) {
|
||||
score = miniMax(game, false, depth, Math.max(alpha, alphaT), beta).getScore();
|
||||
}
|
||||
|
||||
game.revertMove();
|
||||
|
||||
if (score > alphaT) {
|
||||
alphaT = score;
|
||||
}
|
||||
|
||||
if (alphaT >= beta) {
|
||||
return new MiniMaxResult(alphaT, pawn.getRow(), pawn.getCol(), movement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Choisir aléatoirement
|
||||
int index = random.nextInt(results.size());
|
||||
return results.get(index);
|
||||
if (lastPawn == null) {
|
||||
return new MiniMaxResult(alphaT, 0, 0, null);
|
||||
}
|
||||
return new MiniMaxResult(alphaT, lastPawn.getRow(), lastPawn.getCol(), lastMovement);
|
||||
}
|
||||
|
||||
private static int evaluate(Pawn pawn, PusherBoard board) {
|
||||
int score = didWin(pawn);
|
||||
score = Math.max(score, didCapture(pawn, board));
|
||||
private static MiniMaxResult min(MovingBoard game, int depth, int alpha, int beta) {
|
||||
int betaT = Integer.MAX_VALUE;
|
||||
MovingPawn lastPawn = null;
|
||||
Pawn.PawnMovement lastMovement = null;
|
||||
|
||||
return score;
|
||||
for (MovingPawn pawn : game.getMinPawns()) {
|
||||
for (Pawn.PawnMovement movement : Pawn.PawnMovement.values()) {
|
||||
if (!pawn.isMoveValid(game.getBoard(), movement)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lastPawn = pawn;
|
||||
lastMovement = movement;
|
||||
|
||||
game.move(pawn, movement);
|
||||
|
||||
int score = evaluate(pawn, game, depth);
|
||||
if (depth < MAX_DEPTH) {
|
||||
score = miniMax(game, true, depth, alpha, Math.min(betaT, beta)).getScore();
|
||||
}
|
||||
|
||||
game.revertMove();
|
||||
|
||||
if (score < betaT) {
|
||||
betaT = score;
|
||||
}
|
||||
|
||||
if (betaT <= beta) {
|
||||
return new MiniMaxResult(betaT, pawn.getRow(), pawn.getCol(), movement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lastPawn == null) {
|
||||
return new MiniMaxResult(betaT, 0, 0, null);
|
||||
}
|
||||
return new MiniMaxResult(betaT, lastPawn.getRow(), lastPawn.getCol(), lastMovement);
|
||||
}
|
||||
|
||||
private static int didWin(Pawn pawn) {
|
||||
int goal = pawn.getPlayer() == Player.RED ? 7 : 0;
|
||||
private static int evaluate(IPawn pawn, MovingBoard game, int depth) {
|
||||
int score = didWin(pawn) + didCapture(pawn, game);
|
||||
|
||||
if (pawn.getRow() == goal) {
|
||||
return Integer.MAX_VALUE;
|
||||
score += pawn.isPusher() ? 0 : 5;
|
||||
|
||||
int row = pawn.getRow();
|
||||
int col = pawn.getCol();
|
||||
int nextNextRow = row + pawn.getDirection() * 2;
|
||||
|
||||
// Attire nos pusher vers nos pushed
|
||||
if (pawn.isPusher() && nextNextRow >= 0 && nextNextRow <= 7) {
|
||||
for (Pawn.PawnMovement move : Pawn.PawnMovement.values()) {
|
||||
int nextCol = col + move.getMove();
|
||||
if (nextCol < 0 || nextCol > 7) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IPawn nearPawn = game.getBoard()[nextNextRow][nextCol];
|
||||
if (nearPawn != null && !nearPawn.isPusher() && nearPawn.getPlayer() == pawn.getPlayer()) {
|
||||
score += 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return score * pawn.getDirection();
|
||||
}
|
||||
|
||||
private static int didWin(IPawn pawn) {
|
||||
if (pawn.getRow() == pawn.getPlayer().getGoal()) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int didCapture(Pawn pawn, PusherBoard board) {
|
||||
Pawn capturedPawn = board.getBoard()[pawn.getRow()][pawn.getCol()];
|
||||
private static int didCapture(IPawn pawn, MovingBoard game) {
|
||||
IPawn capturedPawn = game.getBoard()[pawn.getRow()][pawn.getCol()];
|
||||
|
||||
if (capturedPawn != null) {
|
||||
if (capturedPawn.getPlayer() != pawn.getPlayer()) {
|
||||
return 50;
|
||||
}
|
||||
if (capturedPawn != null && capturedPawn.getPlayer() != game.getPlayer()) {
|
||||
return 500;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -93,12 +143,14 @@ public class MiniMax {
|
|||
|
||||
static class MiniMaxResult {
|
||||
private final int score;
|
||||
private final Pawn pawn;
|
||||
private final int row;
|
||||
private final int col;
|
||||
private final Pawn.PawnMovement movement;
|
||||
|
||||
public MiniMaxResult(int score, Pawn pawn, Pawn.PawnMovement movement) {
|
||||
public MiniMaxResult(int score, int row, int col, Pawn.PawnMovement movement) {
|
||||
this.score = score;
|
||||
this.pawn = pawn;
|
||||
this.row = row;
|
||||
this.col = col;
|
||||
this.movement = movement;
|
||||
}
|
||||
|
||||
|
@ -106,8 +158,12 @@ public class MiniMax {
|
|||
return score;
|
||||
}
|
||||
|
||||
public Pawn getPawn() {
|
||||
return pawn;
|
||||
public int getRow() {
|
||||
return row;
|
||||
}
|
||||
|
||||
public int getCol() {
|
||||
return col;
|
||||
}
|
||||
|
||||
public Pawn.PawnMovement getMovement() {
|
||||
|
@ -118,7 +174,8 @@ public class MiniMax {
|
|||
public String toString() {
|
||||
return "MiniMaxResult{" +
|
||||
"score=" + score +
|
||||
", pawn=" + pawn +
|
||||
", col=" + col +
|
||||
", row=" + row +
|
||||
", movement=" + movement +
|
||||
'}';
|
||||
}
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
package laboratoire4;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class MovingBoard {
|
||||
private final MovingPawn[][] board;
|
||||
private final Player player;
|
||||
|
||||
private final Stack<MovingPawn> removedPawns = new Stack<>();
|
||||
private final Stack<MovingPawn> previousMovedPawns = new Stack<>();
|
||||
|
||||
public MovingBoard(Pawn[][] board, Player player) {
|
||||
this.board = asMovingPawns(board);
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public void move(MovingPawn pawn, Pawn.PawnMovement movement) {
|
||||
int toRow = pawn.getRow() + pawn.getDirection();
|
||||
int toCol = pawn.getCol() + movement.getMove();
|
||||
MovingPawn capturedPawn = board[toRow][toCol];
|
||||
|
||||
previousMovedPawns.push(pawn);
|
||||
removedPawns.push(capturedPawn);
|
||||
|
||||
board[pawn.getRow()][pawn.getCol()] = null;
|
||||
board[toRow][toCol] = pawn;
|
||||
pawn.move(movement);
|
||||
}
|
||||
|
||||
public void revertMove() {
|
||||
MovingPawn pawn = previousMovedPawns.pop();
|
||||
MovingPawn capturedPawn = removedPawns.pop();
|
||||
|
||||
board[pawn.getRow()][pawn.getCol()] = capturedPawn;
|
||||
|
||||
pawn.revertMove();
|
||||
board[pawn.getRow()][pawn.getCol()] = pawn;
|
||||
}
|
||||
|
||||
public MovingPawn[][] getBoard() {
|
||||
return board;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public Collection<MovingPawn> getMaxPawns() {
|
||||
return getPawns(p -> p.getPlayer() == player);
|
||||
}
|
||||
|
||||
public Collection<MovingPawn> getMinPawns() {
|
||||
return getPawns(p -> p.getPlayer() != player);
|
||||
}
|
||||
|
||||
private Collection<MovingPawn> getPawns(Predicate<MovingPawn> predicate) {
|
||||
List<MovingPawn> pawns = new ArrayList<>();
|
||||
for (MovingPawn[] row : board) {
|
||||
for (MovingPawn pawn : row) {
|
||||
if (pawn != null && predicate.test(pawn)) {
|
||||
pawns.add(pawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
return pawns;
|
||||
}
|
||||
|
||||
public static MovingPawn[][] asMovingPawns(Pawn[][] board) {
|
||||
MovingPawn[][] to = new MovingPawn[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;
|
||||
}
|
||||
|
||||
MovingPawn pawn = MovingPawn.from(board[row][col]);
|
||||
to[row][col] = pawn;
|
||||
}
|
||||
}
|
||||
return to;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package laboratoire4;
|
||||
|
||||
public interface MovingPawn extends IPawn {
|
||||
void revertMove();
|
||||
|
||||
static MovingPawn from(Pawn pawn) {
|
||||
if (pawn instanceof Pusher) {
|
||||
return new MovingPusher(pawn.getPlayer(), pawn.getRow(), pawn.getCol());
|
||||
}
|
||||
|
||||
return new MovingPushed(pawn.getPlayer(), pawn.getRow(), pawn.getCol());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package laboratoire4;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
public class MovingPushed extends Pushed implements MovingPawn {
|
||||
private final Stack<PawnMovement> previousMoves = new Stack<>();
|
||||
|
||||
public MovingPushed(Player player, int row, int col) {
|
||||
super(player, row, col);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(PawnMovement movement) {
|
||||
super.move(movement);
|
||||
previousMoves.push(movement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revertMove() {
|
||||
PawnMovement move = previousMoves.pop();
|
||||
setRow(row - getDirection());
|
||||
setCol(col - move.getMove());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package laboratoire4;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
public class MovingPusher extends Pusher implements MovingPawn {
|
||||
private final Stack<PawnMovement> previousMoves = new Stack<>();
|
||||
|
||||
public MovingPusher(Player player, int row, int col) {
|
||||
super(player, row, col);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move(PawnMovement movement) {
|
||||
previousMoves.push(movement);
|
||||
super.move(movement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revertMove() {
|
||||
PawnMovement move = previousMoves.pop();
|
||||
setRow(row - getDirection());
|
||||
setCol(col - move.getMove());
|
||||
}
|
||||
}
|
|
@ -1,20 +1,18 @@
|
|||
package laboratoire4;
|
||||
|
||||
public abstract class Pawn {
|
||||
public abstract class Pawn implements IPawn {
|
||||
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);
|
||||
setRow(row + player.getDirection());
|
||||
setCol(col + movement.move);
|
||||
}
|
||||
|
||||
|
@ -44,12 +42,10 @@ public abstract class Pawn {
|
|||
}
|
||||
|
||||
public int getDirection() {
|
||||
return direction;
|
||||
return player.getDirection();
|
||||
}
|
||||
|
||||
public boolean isMoveValid(PusherBoard game, PawnMovement movement) {
|
||||
Pawn[][] board = game.getBoard();
|
||||
|
||||
public boolean isMoveValid(IPawn[][] board, PawnMovement movement) {
|
||||
int nextRow = row + getDirection();
|
||||
if (nextRow < 0 || nextRow >= board.length) {
|
||||
return false;
|
||||
|
@ -60,10 +56,10 @@ public abstract class Pawn {
|
|||
return false;
|
||||
}
|
||||
|
||||
return isMoveValid(board, movement);
|
||||
return isMoveReallyValid(board, movement);
|
||||
}
|
||||
|
||||
protected abstract boolean isMoveValid(Pawn[][] board, PawnMovement movement);
|
||||
protected abstract boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement);
|
||||
|
||||
enum PawnMovement {
|
||||
STRAIGHT(0),
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
package laboratoire4;
|
||||
|
||||
public enum Player {
|
||||
BLACK,
|
||||
RED
|
||||
BLACK(-1, 0),
|
||||
RED(1, 7);
|
||||
|
||||
private int direction;
|
||||
private int goal;
|
||||
|
||||
Player(int direction, int goal) {
|
||||
this.direction = direction;
|
||||
this.goal = goal;
|
||||
}
|
||||
|
||||
public int getDirection() {
|
||||
return direction;
|
||||
}
|
||||
|
||||
public int getGoal() {
|
||||
return goal;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,29 +6,31 @@ public class Pushed extends Pawn {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isMoveValid(Pawn[][] board, PawnMovement movement) {
|
||||
Pawn pusher = null;
|
||||
Pawn to = board[row + direction][col + movement.getMove()];
|
||||
public boolean isPusher() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement) {
|
||||
int direction = getDirection();
|
||||
IPawn pusher = null;
|
||||
IPawn to = board[row + direction][col + movement.getMove()];
|
||||
|
||||
if (col > 0 && movement == PawnMovement.RIGHT_DIAGONAL) {
|
||||
pusher = board[row - direction][col - 1];
|
||||
pusher = board[row - direction][col - movement.getMove()];
|
||||
} else if (col < board.length - 1 && movement == PawnMovement.LEFT_DIAGONAL) {
|
||||
pusher = board[row - direction][col + 1];
|
||||
pusher = board[row - direction][col - movement.getMove()];
|
||||
} else if (movement == PawnMovement.STRAIGHT) {
|
||||
pusher = board[row - direction][col];
|
||||
}
|
||||
|
||||
boolean pusherValid = pusher instanceof Pusher;
|
||||
boolean destinationValid = to == null || to.player != this.player;
|
||||
boolean pusherValid = pusher != null && pusher.isPusher() && pusher.getPlayer() == player;
|
||||
boolean destinationValid = to == null || (movement != PawnMovement.STRAIGHT && to.getPlayer() != this.player);
|
||||
return pusherValid && destinationValid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Pushed{" +
|
||||
player +
|
||||
", " + col +
|
||||
", " + row +
|
||||
"} ";
|
||||
return String.format("Pushed{%s, %s}", player, getPosition());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,22 +6,27 @@ public class Pusher extends Pawn {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isMoveValid(Pawn[][] board, PawnMovement movement) {
|
||||
Pawn to = board[row + direction][col + movement.getMove()];
|
||||
public boolean isPusher() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement) {
|
||||
IPawn to = board[getRow() + getDirection()][getCol() + movement.getMove()];
|
||||
|
||||
if (to == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return to.player != this.player && movement != PawnMovement.STRAIGHT;
|
||||
if (to.getPlayer() == player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return movement != PawnMovement.STRAIGHT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Pusher{" +
|
||||
player +
|
||||
", " + col +
|
||||
", " + row +
|
||||
"} ";
|
||||
return String.format("Pusher{%s, %s}", player, getPosition());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,9 @@
|
|||
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;
|
||||
|
||||
|
@ -31,12 +25,6 @@ public class PusherBoard {
|
|||
pawn = new Pushed(pawnPlayer, row, col);
|
||||
}
|
||||
|
||||
if (pawnPlayer == player) {
|
||||
maxPawns.add(pawn);
|
||||
} else {
|
||||
minPawns.add(pawn);
|
||||
}
|
||||
|
||||
board[row][col] = pawn;
|
||||
}
|
||||
|
||||
|
@ -50,88 +38,66 @@ public class PusherBoard {
|
|||
|
||||
public String runNextMove() {
|
||||
MiniMax.MiniMaxResult result = MiniMax.miniMax(this);
|
||||
Pawn pawn = result.getPawn();
|
||||
Pawn pawn = board[result.getRow()][result.getCol()];
|
||||
System.out.println(result.getScore());
|
||||
|
||||
String initialPosition = pawn.getPosition();
|
||||
|
||||
move(pawn, result.getMovement());
|
||||
String nextPosition = pawn.getPosition();
|
||||
|
||||
return initialPosition + "-" + pawn.getPosition();
|
||||
return initialPosition + "-" + nextPosition;
|
||||
}
|
||||
|
||||
public void move(String move) {
|
||||
//FORMAT ex : D2-D3
|
||||
String[] split = move.trim().split(" - ");
|
||||
move(split[0], split[1]);
|
||||
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;
|
||||
|
||||
Pawn.PawnMovement movement = Pawn.PawnMovement.from(toCol - fromCol);
|
||||
move(fromRow, fromCol, movement);
|
||||
}
|
||||
|
||||
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)) {
|
||||
public void move(int row, int col, Pawn.PawnMovement movement) {
|
||||
Pawn pawn = board[row][col];
|
||||
if (pawn == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Pawn pawn = board[from_row][from_col];
|
||||
Pawn destPawn = board[to_row][to_col];
|
||||
|
||||
if (destPawn != null) {
|
||||
if (destPawn.getPlayer() == Player.RED) {
|
||||
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);
|
||||
move(pawn, movement);
|
||||
}
|
||||
|
||||
private void move(Pawn pawn, Pawn.PawnMovement movement) {
|
||||
// if (!pawn.isMoveValid(board, movement)) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
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);
|
||||
int toRow = pawn.getRow() + pawn.getDirection();
|
||||
int toCol = pawn.getCol() + movement.getMove();
|
||||
|
||||
if (pawn == null) {
|
||||
return false;
|
||||
}
|
||||
board[pawn.getRow()][pawn.getCol()] = null;
|
||||
board[toRow][toCol] = pawn;
|
||||
pawn.move(movement);
|
||||
}
|
||||
|
||||
return pawn.isMoveValid(this, move);
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public Pawn[][] getBoard() {
|
||||
return board;
|
||||
}
|
||||
|
||||
public List<Pawn> getMaxPawns() {
|
||||
return maxPawns;
|
||||
}
|
||||
|
||||
public List<Pawn> getMinPawns() {
|
||||
return minPawns;
|
||||
}
|
||||
|
||||
public void printBoard() {
|
||||
public static void printBoard(Pawn[][] board) {
|
||||
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] + " | ");
|
||||
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.print(" | ");
|
||||
}
|
||||
}
|
||||
System.out.println();
|
||||
|
|
Loading…
Reference in New Issue