diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 4910537..854915f 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,13 +4,24 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -31,6 +42,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -52,20 +91,21 @@
- {
- "keyToString": {
- "RunOnceActivity.OpenProjectViewOnStart": "true",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "SHARE_PROJECT_CONFIGURATION_FILES": "true",
- "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"
+
-
+}]]>
+
@@ -79,8 +119,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -96,7 +164,9 @@
-
+
+
+
1679263366439
@@ -105,7 +175,14 @@
1679263366439
-
+
+ 1679348475071
+
+
+
+ 1679348475071
+
+
@@ -113,6 +190,7 @@
-
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index bf36b1a..848b6ab 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,8 +9,8 @@
1.0-SNAPSHOT
- 18
- 18
+ 11
+ 11
UTF-8
diff --git a/src/main/java/laboratoire4/Client.java b/src/main/java/laboratoire4/Client.java
index 1fdba45..8ee65da 100644
--- a/src/main/java/laboratoire4/Client.java
+++ b/src/main/java/laboratoire4/Client.java
@@ -1,124 +1,97 @@
package laboratoire4;
-import java.io.*;
-import java.net.*;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.net.Socket;
-class Client {
- public static void main(String[] args) {
+public class Client {
+ private final Socket socket;
+ private final BufferedInputStream input;
+ private final BufferedOutputStream output;
+ private PusherBoard board;
- Socket MyClient;
- BufferedInputStream input;
- BufferedOutputStream output;
- int[][] board = new int[8][8];
+ public Client(String host, int port) throws IOException {
+ socket = new Socket(host, port);
+ input = new BufferedInputStream(socket.getInputStream());
+ output = new BufferedOutputStream(socket.getOutputStream());
+ }
+ public void listen() {
try {
- MyClient = new Socket("localhost", 8888);
+ while (true) {
+ char cmd;
+ cmd = (char) input.read();
- input = new BufferedInputStream(MyClient.getInputStream());
- output = new BufferedOutputStream(MyClient.getOutputStream());
- BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
- while(1 == 1){
- char cmd = 0;
-
- cmd = (char)input.read();
- System.out.println(cmd);
- // Debut de la partie en joueur blanc
- if(cmd == '1'){
- byte[] aBuffer = new byte[1024];
-
- int size = input.available();
- //System.out.println("size " + size);
- input.read(aBuffer,0,size);
- String s = new String(aBuffer).trim();
- System.out.println(s);
- String[] boardValues;
- boardValues = s.split(" ");
- int x=0,y=0;
- for(int i=0; i 0) {
+ input.read(aBuffer, 0, size);
+ String previousMove = new String(aBuffer);
+ System.out.println("Mouvement reçu: " + previousMove);
+
+ board.move(previousMove);
}
+ String nextMove = board.runNextMove();
+ System.out.println("Prochain mouvement: " + nextMove);
+
+ output.write(nextMove.getBytes(), 0, nextMove.length());
+ output.flush();
+ }
+
+ private void handleInvalidMove() throws InterruptedException {
+ System.err.println("Mouvement invalide!");
+ Thread.sleep(500);
+ board.printBoard();
+ }
+
+ private void stopGame() throws IOException {
+ System.out.println("GG well played!");
+ socket.close();
}
}
diff --git a/src/main/java/laboratoire4/GameTree.java b/src/main/java/laboratoire4/GameTree.java
index e48283c..48c31d4 100644
--- a/src/main/java/laboratoire4/GameTree.java
+++ b/src/main/java/laboratoire4/GameTree.java
@@ -23,6 +23,14 @@ public class GameTree {
public Collection getChilds() {
return childs;
}
+
+ public Pawn getPawn() {
+ return pawn;
+ }
+
+ public Pawn.PawnMovement getMovement() {
+ return movement;
+ }
}
}
diff --git a/src/main/java/laboratoire4/Main.java b/src/main/java/laboratoire4/Main.java
new file mode 100644
index 0000000..b27a322
--- /dev/null
+++ b/src/main/java/laboratoire4/Main.java
@@ -0,0 +1,9 @@
+package laboratoire4;
+
+import java.io.IOException;
+
+public class Main {
+ public static void main(String[] args) throws IOException {
+ new Client("localhost", 8888).listen();
+ }
+}
diff --git a/src/main/java/laboratoire4/MiniMax.java b/src/main/java/laboratoire4/MiniMax.java
index e3cab45..6503a31 100644
--- a/src/main/java/laboratoire4/MiniMax.java
+++ b/src/main/java/laboratoire4/MiniMax.java
@@ -1,50 +1,71 @@
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();
- public static int miniMax(GameTree tree) {
- return miniMax(tree.getRoot(), Player.MAX, 0);
+ public static MiniMaxResult miniMax(PusherBoard board) {
+ return miniMax(board, true, 0, Integer.MIN_VALUE);
}
- private static int miniMax(GameTree.Node node, Player player, int depth) {
- if (depth == MAX_DEPTH) {
- return evaluate(node);
- }
+ private static MiniMaxResult miniMax(PusherBoard board, boolean max, int depth, int alphaBeta) {
+ int limScore = max ? Integer.MIN_VALUE : Integer.MAX_VALUE;
+ List pawns = max ?
+ board.getMaxPawns() :
+ board.getMinPawns();
- return player == Player.MAX ?
- max(node, depth) :
- min(node, depth);
- }
+ List results = new ArrayList<>();
- private static int max(GameTree.Node node, int depth) {
- int maxScore = Integer.MIN_VALUE;
+ for (Pawn pawn : pawns) {
+ int originalRow = pawn.getRow();
+ int originalCol = pawn.getCol();
- for (GameTree.Node child : node.getChilds()) {
- int score = miniMax(child, Player.MIN, depth + 1);
- if (score > maxScore) {
- maxScore = score;
+ 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);
+ }
+
+ pawn.setRow(originalRow);
+ pawn.setCol(originalCol);
}
}
- return maxScore;
+ // Choisir aléatoirement
+ int index = random.nextInt(results.size());
+ return results.get(index);
}
- private static int min(GameTree.Node node, int depth) {
- int minScore = Integer.MAX_VALUE;
+ private static int evaluate(Pawn pawn, PusherBoard board) {
+ int score = didWin(pawn);
+ score = Math.max(score, didCapture(pawn, board));
- for (GameTree.Node child : node.getChilds()) {
- int score = miniMax(child, Player.MIN, depth + 1);
- if (score < minScore) {
- minScore = score;
- }
- }
-
- return minScore;
- }
-
- private static int evaluate(GameTree.Node node) {
-
- return 0;
+ return score;
}
}
diff --git a/src/main/java/laboratoire4/Pawn.java b/src/main/java/laboratoire4/Pawn.java
index ddb9768..bd6b8d9 100644
--- a/src/main/java/laboratoire4/Pawn.java
+++ b/src/main/java/laboratoire4/Pawn.java
@@ -1,18 +1,30 @@
package laboratoire4;
public abstract class Pawn {
- protected final PawnColor color;
- protected int col;
+ protected final Player player;
protected int row;
+ protected int col;
+ protected int direction;
- public Pawn(PawnColor color, int col, int row) {
- this.color = color;
- this.col = col;
+ 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 PawnColor getColor() {
- return color;
+ public void move(PawnMovement movement) {
+ setRow(row + direction);
+ setCol(col + movement.move);
+ }
+
+ public String getPosition() {
+ char colStr = (char)(col + 65);
+ return String.format("%s%d", colStr, row + 1);
+ }
+
+ public Player getPlayer() {
+ return player;
}
public int getCol() {
@@ -31,13 +43,28 @@ public abstract class Pawn {
this.row = row;
}
- public abstract boolean isMoveValid(PusherBoard board, PawnMovement movement);
-
- enum PawnColor {
- RED,
- BLACK
+ public int getDirection() {
+ return direction;
}
+ public boolean isMoveValid(PusherBoard game, PawnMovement movement) {
+ Pawn[][] board = game.getBoard();
+
+ int nextRow = row + getDirection();
+ if (nextRow < 0 || nextRow >= board.length) {
+ return false;
+ }
+
+ int nextCol = col + movement.move;
+ if (nextCol < 0 || nextCol >= board.length) {
+ return false;
+ }
+
+ return isMoveValid(board, movement);
+ }
+
+ protected abstract boolean isMoveValid(Pawn[][] board, PawnMovement movement);
+
enum PawnMovement {
STRAIGHT(0),
LEFT_DIAGONAL(-1),
@@ -52,5 +79,15 @@ public abstract class Pawn {
public int getMove() {
return move;
}
+
+ public static PawnMovement from(int move) {
+ if (move == 0) {
+ return STRAIGHT;
+ }
+ if (move == 1) {
+ return RIGHT_DIAGONAL;
+ }
+ return LEFT_DIAGONAL;
+ }
}
}
diff --git a/src/main/java/laboratoire4/Player.java b/src/main/java/laboratoire4/Player.java
index 99a2b53..a94952b 100644
--- a/src/main/java/laboratoire4/Player.java
+++ b/src/main/java/laboratoire4/Player.java
@@ -1,6 +1,6 @@
package laboratoire4;
public enum Player {
- MIN,
- MAX
+ BLACK,
+ RED
}
diff --git a/src/main/java/laboratoire4/Pushed.java b/src/main/java/laboratoire4/Pushed.java
index 3438101..927c490 100644
--- a/src/main/java/laboratoire4/Pushed.java
+++ b/src/main/java/laboratoire4/Pushed.java
@@ -1,26 +1,34 @@
package laboratoire4;
public class Pushed extends Pawn {
- public Pushed(PawnColor color, int col, int row) {
- super(color, col, row);
+ public Pushed(Player player, int row, int col) {
+ super(player, row, col);
}
@Override
- public boolean isMoveValid(PusherBoard game, PawnMovement movement) {
- Pawn[][] board = game.getBoard();
+ public boolean isMoveValid(Pawn[][] board, PawnMovement movement) {
Pawn pusher = null;
- Pawn to = board[row + 1][col + movement.getMove()];
+ Pawn to = board[row + direction][col + movement.getMove()];
if (col > 0 && movement == PawnMovement.RIGHT_DIAGONAL) {
- pusher = board[row - 1][col - 1];
+ pusher = board[row - direction][col - 1];
} else if (col < board.length - 1 && movement == PawnMovement.LEFT_DIAGONAL) {
- pusher = board[row - 1][col + 1];
+ pusher = board[row - direction][col + 1];
} else if (movement == PawnMovement.STRAIGHT) {
- pusher = board[row - 1][col];
+ pusher = board[row - direction][col];
}
- boolean pusherValid = pusher != null;
- boolean destinationValid = to == null || to.color != this.color;
+ boolean pusherValid = pusher instanceof Pusher;
+ boolean destinationValid = to == null || to.player != this.player;
return pusherValid && destinationValid;
}
+
+ @Override
+ public String toString() {
+ return "Pushed{" +
+ player +
+ ", " + col +
+ ", " + row +
+ "} ";
+ }
}
diff --git a/src/main/java/laboratoire4/Pusher.java b/src/main/java/laboratoire4/Pusher.java
index 2fb430c..01e4fbc 100644
--- a/src/main/java/laboratoire4/Pusher.java
+++ b/src/main/java/laboratoire4/Pusher.java
@@ -1,14 +1,27 @@
package laboratoire4;
public class Pusher extends Pawn {
- public Pusher(PawnColor color, int col, int row) {
- super(color, col, row);
+ public Pusher(Player player, int row, int col) {
+ super(player, row, col);
}
@Override
- public boolean isMoveValid(PusherBoard game, PawnMovement movement) {
- Pawn to = game.getBoard()[row + 1][col + movement.getMove()];
+ public boolean isMoveValid(Pawn[][] board, PawnMovement movement) {
+ Pawn to = board[row + direction][col + movement.getMove()];
- return to == null || to.color != this.color;
+ if (to == null) {
+ return true;
+ }
+
+ return to.player != this.player && movement != PawnMovement.STRAIGHT;
+ }
+
+ @Override
+ public String toString() {
+ return "Pusher{" +
+ player +
+ ", " + col +
+ ", " + row +
+ "} ";
}
}
diff --git a/src/main/java/laboratoire4/PusherBoard.java b/src/main/java/laboratoire4/PusherBoard.java
index 338ab22..b2ebf07 100644
--- a/src/main/java/laboratoire4/PusherBoard.java
+++ b/src/main/java/laboratoire4/PusherBoard.java
@@ -1,130 +1,137 @@
package laboratoire4;
+import java.util.ArrayList;
+import java.util.List;
+
public class PusherBoard {
+ private final Player player;
private Pawn[][] board;
- public PusherBoard() {
- this.newGame();
+ private final List maxPawns = new ArrayList<>();
+ private final List minPawns = new ArrayList<>();
+
+ public PusherBoard(Player player, String[] boardValues) {
+ this.player = player;
+
+ newGame(boardValues);
}
- public void newGame() {
+ public void newGame(String[] boardValues) {
this.board = new Pawn[8][8];
- // TODO: Construire depuis le serveur
- for (int i = 0; i < board.length; i++) {
- for (int j = 0; j < board.length; j++) {
- Pawn pawn = null;
- Pawn.PawnColor color = i < board.length / 2 ?
- Pawn.PawnColor.RED :
- Pawn.PawnColor.BLACK;
-
- if (i == 0 || i == board.length - 1) {
- pawn = new Pusher(color, i, j);
- } else if (i == 1 || i == board.length - 2) {
- pawn = new Pushed(color, i, j);
+ int col = 0, row = 0;
+ for (String boardValue : boardValues) {
+ int v = Integer.parseInt(boardValue);
+ if (v != 0) {
+ Player pawnPlayer = (v == 1 || v == 2) ? Player.RED : Player.BLACK;
+ Pawn pawn;
+ if (v % 2 == 0) { // 2 et 4 sont les pushers
+ pawn = new Pusher(pawnPlayer, row, col);
+ } else {
+ pawn = new Pushed(pawnPlayer, row, col);
}
- board[i][j] = pawn;
+ if (pawnPlayer == player) {
+ maxPawns.add(pawn);
+ } else {
+ minPawns.add(pawn);
+ }
+
+ board[row][col] = pawn;
+ }
+
+ col++;
+ if (col == board.length) {
+ col = 0;
+ row++;
}
}
}
- public int move(String move) {
- //FORMAT ex : D2-D3
- String[] split = move.split("-");
+ public String runNextMove() {
+ MiniMax.MiniMaxResult result = MiniMax.miniMax(this);
+ Pawn pawn = result.getPawn();
+ String initialPosition = pawn.getPosition();
- return move(split[0], split[1]);
+ move(pawn, result.getMovement());
+
+ return initialPosition + "-" + pawn.getPosition();
}
- public int move(String from, String to) {
+ public void move(String move) {
+ //FORMAT ex : D2-D3
+ String[] split = move.trim().split(" - ");
+ move(split[0], split[1]);
+ }
+
+ private void move(Pawn pawn, Pawn.PawnMovement movement) {
+ move(pawn.getCol(), pawn.getRow(), pawn.getCol() + movement.getMove(), pawn.getRow() + pawn.getDirection());
+ }
+
+ public void move(String from, String to) {
//FORMAT ex : from {D2}, to {D3}
int from_col = (int) from.charAt(0) - 65;
int from_row = Integer.parseInt(String.valueOf(from.charAt(1))) - 1;
int to_col = (int) to.charAt(0) - 65;
int to_row = Integer.parseInt(String.valueOf(to.charAt(1))) - 1;
- return move(from_col, from_row, to_col, to_row);
+ move(from_col, from_row, to_col, to_row);
}
- public int move(int from_col, int from_row, int to_col, int to_row) {
- //FORMAT ex : from_col {3}, from_row {2}, to_col {3}, to_row {3}
-
- //System.out.println("Move :" + from_col+""+from_row + "-"+ to_col+""+to_row);
- //System.out.println("Move is valid : " + isValid(from_col,from_row,to_col,to_row));
-
- if (isValid(from_col, from_row, to_col, to_row)) {
- Pawn pawn = this.getBoard()[from_row][from_col];
- //System.out.println("Pawn to move : " + pawn);
- this.getBoard()[from_row][from_col] = null;
- this.getBoard()[to_row][to_col] = pawn;
+ public void move(int from_col, int from_row, int to_col, int to_row) {
+ if (!isValid(from_col, from_row, to_col)) {
+ return;
}
- return -1;
+ 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, int to_row) {
- Pawn[][] board = this.getBoard();
+ 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);
- //out of bound?
- if ((from_col > 7 || from_col < 0) || ((from_row > 7 || from_row < 0)) || ((to_col > 7 || to_col < 0)) || ((to_row > 7 || to_row < 0)))
+ if (pawn == null) {
return false;
-
- //no pawn to move?
- Pawn pawnToMove = board[from_row][from_col];
- if (pawnToMove == null) return false;
-
- //Pawn at destination is our own pawn?
- Pawn destination = board[to_row][to_col];
- char source_color = pawnToMove.name().charAt(0);
- if (destination != null) {
- char destination_color = destination.name().charAt(0);
-
- if (source_color == destination_color) return false;
}
- //Pawn goes back? or move is in valid range?
- if (source_color == 'R') {
- if (from_row > to_row) return false;
- if (from_row + 1 != to_row) return false;
- } else if (source_color == 'B') {
- if (from_row < to_row) return false;
- if (from_row - 1 != to_row) return false;
- }
-
- //PUSHED is in front a PUSHER?
- if (pawnToMove.equals(Pawn.B_PUSHED)) {
- if (from_col + 1 == to_col) {
- return board[from_row + 1][from_col + 1] == Pawn.B_PUSHER;
- } else if (from_col - 1 == to_col) {
- return board[from_row - 1][from_col + 1] == Pawn.B_PUSHER;
- } else if (from_col == to_col) {
- return board[from_row + 1][from_col] == Pawn.B_PUSHER;
- }
- } else if (pawnToMove.equals(Pawn.R_PUSHED)) {
- if (from_col + 1 == to_col) {
- return board[from_row + 1][from_col - 1] == Pawn.R_PUSHER;
- } else if (from_col - 1 == to_col) {
- return board[from_row - 1][from_col - 1] == Pawn.R_PUSHER;
- } else if (from_col == to_col) {
- return board[from_row - 1][from_col] == Pawn.R_PUSHER;
- }
- }
-
- return true;
+ return pawn.isMoveValid(this, move);
}
public Pawn[][] getBoard() {
return board;
}
+ public List getMaxPawns() {
+ return maxPawns;
+ }
+
+ public List getMinPawns() {
+ return minPawns;
+ }
+
public void printBoard() {
for (int i = 7; i >= 0; i--) {
for (int j = 0; j < this.board.length; j++) {
if (this.board[i][j] != null) {
System.out.print(this.board[i][j] + " | ");
} else {
- System.out.print(" | ");
+ System.out.print(" | ");
}
}
System.out.println();
diff --git a/src/main/java/laboratoire4/Test.java b/src/main/java/laboratoire4/Test.java
deleted file mode 100644
index f560894..0000000
--- a/src/main/java/laboratoire4/Test.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package laboratoire4;
-
-public class Test {
- public static void main(String[] args) {
- PusherBoard pusherBoard = new PusherBoard();
- testMoves(pusherBoard);
- pusherBoard.printBoard();
- }
-
- private static void testMoves(PusherBoard pusherBoard){
- //Move examples
- pusherBoard.move("D2","D3");
- pusherBoard.move("C2","C3");
- pusherBoard.move("D1","D2");
- pusherBoard.move("D2","E3");
- pusherBoard.move("C1","C2");
- pusherBoard.move("E3","D4");
-
- pusherBoard.move("A5","A6");
- pusherBoard.move("D2","D1");
- pusherBoard.move("H8","H9");
- pusherBoard.move("A1","A3");
- pusherBoard.move("A1","A2");
- pusherBoard.move("A8","A6");
- pusherBoard.move("A8","A7");
- pusherBoard.move("D3","D4");
- pusherBoard.move("C3","D4");
- }
-}
diff --git a/src/main/java/laboratoire4/TestPusherBoard.java b/src/main/java/laboratoire4/TestPusherBoard.java
deleted file mode 100644
index 8a6cde9..0000000
--- a/src/main/java/laboratoire4/TestPusherBoard.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package laboratoire4;
-
-import org.junit.Test;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-class TestPusherBoard {
-
- private Method getIsValidMethod() throws NoSuchMethodException {
- Method method = PusherBoard.class.getDeclaredMethod("isValid", int.class, int.class, int.class, int.class);
- method.setAccessible(true);
- return method;
- }
-
- @Test
- public void moveValidation() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
- PusherBoard pusherBoard = new PusherBoard();
-
- //Move examples
-
- assertEquals(true, getIsValidMethod().invoke(null, null, new Integer[] { 3,2,3,3 }));
-// assertEquals(true,pusherBoard.move("C2","C3"));
-// assertEquals(true,pusherBoard.move("D1","D3"));
-// assertEquals(true,pusherBoard.move("D2","E3"));
- }
-}