import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.Random; public class GomokuGame { public static final int DEFAULT_BOARD_WIDTH = 15; // largeur du plateau public static final int DEFAULT_BOARD_HEIGHT = 15; // hauteur du plateau public static final int DEFAULT_TOKENS_COUNT = 60; // nb de jetons public static final int NB_CELL_PLAY = 5; // nb de jetons private Player player1; private Player player2; private Player currentPlayer; private GomokuBoard board; private GomokuRenderer renderer; private boolean playRenderer= true; Color colorP1; int currentPlayerInt; Coordinate cellCoor = null; public static void main(String[] args) { // Test GomokuGame g = new GomokuGame(); System.out.println(g.load(Path.of(".cache/test.dat"))); g.renderer = new ConsoleRenderer(); g.renderer.init(g); g.renderer.update(); g.board.expandBoard(Cardinal.SE); g.renderer.update(); } public void newGame(boolean bot, String name1, String name2, int tokens) { Color[] possible = { Color.WHITE, Color.BLACK }; int rnd = new Random().nextInt(possible.length); Color colorPlayer1 = possible[rnd]; Color colorPlayer2 = colorPlayer1.inverse(); this.player1 = new Human(name1, colorPlayer1, tokens); if (bot) { this.player2 = new GomokuAI(name2, colorPlayer2, tokens); } else { this.player2 = new Human(name2, colorPlayer2, tokens); } this.board = new GomokuBoard(15, 15); this.colorP1 = colorPlayer1; currentPlayer = this.player1.color == Color.WHITE ? this.player1: this.player2; this.currentPlayerInt = this.player1.color == Color.WHITE ? 1 : 2; this.renderer = new SwingRenderer(); } public void startGame() { /* GomokuCell actualPlayedCell = play(player1); if( NB_CELL_PLAY <= board.countMax(board.countAlignedCells(actualPlayedCell))) { System.out.println("c'est gangée !"); } */ while(this.player1.tokens > 0 || this.player2.tokens > 0){ GomokuCell currentPlay = null; while (currentPlay == null) { currentPlay = this.play(this.currentPlayer); } if( NB_CELL_PLAY <= board.countMax(board.countAlignedCells(currentPlay))) { this.renderer.updateStatus("Le joueur " + this.currentPlayer + "a gagné !"); return; } this.currentPlayer = this.nextPlayer(); } this.renderer.updateStatus("Match nul, il ne reste plus de jeton."); return; } /** * Place the token on the cell where the player play. * @param Player get player to play the cell. */ public GomokuCell play(Player player) { GomokuCell cellToPlay = null; if (this.playRenderer){ // If we play the game with the renderer. while (this.cellCoor == null) { try{ wait(16); } catch(InterruptedException e){ this.save(null); System.out.println(e); } } cellToPlay= this.board.get(this.cellCoor.x, this.cellCoor.y); if (!cellToPlay.isPlayable()) { // If the cell is not playable we return null to not play. return null; } cellToPlay.setState(player.color); this.cellCoor = null; } else{ cellToPlay = player.chooseMove(board); cellToPlay.setState(player.color); } return cellToPlay; } public boolean save(Path filename) { // save the game state to the file // 1. Open the file // 2. Write the first line with: // w h colorP1 currentPlayerInt nbTokens1 nbTokens2 // 3. Write the next h lines with the board // 4. Close the file // 5. Return true if successful, false otherwise // if filename is null, save to default file in ".cache/save.dat" if (filename == null) { filename = Path.of(".cache/save.dat"); } try (BufferedWriter writer = Files.newBufferedWriter(filename)) { // Write the first line writer.write(String.format("%d %d %s %d %d %d%n", this.getBoard().getWidth(), this.getBoard().getHeight(), colorP1, currentPlayerInt, this.player1.tokens, this.player2.tokens )); // Write the board for (int i = 0; i < this.getBoard().getHeight(); ++i) { for (int j = 0; j < this.getBoard().getWidth(); ++j) { char c; switch (board.get(i, j).getState()) { case BLACK: c = 'X'; break; case WHITE: c = 'O'; break; case NIL: c = '.'; break; default: throw new IllegalStateException( String.format("Unexpected value at cell (%d, %d): %s", i, j, board.get(i, j).getState())); } writer.write(c); } writer.newLine(); } } catch (IOException e) { System.err.println("Error writing file: " + e.getMessage()); return false; } catch (Exception e) { System.err.println("Unexpected error: " + e.getMessage()); return false; } return true; } public boolean load(Path filename) { // load the game state from the file // 1. Open the file // 2. Read the first line to get: // w h colorP1 currentPlayerInt nbTokens1 nbTokens2 // 3. Read the next h lines to get the board // 4. Close the file // 5. Initialize the board with the read values int w, h; Color[][] colors; try (BufferedReader reader = Files.newBufferedReader(filename)) { String line = reader.readLine(); if (line == null) { throw new IOException("Empty save file"); } String[] parts = line.split(" "); if (parts.length != 6) { throw new IOException("Invalid save file format"); } w = Integer.parseInt(parts[0]); h = Integer.parseInt(parts[1]); colorP1 = Color.valueOf(parts[2]); currentPlayerInt = Integer.parseInt(parts[3]); this.player1.tokens = Integer.parseInt(parts[4]); this.player2.tokens = Integer.parseInt(parts[5]); if (w <= 0 || h <= 0) { throw new IllegalArgumentException("Invalid board dimensions"); } colors = new Color[h][w]; for (int i = 0; i < h; ++i) { line = reader.readLine(); if (line == null) { throw new IOException("Unexpected end of file"); } if (line.length() != w) { throw new IOException("Invalid board line format"); } for (int j = 0; j < w; ++j) { switch (line.charAt(j)) { case 'X': colors[i][j] = Color.BLACK; break; case 'O': colors[i][j] = Color.WHITE; break; case '.': colors[i][j] = Color.NIL; break; default: throw new IllegalArgumentException("Invalid color: " + line.charAt(j)); } } } } catch (IOException e) { System.err.println("Error reading file: " + e.getMessage()); return false; } catch (NumberFormatException e) { System.err.println("Invalid number format: " + e.getMessage()); return false; } catch (IllegalArgumentException e) { System.err.println("Invalid color format: " + e.getMessage()); return false; } catch (Exception e) { System.err.println("Unexpected error: " + e.getMessage()); return false; } // Initialize the board with the read values this.board = new GomokuBoard(w, h, colors); return true; } private Player nextPlayer(){ if (this.currentPlayer == this.player1){ return this.player2; } return player1; } public GomokuBoard getBoard() { return this.board; } }