Compare commits

..

No commits in common. "bd0fc7edfd20c4c1cb52f44409a914c77d53a30a" and "faecae0822205b7b079350afc99bdef78f83998f" have entirely different histories.

14 changed files with 232 additions and 434 deletions

View File

@ -8,7 +8,7 @@
</list> </list>
</option> </option>
</component> </component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_18" default="true" project-jdk-name="11" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" /> <output url="file://$PROJECT_DIR$/out" />
</component> </component>
</project> </project>

View File

@ -4,23 +4,25 @@
<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="AI"> <list default="true" id="41395b4b-3252-492c-a869-5f4dab107186" name="Changes" comment="Movement logic">
<change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/IPawn.java" afterDir="false" /> <change afterPath="$PROJECT_DIR$/src/main/java/laboratoire4/Main.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$/.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/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/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/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/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/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/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/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>
<list id="98b8a79f-2f53-42bf-96da-7af322697a0d" name="Changes by acastonguay" comment="" />
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
@ -30,17 +32,44 @@
<option name="RECENT_TEMPLATES"> <option name="RECENT_TEMPLATES">
<list> <list>
<option value="Class" /> <option value="Class" />
<option value="Interface" />
</list> </list>
</option> </option>
</component> </component>
<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="master" /> <entry key="$PROJECT_DIR$" value="alexis" />
</map> </map>
</option> </option>
</component> </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"> <component name="MacroExpansionManager">
<option name="directoryName" value="x0367gi2" /> <option name="directoryName" value="x0367gi2" />
</component> </component>
@ -54,9 +83,6 @@
</MavenImportingSettings> </MavenImportingSettings>
</option> </option>
</component> </component>
<component name="ProblemsViewState">
<option name="selectedTabId" value="ProjectErrors" />
</component>
<component name="ProjectId" id="2NFN0RGJNNJqiDmt34ixVwkIwEm" /> <component name="ProjectId" id="2NFN0RGJNNJqiDmt34ixVwkIwEm" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true"> <component name="ProjectLevelVcsManager" settingsEditedManually="true">
<ConfirmationsSetting value="2" id="Add" /> <ConfirmationsSetting value="2" id="Add" />
@ -65,21 +91,20 @@
<option name="hideEmptyMiddlePackages" value="true" /> <option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" /> <option name="showLibraryContents" value="true" />
</component> </component>
<component name="PropertiesComponent">{ <component name="PropertiesComponent"><![CDATA[{
&quot;keyToString&quot;: { "keyToString": {
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;, "RunOnceActivity.OpenProjectViewOnStart": "true",
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;, "RunOnceActivity.ShowReadmeOnStart": "true",
&quot;SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;, "SHARE_PROJECT_CONFIGURATION_FILES": "true",
&quot;codeWithMe.voiceChat.enabledByDefault&quot;: &quot;false&quot;, "codeWithMe.voiceChat.enabledByDefault": "false",
&quot;last_opened_file_path&quot;: &quot;/home/william/Dev/Projects&quot;, "last_opened_file_path": "/home/william/Dev/Projects",
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;, "node.js.detected.package.eslint": "true",
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;, "node.js.detected.package.tslint": "true",
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;, "node.js.selected.package.eslint": "(autodetect)",
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;, "node.js.selected.package.tslint": "(autodetect)",
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;, "vue.rearranger.settings.migration": "true"
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
} }
}</component> }]]></component>
<component name="RunManager" selected="Application.Main"> <component name="RunManager" selected="Application.Main">
<configuration name="Client" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true"> <configuration name="Client" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="laboratoire4.Client" /> <option name="MAIN_CLASS_NAME" value="laboratoire4.Client" />
@ -142,8 +167,6 @@
<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="7700000" />
</task> </task>
<task id="LOCAL-00001" summary="MiniMax"> <task id="LOCAL-00001" summary="MiniMax">
<created>1679263366439</created> <created>1679263366439</created>
@ -159,14 +182,7 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1679348475071</updated> <updated>1679348475071</updated>
</task> </task>
<task id="LOCAL-00003" summary="Small fixes"> <option name="localTasksCounter" value="3" />
<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 /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@ -175,15 +191,6 @@
<component name="VcsManagerConfiguration"> <component name="VcsManagerConfiguration">
<MESSAGE value="MiniMax" /> <MESSAGE value="MiniMax" />
<MESSAGE value="Movement logic" /> <MESSAGE value="Movement logic" />
<MESSAGE value="Small fixes" /> <option name="LAST_COMMIT_MESSAGE" value="Movement logic" />
<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> </component>
</project> </project>

View File

@ -65,7 +65,7 @@ public class Client {
return player == Player.RED; return player == Player.RED;
} }
private void play() throws IOException, InterruptedException { private void play() throws IOException {
byte[] aBuffer = new byte[16]; byte[] aBuffer = new byte[16];
int size = input.available(); int size = input.available();
if (size > 0) { if (size > 0) {
@ -76,8 +76,6 @@ public class Client {
board.move(previousMove); board.move(previousMove);
} }
Thread.sleep(500);
String nextMove = board.runNextMove(); String nextMove = board.runNextMove();
System.out.println("Prochain mouvement: " + nextMove); System.out.println("Prochain mouvement: " + nextMove);
@ -85,18 +83,15 @@ public class Client {
output.flush(); output.flush();
} }
private void handleInvalidMove() throws InterruptedException, IOException { private void handleInvalidMove() throws InterruptedException {
System.err.println("Mouvement invalide!"); System.err.println("Mouvement invalide!");
Thread.sleep(500); Thread.sleep(500);
board.printBoard();
PusherBoard.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();
} }
} }

View File

@ -1,13 +0,0 @@
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);
}

View File

@ -1,141 +1,91 @@
package laboratoire4; package laboratoire4;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class MiniMax { public class MiniMax {
private static final int MAX_DEPTH = 1; private static final int MAX_DEPTH = 4;
private static Random random = new Random();
public static MiniMaxResult miniMax(PusherBoard board) { public static MiniMaxResult miniMax(PusherBoard board) {
MovingBoard game = new MovingBoard(board.getBoard(), board.getPlayer()); return miniMax(board, true, 0, Integer.MIN_VALUE);
return miniMax(game, true, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
} }
private static MiniMaxResult miniMax(MovingBoard game, boolean max, int depth, int alpha, int beta) { private static MiniMaxResult miniMax(PusherBoard board, boolean max, int depth, int alphaBeta) {
depth += 1; int limScore = max ? Integer.MIN_VALUE : Integer.MAX_VALUE;
List<Pawn> pawns = max ?
board.getMaxPawns() :
board.getMinPawns();
if (max) { List<MiniMaxResult> results = new ArrayList<>();
return max(game, depth, alpha, beta);
}
return min(game, depth, alpha, beta); for (Pawn pawn : pawns) {
} int originalRow = pawn.getRow();
int originalCol = pawn.getCol();
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()) { for (Pawn.PawnMovement movement : Pawn.PawnMovement.values()) {
if (!pawn.isMoveValid(game.getBoard(), movement)) { if (pawn.isMoveValid(board, movement)) {
continue; 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;
} }
lastPawn = pawn; MiniMaxResult result = new MiniMaxResult(limScore, pawn, movement);
lastMovement = movement;
game.move(pawn, movement); //elagage alphaBeta
if ((max && limScore >= alphaBeta) ||
(!max && limScore <= alphaBeta)) {
pawn.setRow(originalRow);
pawn.setCol(originalCol);
int score = evaluate(pawn, game, depth); return result;
if (depth < MAX_DEPTH) {
score = miniMax(game, false, depth, Math.max(alpha, alphaT), beta).getScore();
} }
game.revertMove(); results.add(result);
if (score > alphaT) {
alphaT = score;
} }
if (alphaT >= beta) { pawn.setRow(originalRow);
return new MiniMaxResult(alphaT, pawn.getRow(), pawn.getCol(), movement); pawn.setCol(originalCol);
}
} }
} }
if (lastPawn == null) { // Choisir aléatoirement
return new MiniMaxResult(alphaT, 0, 0, null); int index = random.nextInt(results.size());
} return results.get(index);
return new MiniMaxResult(alphaT, lastPawn.getRow(), lastPawn.getCol(), lastMovement);
} }
private static MiniMaxResult min(MovingBoard game, int depth, int alpha, int beta) { private static int evaluate(Pawn pawn, PusherBoard board) {
int betaT = Integer.MAX_VALUE; int score = didWin(pawn);
MovingPawn lastPawn = null; score = Math.max(score, didCapture(pawn, board));
Pawn.PawnMovement lastMovement = null;
for (MovingPawn pawn : game.getMinPawns()) { return score;
for (Pawn.PawnMovement movement : Pawn.PawnMovement.values()) {
if (!pawn.isMoveValid(game.getBoard(), movement)) {
continue;
} }
lastPawn = pawn; private static int didWin(Pawn pawn) {
lastMovement = movement; int goal = pawn.getPlayer() == Player.RED ? 7 : 0;
game.move(pawn, movement); if (pawn.getRow() == goal) {
return Integer.MAX_VALUE;
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 evaluate(IPawn pawn, MovingBoard game, int depth) {
int score = didWin(pawn) + didCapture(pawn, game);
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; return 0;
} }
private static int didCapture(IPawn pawn, MovingBoard game) { private static int didCapture(Pawn pawn, PusherBoard board) {
IPawn capturedPawn = game.getBoard()[pawn.getRow()][pawn.getCol()]; Pawn capturedPawn = board.getBoard()[pawn.getRow()][pawn.getCol()];
if (capturedPawn != null && capturedPawn.getPlayer() != game.getPlayer()) { if (capturedPawn != null) {
return 500; if (capturedPawn.getPlayer() != pawn.getPlayer()) {
return 50;
}
} }
return 0; return 0;
@ -143,14 +93,12 @@ public class MiniMax {
static class MiniMaxResult { static class MiniMaxResult {
private final int score; private final int score;
private final int row; private final Pawn pawn;
private final int col;
private final Pawn.PawnMovement movement; private final Pawn.PawnMovement movement;
public MiniMaxResult(int score, int row, int col, Pawn.PawnMovement movement) { public MiniMaxResult(int score, Pawn pawn, Pawn.PawnMovement movement) {
this.score = score; this.score = score;
this.row = row; this.pawn = pawn;
this.col = col;
this.movement = movement; this.movement = movement;
} }
@ -158,12 +106,8 @@ public class MiniMax {
return score; return score;
} }
public int getRow() { public Pawn getPawn() {
return row; return pawn;
}
public int getCol() {
return col;
} }
public Pawn.PawnMovement getMovement() { public Pawn.PawnMovement getMovement() {
@ -174,8 +118,7 @@ public class MiniMax {
public String toString() { public String toString() {
return "MiniMaxResult{" + return "MiniMaxResult{" +
"score=" + score + "score=" + score +
", col=" + col + ", pawn=" + pawn +
", row=" + row +
", movement=" + movement + ", movement=" + movement +
'}'; '}';
} }

View File

@ -1,86 +0,0 @@
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;
}
}

View File

@ -1,14 +0,0 @@
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());
}
}

View File

@ -1,25 +0,0 @@
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());
}
}

View File

@ -1,24 +0,0 @@
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());
}
}

View File

@ -1,18 +1,20 @@
package laboratoire4; package laboratoire4;
public abstract class Pawn implements IPawn { public abstract class Pawn {
protected final Player player; protected final Player player;
protected int row; protected int row;
protected int col; protected int col;
protected int direction;
public Pawn(Player player, int row, int col) { public Pawn(Player player, int row, int col) {
this.player = player; this.player = player;
this.row = row; this.row = row;
this.col = col; this.col = col;
this.direction = player == Player.RED ? 1 : -1;
} }
public void move(PawnMovement movement) { public void move(PawnMovement movement) {
setRow(row + player.getDirection()); setRow(row + direction);
setCol(col + movement.move); setCol(col + movement.move);
} }
@ -42,10 +44,12 @@ public abstract class Pawn implements IPawn {
} }
public int getDirection() { public int getDirection() {
return player.getDirection(); return direction;
} }
public boolean isMoveValid(IPawn[][] board, PawnMovement movement) { public boolean isMoveValid(PusherBoard game, PawnMovement movement) {
Pawn[][] board = game.getBoard();
int nextRow = row + getDirection(); int nextRow = row + getDirection();
if (nextRow < 0 || nextRow >= board.length) { if (nextRow < 0 || nextRow >= board.length) {
return false; return false;
@ -56,10 +60,10 @@ public abstract class Pawn implements IPawn {
return false; return false;
} }
return isMoveReallyValid(board, movement); return isMoveValid(board, movement);
} }
protected abstract boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement); protected abstract boolean isMoveValid(Pawn[][] board, PawnMovement movement);
enum PawnMovement { enum PawnMovement {
STRAIGHT(0), STRAIGHT(0),

View File

@ -1,22 +1,6 @@
package laboratoire4; package laboratoire4;
public enum Player { public enum Player {
BLACK(-1, 0), BLACK,
RED(1, 7); RED
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;
}
} }

View File

@ -6,31 +6,29 @@ public class Pushed extends Pawn {
} }
@Override @Override
public boolean isPusher() { public boolean isMoveValid(Pawn[][] board, PawnMovement movement) {
return false; Pawn pusher = null;
} Pawn to = board[row + direction][col + movement.getMove()];
@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) { if (col > 0 && movement == PawnMovement.RIGHT_DIAGONAL) {
pusher = board[row - direction][col - movement.getMove()]; pusher = board[row - direction][col - 1];
} else if (col < board.length - 1 && movement == PawnMovement.LEFT_DIAGONAL) { } else if (col < board.length - 1 && movement == PawnMovement.LEFT_DIAGONAL) {
pusher = board[row - direction][col - movement.getMove()]; pusher = board[row - direction][col + 1];
} else if (movement == PawnMovement.STRAIGHT) { } else if (movement == PawnMovement.STRAIGHT) {
pusher = board[row - direction][col]; pusher = board[row - direction][col];
} }
boolean pusherValid = pusher != null && pusher.isPusher() && pusher.getPlayer() == player; boolean pusherValid = pusher instanceof Pusher;
boolean destinationValid = to == null || (movement != PawnMovement.STRAIGHT && to.getPlayer() != this.player); boolean destinationValid = to == null || to.player != this.player;
return pusherValid && destinationValid; return pusherValid && destinationValid;
} }
@Override @Override
public String toString() { public String toString() {
return String.format("Pushed{%s, %s}", player, getPosition()); return "Pushed{" +
player +
", " + col +
", " + row +
"} ";
} }
} }

View File

@ -6,27 +6,22 @@ public class Pusher extends Pawn {
} }
@Override @Override
public boolean isPusher() { public boolean isMoveValid(Pawn[][] board, PawnMovement movement) {
return true; Pawn to = board[row + direction][col + movement.getMove()];
}
@Override
public boolean isMoveReallyValid(IPawn[][] board, PawnMovement movement) {
IPawn to = board[getRow() + getDirection()][getCol() + movement.getMove()];
if (to == null) { if (to == null) {
return true; return true;
} }
if (to.getPlayer() == player) { return to.player != this.player && movement != PawnMovement.STRAIGHT;
return false;
}
return movement != PawnMovement.STRAIGHT;
} }
@Override @Override
public String toString() { public String toString() {
return String.format("Pusher{%s, %s}", player, getPosition()); return "Pusher{" +
player +
", " + col +
", " + row +
"} ";
} }
} }

View File

@ -1,9 +1,15 @@
package laboratoire4; package laboratoire4;
import java.util.ArrayList;
import java.util.List;
public class PusherBoard { public class PusherBoard {
private final Player player; private final Player player;
private Pawn[][] board; private Pawn[][] board;
private final List<Pawn> maxPawns = new ArrayList<>();
private final List<Pawn> minPawns = new ArrayList<>();
public PusherBoard(Player player, String[] boardValues) { public PusherBoard(Player player, String[] boardValues) {
this.player = player; this.player = player;
@ -25,6 +31,12 @@ public class PusherBoard {
pawn = new Pushed(pawnPlayer, row, col); pawn = new Pushed(pawnPlayer, row, col);
} }
if (pawnPlayer == player) {
maxPawns.add(pawn);
} else {
minPawns.add(pawn);
}
board[row][col] = pawn; board[row][col] = pawn;
} }
@ -38,64 +50,86 @@ public class PusherBoard {
public String runNextMove() { public String runNextMove() {
MiniMax.MiniMaxResult result = MiniMax.miniMax(this); MiniMax.MiniMaxResult result = MiniMax.miniMax(this);
Pawn pawn = board[result.getRow()][result.getCol()]; Pawn pawn = result.getPawn();
System.out.println(result.getScore());
String initialPosition = pawn.getPosition(); String initialPosition = pawn.getPosition();
move(pawn, result.getMovement());
String nextPosition = pawn.getPosition();
return initialPosition + "-" + nextPosition; move(pawn, result.getMovement());
return initialPosition + "-" + pawn.getPosition();
} }
public void move(String move) { public void move(String move) {
//FORMAT ex : D2-D3
String[] split = move.trim().split(" - "); String[] split = move.trim().split(" - ");
String from = split[0]; move(split[0], split[1]);
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);
}
public void move(int row, int col, Pawn.PawnMovement movement) {
Pawn pawn = board[row][col];
if (pawn == null) {
return;
}
move(pawn, movement);
} }
private void move(Pawn pawn, Pawn.PawnMovement movement) { private void move(Pawn pawn, Pawn.PawnMovement movement) {
// if (!pawn.isMoveValid(board, movement)) { move(pawn.getCol(), pawn.getRow(), pawn.getCol() + movement.getMove(), pawn.getRow() + pawn.getDirection());
// return;
// }
int toRow = pawn.getRow() + pawn.getDirection();
int toCol = pawn.getCol() + movement.getMove();
board[pawn.getRow()][pawn.getCol()] = null;
board[toRow][toCol] = pawn;
pawn.move(movement);
} }
public Player getPlayer() { public void move(String from, String to) {
return player; //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.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);
}
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() { public Pawn[][] getBoard() {
return board; return board;
} }
public static void printBoard(Pawn[][] 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 i = 7; i >= 0; i--) {
for (int j = 0; j < board.length; j++) { for (int j = 0; j < this.board.length; j++) {
if (board[i][j] != null) { if (this.board[i][j] != null) {
System.out.print(board[i][j] + " | "); System.out.print(this.board[i][j] + " | ");
} else { } else {
System.out.print(" | "); System.out.print(" | ");
} }