main game
This commit is contained in:
371
\
Normal file
371
\
Normal file
@@ -0,0 +1,371 @@
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Random;
|
||||
import java.io.BufferedWriter;
|
||||
|
||||
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 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) {
|
||||
|
||||
int sizeX = 15;
|
||||
int sizeY = 15;
|
||||
int nbToken = 50;
|
||||
int nbJetonsAligne = 5;
|
||||
boolean renderer = false;
|
||||
String path_a_load = "";
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
switch (args[i]) {
|
||||
case "--save":
|
||||
if (i + 1 < args.length) {
|
||||
path_a_load = args[++i];
|
||||
}
|
||||
break;
|
||||
|
||||
case "--size":
|
||||
if (i + 2 < args.length) {
|
||||
sizeX = Integer.parseInt(args[++i]);
|
||||
sizeY = Integer.parseInt(args[++i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case "--nbToken":
|
||||
if (i + 1 < args.length) {
|
||||
nbToken = Integer.parseInt(args[++i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case "--nbTokenToWin":
|
||||
if (i + 1 < args.length) {
|
||||
nbJetonsAligne = Integer.parseInt(args[++i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case "--renderer":
|
||||
if (i + 1 < args.length) {
|
||||
String bool = args[++i];
|
||||
if (bool == "true") {
|
||||
renderer = true;
|
||||
} else {
|
||||
renderer = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
System.out.println("Invalid option : " + args[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sizeY < 3 || sizeX < 3) {
|
||||
System.out.println("Board is too small !");
|
||||
return;
|
||||
}
|
||||
GomokuGame g = new GomokuGame(false);// metre true ou fals si in veut l'affichage ou non
|
||||
g.renderer = new ConsoleRenderer();
|
||||
g.NB_CELL_PLAY = nbJetonsAligne;
|
||||
g.renderer.init(g);
|
||||
g.board = new GomokuBoard(sizeX, sizeY);
|
||||
g.board.get(sizeX / 2, sizeY / 2).setState(Color.BLACK);
|
||||
g.player1 = new Human("un", Color.WHITE, nbToken);
|
||||
g.player2 = new GomokuAI("deux", Color.BLACK, nbToken - 1);
|
||||
// System.out.println(g.board);
|
||||
// g.renderer.update();
|
||||
g.startGame();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method init the game with these parameters.
|
||||
*
|
||||
* @param bot If the player want to play with a bot it's true.
|
||||
* @param name1 Name of player one.
|
||||
* @param name2 Name of player two.
|
||||
* @param tokens Number of tokens for each player.
|
||||
*/
|
||||
|
||||
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 method is the main loop of the game
|
||||
*/
|
||||
public void startGame() {
|
||||
/*
|
||||
* GomokuCell actualPlayedCell = play(player1);
|
||||
* if( NB_CELL_PLAY <=
|
||||
* board.countMax(board.countAlignedCells(actualPlayedCell)))
|
||||
* {
|
||||
* System.out.println("c'est gangée !");
|
||||
* }
|
||||
*/
|
||||
this.currentPlayer = player1;
|
||||
renderer.update();
|
||||
while (this.player1.tokens > 0 || this.player2.tokens > 0) {
|
||||
GomokuCell currentPlay = null;
|
||||
while (currentPlay == null) {
|
||||
currentPlay = this.play(this.currentPlayer);
|
||||
}
|
||||
// Expand the board if one of the neighbours of the cell is null
|
||||
// Only check for North, South, East and West neighbours
|
||||
for (Cardinal cardinal : Cardinal.NS_EW) {
|
||||
GomokuCell neighbour = currentPlay.getNeighbour(cardinal);
|
||||
if (neighbour == null) {
|
||||
this.board.expandBoard(cardinal);
|
||||
}
|
||||
}
|
||||
if (NB_CELL_PLAY <= board.countMax(board.countAlignedCells(currentPlay))) {
|
||||
this.renderer.updateStatus("Le joueur " + this.currentPlayer + "a gagné !");
|
||||
return;
|
||||
}
|
||||
this.currentPlayer.tokens -= 1;
|
||||
this.currentPlayer = this.nextPlayer();
|
||||
renderer.update();
|
||||
}
|
||||
|
||||
this.renderer.updateStatus("Match nul, il ne reste plus de jetons.");
|
||||
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);
|
||||
if (cellToPlay == null || !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(this.board);
|
||||
cellToPlay.setState(player.color);
|
||||
}
|
||||
return cellToPlay;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method save the game on a file.
|
||||
*
|
||||
* @param filename The file to save.
|
||||
* @return True if successful and false if not.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method load a game on the file.
|
||||
*
|
||||
* @param filename The file to load.
|
||||
* @return True if successful and False if not.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method return the next player to play.
|
||||
*
|
||||
* @return The next player.
|
||||
*/
|
||||
private Player nextPlayer() {
|
||||
if (this.currentPlayer == this.player1) {
|
||||
return this.player2;
|
||||
}
|
||||
return player1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the board.
|
||||
*/
|
||||
public GomokuBoard getBoard() {
|
||||
return this.board;
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,9 @@ public class GomokuAI extends Player {
|
||||
* @param name The name of the player.
|
||||
* @param color The color of the player.
|
||||
*/
|
||||
public GomokuAI(String name, Color color, int tokens) {
|
||||
public GomokuAI(String name, Color color, int tokens, int difficulty) {
|
||||
super(name, color, tokens);
|
||||
this.difficulty = difficulty;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
|
||||
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;
|
||||
import java.io.BufferedReader;
|
||||
import java.util.Random;
|
||||
|
||||
public class GomokuGame {
|
||||
|
||||
@@ -20,15 +21,36 @@ public class GomokuGame {
|
||||
private GomokuBoard board;
|
||||
|
||||
private GomokuRenderer renderer;
|
||||
private boolean playRenderer = true;
|
||||
|
||||
Color colorP1;
|
||||
int currentPlayerInt;
|
||||
|
||||
Coordinate cellCoor = null;
|
||||
|
||||
GomokuGame(boolean renderer) {
|
||||
this.playRenderer = renderer;
|
||||
GomokuGame(int nbToken, int jtToWin, int x, int y, boolean pvp, int difficulty) {
|
||||
Random r = new Random();
|
||||
this.renderer = new ConsoleRenderer();
|
||||
this.NB_CELL_PLAY = jtToWin;
|
||||
this.renderer.init(this);
|
||||
this.board = new GomokuBoard(x, y);
|
||||
this.board.get(x / 2, y / 2).setState(Color.BLACK);
|
||||
|
||||
if (r.nextInt() % 2 == 0) {
|
||||
this.player1 = new Human("Premier joueur", Color.WHITE, nbToken);
|
||||
if (pvp) {
|
||||
this.player2 = new Human("Deuxieme joueur", Color.WHITE, nbToken);
|
||||
|
||||
}
|
||||
this.player2 = new GomokuAI("deux", Color.BLACK, nbToken - 1, difficulty);
|
||||
} else {
|
||||
this.player2 = new Human("Premier joueur", Color.WHITE, nbToken);
|
||||
if (pvp) {
|
||||
this.player1 = new Human("Deuxieme joueur", Color.WHITE, nbToken);
|
||||
|
||||
}
|
||||
this.player1 = new GomokuAI("deux", Color.BLACK, nbToken - 1, difficulty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
@@ -37,7 +59,8 @@ public class GomokuGame {
|
||||
int sizeY = 15;
|
||||
int nbToken = 50;
|
||||
int nbJetonsAligne = 5;
|
||||
boolean renderer = false;
|
||||
int difficulty = 2;
|
||||
boolean pvp = true;
|
||||
String path_a_load = "";
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
@@ -47,33 +70,55 @@ public class GomokuGame {
|
||||
path_a_load = args[++i];
|
||||
}
|
||||
break;
|
||||
case "--pvp":
|
||||
pvp = true;
|
||||
break;
|
||||
|
||||
case "--size":
|
||||
if (i + 2 < args.length) {
|
||||
try {
|
||||
sizeX = Integer.parseInt(args[++i]);
|
||||
sizeY = Integer.parseInt(args[++i]);
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.println("Arguments de --size invalides, config par défaut a été appliquée.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "--nbToken":
|
||||
if (i + 1 < args.length) {
|
||||
try {
|
||||
nbToken = Integer.parseInt(args[++i]);
|
||||
} catch (Exception e) {
|
||||
System.out.println("Argument de --nbToken invalide, config par défaut a été appliquée.");
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "--difficulty":
|
||||
if (i + 1 < args.length) {
|
||||
try {
|
||||
difficulty = Integer.parseInt(args[++i]);
|
||||
if (difficulty > 3 || difficulty < 1) {
|
||||
System.out.println(
|
||||
"Argument de --difficluty invalide, config par défaut a été appliquée.");
|
||||
difficulty = 2;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.out.println("Argument de --difficluty invalide, config par défaut a été appliquée.");
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "--nbTokenToWin":
|
||||
if (i + 1 < args.length) {
|
||||
try {
|
||||
nbJetonsAligne = Integer.parseInt(args[++i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case "--renderer":
|
||||
if (i + 1 < args.length) {
|
||||
String bool = args[++i];
|
||||
if (bool == "true") {
|
||||
renderer = true;
|
||||
} else {
|
||||
renderer = false;
|
||||
} catch (Exception e) {
|
||||
System.out
|
||||
.println("Argument de --nbTokenToWin invalide, config par défaut a été appliquée.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -87,51 +132,11 @@ public class GomokuGame {
|
||||
System.out.println("Board is too small !");
|
||||
return;
|
||||
}
|
||||
GomokuGame g = new GomokuGame(false);// metre true ou fals si in veut l'affichage ou non
|
||||
g.renderer = new ConsoleRenderer();
|
||||
g.NB_CELL_PLAY = nbJetonsAligne;
|
||||
g.renderer.init(g);
|
||||
g.board = new GomokuBoard(sizeX, sizeY);
|
||||
g.board.get(sizeX / 2, sizeY / 2).setState(Color.BLACK);
|
||||
g.player1 = new Human("un", Color.WHITE, nbToken);
|
||||
g.player2 = new GomokuAI("deux", Color.BLACK, nbToken - 1);
|
||||
// System.out.println(g.board);
|
||||
// g.renderer.update();
|
||||
GomokuGame g = new GomokuGame(nbToken, nbJetonsAligne, sizeX, sizeY, pvp, difficulty);
|
||||
g.startGame();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method init the game with these parameters.
|
||||
*
|
||||
* @param bot If the player want to play with a bot it's true.
|
||||
* @param name1 Name of player one.
|
||||
* @param name2 Name of player two.
|
||||
* @param tokens Number of tokens for each player.
|
||||
*/
|
||||
|
||||
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 method is the main loop of the game
|
||||
*/
|
||||
@@ -179,26 +184,8 @@ public class GomokuGame {
|
||||
*/
|
||||
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);
|
||||
if (cellToPlay == null || !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(this.board);
|
||||
cellToPlay.setState(player.color);
|
||||
}
|
||||
return cellToPlay;
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user