Compare commits

...

4 Commits

Author SHA1 Message Date
william bd0fc7edfd Fixes? 2023-03-24 14:36:13 -04:00
william 0b528baa8b AI 2023-03-22 10:15:27 -04:00
william 39051a8fdd Small fixes 2023-03-22 09:01:39 -04:00
William Nolin 0ff8d6f057 Merge pull request 'william' (#1) from william into master
Reviewed-on: #1
2023-03-21 18:08:13 -04:00
14 changed files with 428 additions and 226 deletions

View File

@ -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>

View File

@ -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">{
&quot;keyToString&quot;: {
&quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
&quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
&quot;SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;,
&quot;codeWithMe.voiceChat.enabledByDefault&quot;: &quot;false&quot;,
&quot;last_opened_file_path&quot;: &quot;/home/william/Dev/Projects&quot;,
&quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
&quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
&quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
&quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
&quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
&quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
}
}]]></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>

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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 +
'}';
}

View File

@ -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;
}
}

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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),

View File

@ -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;
}
}

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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();