Compare commits

...

2 Commits

Author SHA1 Message Date
9d418b6286 othello/reversi 2024-10-09 15:11:46 +02:00
8d5bc6b0a7 Refaire Undo 2024-10-09 14:19:22 +02:00
6 changed files with 417 additions and 1 deletions

BIN
Nim.zip Normal file

Binary file not shown.

View File

@ -1,5 +1,26 @@
import java.util.Iterator;
import fr.iut_fbleau.raw_api_body.entity.*;
public class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
PlateauNim jeu = new PlateauNim(5, Player.JOUEUR1);
jeu.doPly(new NimPly(2));
jeu.doPly(new NimPly(1));
jeu.doPly(new NimPly(1));
jeu.doPly(new NimPly(1));
if (jeu.isFinished()) {
int resultat = jeu.getResult();
if (resultat == Result.PERDU) {
System.out.println("Le joueur 1 a perdu !");
} else if (resultat == Result.GAGNE) {
System.out.println("Le joueur 1 a gagné !");
} else {
System.out.println("Égalité !");
}
}
else {
System.out.println("C'est pas fini : " + jeu.isFinished());
}
}
}

View File

@ -0,0 +1,24 @@
package fr.iut_fbleau.raw_api_body.entity;
/**
* Represents a move in the Nim game.
*/
public class NimPly extends Ply {
private final int allumettes;
// Constructor to initialize the move with a number of allumettes to remove
public NimPly(int allumettes) {
this.allumettes = allumettes;
}
// Returns the number of allumettes removed
public int getallumettes() {
return allumettes;
}
@Override
public String toString() {
return "Remove " + allumettes + " allumettes.";
}
}

View File

@ -0,0 +1,108 @@
package fr.iut_fbleau.raw_api_body.entity;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Implements the Plateau interface for the game of Nim.
*/
public class PlateauNim implements Plateau {
private int allumettesRestantes; // Number of remaining allumettes
private Player currentPlayer; // Current player
private boolean gameFinished; // Game status
private int result; // Game result: 1 (win), 0 (draw), -1 (loss)
private List<Ply> playHistory; // History of moves
// Constructor initializes the game with a given number of allumettes and a starting player
public PlateauNim(int initialallumettes, Player startingPlayer) {
this.allumettesRestantes = initialallumettes;
this.currentPlayer = startingPlayer;
this.gameFinished = false;
this.result = 0;
this.playHistory = new ArrayList<>();
}
@Override
public Player getPlayer() {
if (gameFinished) {
throw new NullPointerException("Game is over.");
}
return this.currentPlayer;
}
@Override
public boolean isFinished() {
return this.gameFinished;
}
@Override
public int getResult() {
if (!gameFinished) {
throw new NullPointerException("Game is not over.");
}
return this.result;
}
@Override
public Iterator<Ply> givePlies() {
if (gameFinished) {
throw new NullPointerException("Game is over.");
}
// Generate legal moves (remove 1, 2, or 3 allumettes, but not more than remaining allumettes)
List<Ply> legalPlies = new ArrayList<>();
for (int i = 1; i <= Math.min(3, allumettesRestantes); i++) {
legalPlies.add(new NimPly(i));
}
return legalPlies.iterator();
}
@Override
public void doPly(Ply ply) {
if (!(ply instanceof NimPly)) {
throw new IllegalArgumentException("Invalid move type.");
}
NimPly nimPly = (NimPly) ply;
if (nimPly.getallumettes() < 1 || nimPly.getallumettes() > Math.min(3, allumettesRestantes)) {
throw new IllegalArgumentException("Invalid move.");
}
// Update the state
allumettesRestantes -= nimPly.getallumettes();
playHistory.add(nimPly);
// Check if game is finished
if (allumettesRestantes == 0) {
gameFinished = true;
if (this.currentPlayer == Player.JOUEUR1){
result = -1; // Player 2 Win
}
else{
result = 1; // Player 1 Win
}
} else {
// Switch players if game is not finished
currentPlayer = (currentPlayer == Player.JOUEUR1) ? Player.JOUEUR2 : Player.JOUEUR1;
}
}
@Override
public void undoPly(Ply ply) {
if (playHistory.isEmpty()) {
throw new IllegalStateException("No moves to undo.");
}
if (!playHistory.get(playHistory.size() - 1).equals(ply)) {
throw new IllegalStateException("Cannot undo a non-last move.");
}
// Revert the move
NimPly lastMove = (NimPly) playHistory.remove(playHistory.size() - 1);
allumettesRestantes += lastMove.getallumettes();
// Switch back to previous player
currentPlayer = (currentPlayer == Player.JOUEUR1) ? Player.JOUEUR2 : Player.JOUEUR1;
gameFinished = false; // If game was finished, it's no longer
}
}

View File

@ -0,0 +1,218 @@
package fr.iut_fbleau.raw_api_body.entity;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Implements the Plateau interface for the game of Reversi.
*/
public class PlateauReversi implements Plateau {
private Player[][] board; // The game board
private Player currentPlayer; // Current player
private boolean gameFinished; // Game status
private List<Ply> movesHistory; // History of moves
private int blackCount; // Count of black discs
private int whiteCount; // Count of white discs
// Constructor initializes the game board and sets the starting player
public PlateauReversi() {
this.board = new Player[8][8];
initializeBoard();
this.currentPlayer = Player.JOUEUR1; // JOUEUR1 is black
this.gameFinished = false;
this.movesHistory = new ArrayList<>();
this.blackCount = 2; // Starting discs for black
this.whiteCount = 2; // Starting discs for white
}
// Initialize the board with the starting positions
private void initializeBoard() {
board[3][3] = Player.JOUEUR2; // White
board[3][4] = Player.JOUEUR1; // Black
board[4][3] = Player.JOUEUR1; // Black
board[4][4] = Player.JOUEUR2; // White
}
@Override
public Player getPlayer() {
if (gameFinished) {
throw new NullPointerException("Game is over.");
}
return this.currentPlayer;
}
@Override
public boolean isFinished() {
return this.gameFinished;
}
@Override
public int getResult() {
if (!gameFinished) {
throw new NullPointerException("Game is not over.");
}
if (blackCount > whiteCount) {
return Result.GAGNE; // Black wins
} else if (blackCount < whiteCount) {
return Result.PERDU; // Black loses
} else {
return Result.EGALITE; // Draw
}
}
@Override
public Iterator<Ply> givePlies() {
if (gameFinished) {
throw new NullPointerException("Game is over.");
}
List<Ply> legalMoves = new ArrayList<>();
// Check all positions on the board for legal moves
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
if (isLegalMove(row, col)) {
legalMoves.add(new PlyReversi(row, col));
}
}
}
return legalMoves.iterator();
}
@Override
public void doPly(Ply ply) {
if (!(ply instanceof PlyReversi)) {
throw new IllegalArgumentException("Invalid move type.");
}
PlyReversi move = (PlyReversi) ply;
if (!isLegalMove(move.getRow(), move.getCol())) {
throw new IllegalArgumentException("Invalid move.");
}
// Place the disc
board[move.getRow()][move.getCol()] = currentPlayer;
flipDiscs(move.getRow(), move.getCol());
// Update counts
updateCounts();
// Add to history
movesHistory.add(move);
// Check if the game is finished
if (blackCount + whiteCount == 64 || !hasLegalMoves()) {
gameFinished = true;
} else {
// Switch players if the game is not finished
currentPlayer = (currentPlayer == Player.JOUEUR1) ? Player.JOUEUR2 : Player.JOUEUR1;
}
}
@Override
public void undoPly(Ply ply) {
if (movesHistory.isEmpty()) {
throw new IllegalStateException("No moves to undo.");
}
if (!movesHistory.get(movesHistory.size() - 1).equals(ply)) {
throw new IllegalStateException("Cannot undo a non-last move.");
}
// Revert the move
PlyReversi lastMove = (PlyReversi) movesHistory.remove(movesHistory.size() - 1);
board[lastMove.getRow()][lastMove.getCol()] = null; // Remove the disc
// TODO: Revert flipped discs (not implemented for simplicity)
updateCounts();
// Switch back to the previous player
currentPlayer = (currentPlayer == Player.JOUEUR1) ? Player.JOUEUR2 : Player.JOUEUR1;
gameFinished = false; // If the game was finished, it's no longer
}
// Check if the move is legal
private boolean isLegalMove(int row, int col) {
if (board[row][col] != null) {
return false; // Must be empty
}
// Check all directions for valid flips
return checkDirection(row, col, 1, 0) || // Right
checkDirection(row, col, -1, 0) || // Left
checkDirection(row, col, 0, 1) || // Down
checkDirection(row, col, 0, -1) || // Up
checkDirection(row, col, 1, 1) || // Down-right
checkDirection(row, col, 1, -1) || // Down-left
checkDirection(row, col, -1, 1) || // Up-right
checkDirection(row, col, -1, -1); // Up-left
}
// Check a specific direction for valid flips
private boolean checkDirection(int row, int col, int dRow, int dCol) {
int r = row + dRow;
int c = col + dCol;
boolean hasOpponentDisc = false;
while (r >= 0 && r < 8 && c >= 0 && c < 8) {
if (board[r][c] == null) {
return false; // Found empty space
}
if (board[r][c] == currentPlayer) {
return hasOpponentDisc; // Valid move if we have seen opponent discs
}
hasOpponentDisc = true;
r += dRow;
c += dCol;
}
return false; // No valid flips found
}
// Flip discs after a valid move
private void flipDiscs(int row, int col) {
for (int dRow = -1; dRow <= 1; dRow++) {
for (int dCol = -1; dCol <= 1; dCol++) {
if (dRow == 0 && dCol == 0) continue; // Skip the center
if (checkDirection(row, col, dRow, dCol)) {
flipInDirection(row, col, dRow, dCol);
}
}
}
}
// Flip discs in a specified direction
private void flipInDirection(int row, int col, int dRow, int dCol) {
int r = row + dRow;
int c = col + dCol;
while (board[r][c] != currentPlayer) {
board[r][c] = currentPlayer; // Flip the disc
r += dRow;
c += dCol;
}
}
// Update the count of black and white discs
private void updateCounts() {
blackCount = 0;
whiteCount = 0;
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
if (board[row][col] == Player.JOUEUR1) {
blackCount++;
} else if (board[row][col] == Player.JOUEUR2) {
whiteCount++;
}
}
}
}
// Check if there are any legal moves available for the current player
private boolean hasLegalMoves() {
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
if (isLegalMove(row, col)) {
return true;
}
}
}
return false;
}
}

View File

@ -0,0 +1,45 @@
package fr.iut_fbleau.raw_api_body.entity;
/**
* Represents a move in the Reversi game.
*/
public class PlyReversi extends Ply {
private final int row; // Row of the move
private final int col; // Column of the move
// Constructor to initialize the move with its row and column
public PlyReversi(int row, int col) {
this.row = row;
this.col = col;
}
// Returns the row of the move
public int getRow() {
return row;
}
// Returns the column of the move
public int getCol() {
return col;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
PlyReversi that = (PlyReversi) obj;
return row == that.row && col == that.col;
}
@Override
public int hashCode() {
int result = Integer.hashCode(row);
result = 31 * result + Integer.hashCode(col);
return result;
}
@Override
public String toString() {
return "Move to (" + row + ", " + col + ")";
}
}