如何在 Gomoku javafx 游戏中启用轮流
How to enable turn taking within game of Gomoku javafx
我很难在我的程序中启用轮流。
棋盘上的一个图块被点击,这些坐标被传递给 playMakeMove(),它在棋盘矩阵中移动并设置文本以直观地表示移动。
虽然当有2个玩家参与时(player, RandomAI),使用循环交替轮流后,该方法不起作用。 RandomAI 只是连续进行所有移动,玩家只在完全相同的位置移动一次(不等待鼠标被点击)。
我认为这个问题可以通过等待瓷砖被点击(到 运行 方法 playerMakeMove)然后让 RandomAI 轮流来解决。不确定如何实现这一点。
下面是两个 classes BoardGUI 和 Game 还有另一个 class(不包括)称为 Board。
public class BoardGUI extends Application {
private final int BOARD_SIZE = 15;
private Tile[][] tileBoard = new Tile[BOARD_SIZE][BOARD_SIZE];
private Pane root = new Pane();
private Parent createContent(Game game) {
root.setPrefSize(755, 755);
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
Tile tile = new Tile(i, j);
tile.setTranslateX(j * 50);
tile.setTranslateY(i * 50);
tile.setOnMousePressed(e -> {
System.out.println("tile clicked");
// sets coordinates of tileClicked in game - to be used in making a player move
game.getTile().setRow(tile.getTileRow());
game.getTile().setColumn(tile.getTileCol());
});
root.getChildren().add(tile);
tileBoard[i][j] = tile;
}
}
return root;
}
@Override
public void start(Stage primaryStage) {
Game game = new Game();
Scene scene = new Scene (game.GUI.createContent(game));
primaryStage.setScene(scene);
primaryStage.setTitle("Gomoku");
primaryStage.show();
for (int turns = 0; turns < (game.getBoardSize()*game.getBoardSize()); turns++) {
if(game.getGameOver()) break;
if(!game.isPlayerTurn()) {
//AI make move
game.makeMoveAIRandom(game.getGameBoard());
game.setPlayerTurnTrue();
}
else {
// player make move
game.playerMakeMove(game);
}
}
System.out.println("game over");
}
class Tile extends StackPane {
Text text = new Text();
int row, column;
Tile(int x, int y) {
this.row = x;
this.column = y;
Rectangle border = new Rectangle(50, 50);
border.setFill(Color.BURLYWOOD);
border.setStroke(Color.BLACK);
text.setFont(Font.font(40));
setAlignment(Pos.CENTER);
getChildren().addAll(border, text);
}
void makeMove(Board board, int player, int row, int col) {
System.out.println(row + " " + col);
if (board.isMoveAvailable(row, col)) {
drawTile(player);
makeMoveMatrix(board, player, row, col);
}
System.out.println("makeMove executed");
}
void drawTile(int player) {
System.out.println("setTextTile executed");
text.setText("O");
if (player == 1) text.setFill(Color.BLACK);
else text.setFill(Color.WHITE);
}
void makeMoveMatrix(Board board, int player, int row, int col) {
board.make_move(player, row, col);
}
int getTileRow() { return row; }
void setRow(int row) { this.row = row; }
void setColumn(int column) { this.column = column; }
int getTileCol() { return column; }
}
Tile[][] getTileBoard() { return tileBoard; }
}
public class Game extends BoardGUI {
private final int PLAYER_ONE = 1;
private final int PLAYER_TWO = 2;
BoardGUI GUI;
private Board gameBoard;
private int boardSize = 15;
private int winLength = 5;
private boolean turn = true;
private boolean isGameOver = false;
private Tile tileClicked = new Tile(0, 0);
Game() {
this.gameBoard = new Board(boardSize, winLength);
this.GUI = new BoardGUI();
}
void makeMoveAIRandom(Board gameBoard) {
Random random = new Random();
int index = random.nextInt(gameBoard.availableMoves.size());
int[] move = gameBoard.availableMoves.get(index);
int row = move[0];
int col = move[1];
GUI.getTileBoard()[row][col].makeMove(gameBoard, PLAYER_TWO, move[0], move[1]);
setGameOver(getGameBoard().check_win_all(PLAYER_TWO, row, col));
gameBoard.availableMoves.remove(index);
setPlayerTurnTrue();
}
void playerMakeMove(Game game) {
int row = game.getTile().getTileRow();
int col = game.getTile().getTileCol();
game.GUI.getTileBoard()[row][col].makeMove(game.getGameBoard(), PLAYER_ONE, row, col);
setGameOver(getGameBoard().check_win_all(PLAYER_TWO, row, col));
System.out.println("player taken turn");
setPlayerTurnFalse();
}
Board getGameBoard() { return gameBoard; }
int getBoardSize () { return boardSize; }
boolean isPlayerTurn() { return turn; }
private void setPlayerTurnFalse() { turn = false; }
void setPlayerTurnTrue() { turn = true; }
boolean getGameOver () { return isGameOver; }
private void setGameOver (boolean result) { isGameOver = result; }
Tile getTile () { return tileClicked; }
}
您有 2 个主要选项来实现游戏循环。我不会在 Java 中编写它们的等价物,而是提供伪代码,如果您在转换为 Java.
时遇到问题,您可以询问
第一个选项是触发所有 activity 来自用户的操作。因此,例如,'event' 可能是拖放、选项单击等,具体取决于游戏:
on user event:
change state according to user's choice
go to next player
while next player is AI:
perform automated move
go to next player
第二个更通用的选项是设置一个计时器,该计时器会定期触发以检查是否可以发生 AI 操作。
on user event:
change state according to user's choice
go to next player
on timer tick:
if current player is AI
perform automated move
go to next player
根据游戏机制,每一项都有自己的位置
以下是一个完整的 运行 实现轮流变换的代码。
它还建议进行一些改进和设计更改。请注意评论。
未实现游戏结束逻辑。
为了方便起见,可以将整个代码复制粘贴到一个文件中 (BoardGUI.java
) 和 运行:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class BoardGUI extends Application {
private final static int BOARD_SIZE = 15;
private final Tile[][] tileBoard = new Tile[BOARD_SIZE][BOARD_SIZE];
private final Pane root = new Pane();
private Parent createContent(Game game) {
root.setPrefSize(755, 755);
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
Tile tile = new Tile(i, j);
tile.setTranslateX(j * 50);
tile.setTranslateY(i * 50);
final int row = i, col = j;
tile.setOnMousePressed(e -> {
//the click causes a move
//game.playerMakeMove(game, row, col); //no need to pass a reference of Game to Game
game.playerMakeMove(row, col); //no need to pass a reference of Game to Game
});
root.getChildren().add(tile);
tileBoard[i][j] = tile;
}
}
return root;
}
@Override
public void start(Stage primaryStage) {
//there is no need to get a new instance of BoardGUI from Game.
//Game game = new Game();
//Scene scene = new Scene (game.gui.createContent(game));
//instead:
Game game = new Game(this);
Scene scene = new Scene (createContent(game));
primaryStage.setScene(scene);
primaryStage.setTitle("Gomoku");
primaryStage.show();
//the player should make a move (click) and it should trigger the next move
}
//method moved from Tile
void makeMove(Board board, int player, int row, int col) {
if (board.isMoveAvailable(row, col)) {
tileBoard[row][col].drawTile(player);
makeMoveMatrix(board, player, row, col);
}
}
//method moved from Tile
void makeMoveMatrix(Board board, int player, int row, int col) {
board.make_move(player, row, col);
}
Tile[][] getTileBoard() { return tileBoard; }
class Tile extends StackPane {
Text text = new Text();
int row, column;
Tile(int row, int col) {
this.row = row; column = col;
Rectangle border = new Rectangle(50, 50);
border.setFill(Color.BURLYWOOD);
border.setStroke(Color.BLACK);
text.setFont(Font.font(40));
setAlignment(Pos.CENTER);
getChildren().addAll(border, text);
}
void drawTile(int player) {
text.setText("O");
if (player == Game.PLAYER_ONE) {
text.setFill(Color.BLACK);
} else {
text.setFill(Color.WHITE);
}
}
int getTileRow() { return row; }
void setRow(int row) { this.row = row; }
void setColumn(int column) { this.column = column; }
int getTileCol() { return column; }
}
public static void main(String[] args) {
launch(null);
}
}
class Game {// there is no need for Game to extend BoardGUI
public static final int FREE = 0, PLAYER_ONE = 1, PLAYER_TWO = 2;
private final BoardGUI gui;
private final Board gameBoard;
private final int boardSize = 15, winLength = 5;
private final Random random = new Random(); //no need to create new Randon with every move
//replace this attribute with property so you could listen to it
//private boolean turn = true;
private final BooleanProperty playerTurn = new SimpleBooleanProperty(true);
private boolean isGameOver = false;
Game(BoardGUI gui) { //get a reference to BoardGUI rather than constructing it
gameBoard = new Board(boardSize, winLength);
this.gui = gui;
playerTurn.addListener( (obs,oldValue,newValue) ->{//listen to turn changes
if(!newValue) {
makeMoveAIRandom();
}
});
}
void makeMoveAIRandom() {
if( playerTurn.get() ) return; //run only if not player turn
List<int[]> availableMoves = gameBoard.getAvailableMoves();
int index = random.nextInt(availableMoves.size());
int[] move = availableMoves.get(index);
gui.makeMove(gameBoard, PLAYER_TWO, move[0], move[1]);
setPlayerTurnTrue();
System.out.println("AI taken turn " + move[0] +"-"+ move[1]);
}
//void playerMakeMove(Game game, int row, int col) { //no need to path reference to this
void playerMakeMove(int row, int col) {
if(! playerTurn.get() ) return; //run only if player turn
gui.makeMove(gameBoard, PLAYER_ONE, row, col);
setPlayerTurnFalse();
System.out.println("player taken turn " + row +"-"+col );
}
Board getGameBoard() { return gameBoard; }
int getBoardSize () { return boardSize; }
boolean isPlayerTurn() { return playerTurn.get(); }
private void setPlayerTurnFalse() { playerTurn.set(false); }
void setPlayerTurnTrue() { playerTurn.set(true); }
boolean getGameOver () { return isGameOver; }
private void setGameOver (boolean result) { isGameOver = result; }
}
class Board {
private final int[][] board_matrix;
private final int board_size, win_length;
Board(int board_size, int win_length) {
board_matrix = new int[board_size][board_size];
this.board_size = board_size;
this.win_length = win_length;
for (int i = 0; i < board_size; i++) {
for (int j = 0; j < board_size; j++) {
board_matrix[i][j] = Game.FREE;
}
}
}
boolean isMoveAvailable(int row, int col) {
return board_matrix[row][col] != Game.PLAYER_ONE && board_matrix[row][col] != Game.PLAYER_TWO ;
}
void make_move(int player, int x_pos, int y_pos) {
if (player == Game.PLAYER_ONE) {
board_matrix[x_pos][y_pos] = Game.PLAYER_ONE;
} else {
board_matrix[x_pos][y_pos] = Game.PLAYER_TWO;
}
}
List<int[]> getAvailableMoves(){
List<int[]> availableMoves = new ArrayList<>();
for (int row = 0; row < board_size; row++) {
for (int col = 0; col < board_size; col++) {
if (board_matrix[row][col] == Game.FREE){
availableMoves.add(new int[]{ row, col});
}
}
}
return availableMoves;
}
}
我很难在我的程序中启用轮流。
棋盘上的一个图块被点击,这些坐标被传递给 playMakeMove(),它在棋盘矩阵中移动并设置文本以直观地表示移动。
虽然当有2个玩家参与时(player, RandomAI),使用循环交替轮流后,该方法不起作用。 RandomAI 只是连续进行所有移动,玩家只在完全相同的位置移动一次(不等待鼠标被点击)。
我认为这个问题可以通过等待瓷砖被点击(到 运行 方法 playerMakeMove)然后让 RandomAI 轮流来解决。不确定如何实现这一点。
下面是两个 classes BoardGUI 和 Game 还有另一个 class(不包括)称为 Board。
public class BoardGUI extends Application {
private final int BOARD_SIZE = 15;
private Tile[][] tileBoard = new Tile[BOARD_SIZE][BOARD_SIZE];
private Pane root = new Pane();
private Parent createContent(Game game) {
root.setPrefSize(755, 755);
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
Tile tile = new Tile(i, j);
tile.setTranslateX(j * 50);
tile.setTranslateY(i * 50);
tile.setOnMousePressed(e -> {
System.out.println("tile clicked");
// sets coordinates of tileClicked in game - to be used in making a player move
game.getTile().setRow(tile.getTileRow());
game.getTile().setColumn(tile.getTileCol());
});
root.getChildren().add(tile);
tileBoard[i][j] = tile;
}
}
return root;
}
@Override
public void start(Stage primaryStage) {
Game game = new Game();
Scene scene = new Scene (game.GUI.createContent(game));
primaryStage.setScene(scene);
primaryStage.setTitle("Gomoku");
primaryStage.show();
for (int turns = 0; turns < (game.getBoardSize()*game.getBoardSize()); turns++) {
if(game.getGameOver()) break;
if(!game.isPlayerTurn()) {
//AI make move
game.makeMoveAIRandom(game.getGameBoard());
game.setPlayerTurnTrue();
}
else {
// player make move
game.playerMakeMove(game);
}
}
System.out.println("game over");
}
class Tile extends StackPane {
Text text = new Text();
int row, column;
Tile(int x, int y) {
this.row = x;
this.column = y;
Rectangle border = new Rectangle(50, 50);
border.setFill(Color.BURLYWOOD);
border.setStroke(Color.BLACK);
text.setFont(Font.font(40));
setAlignment(Pos.CENTER);
getChildren().addAll(border, text);
}
void makeMove(Board board, int player, int row, int col) {
System.out.println(row + " " + col);
if (board.isMoveAvailable(row, col)) {
drawTile(player);
makeMoveMatrix(board, player, row, col);
}
System.out.println("makeMove executed");
}
void drawTile(int player) {
System.out.println("setTextTile executed");
text.setText("O");
if (player == 1) text.setFill(Color.BLACK);
else text.setFill(Color.WHITE);
}
void makeMoveMatrix(Board board, int player, int row, int col) {
board.make_move(player, row, col);
}
int getTileRow() { return row; }
void setRow(int row) { this.row = row; }
void setColumn(int column) { this.column = column; }
int getTileCol() { return column; }
}
Tile[][] getTileBoard() { return tileBoard; }
}
public class Game extends BoardGUI {
private final int PLAYER_ONE = 1;
private final int PLAYER_TWO = 2;
BoardGUI GUI;
private Board gameBoard;
private int boardSize = 15;
private int winLength = 5;
private boolean turn = true;
private boolean isGameOver = false;
private Tile tileClicked = new Tile(0, 0);
Game() {
this.gameBoard = new Board(boardSize, winLength);
this.GUI = new BoardGUI();
}
void makeMoveAIRandom(Board gameBoard) {
Random random = new Random();
int index = random.nextInt(gameBoard.availableMoves.size());
int[] move = gameBoard.availableMoves.get(index);
int row = move[0];
int col = move[1];
GUI.getTileBoard()[row][col].makeMove(gameBoard, PLAYER_TWO, move[0], move[1]);
setGameOver(getGameBoard().check_win_all(PLAYER_TWO, row, col));
gameBoard.availableMoves.remove(index);
setPlayerTurnTrue();
}
void playerMakeMove(Game game) {
int row = game.getTile().getTileRow();
int col = game.getTile().getTileCol();
game.GUI.getTileBoard()[row][col].makeMove(game.getGameBoard(), PLAYER_ONE, row, col);
setGameOver(getGameBoard().check_win_all(PLAYER_TWO, row, col));
System.out.println("player taken turn");
setPlayerTurnFalse();
}
Board getGameBoard() { return gameBoard; }
int getBoardSize () { return boardSize; }
boolean isPlayerTurn() { return turn; }
private void setPlayerTurnFalse() { turn = false; }
void setPlayerTurnTrue() { turn = true; }
boolean getGameOver () { return isGameOver; }
private void setGameOver (boolean result) { isGameOver = result; }
Tile getTile () { return tileClicked; }
}
您有 2 个主要选项来实现游戏循环。我不会在 Java 中编写它们的等价物,而是提供伪代码,如果您在转换为 Java.
时遇到问题,您可以询问第一个选项是触发所有 activity 来自用户的操作。因此,例如,'event' 可能是拖放、选项单击等,具体取决于游戏:
on user event:
change state according to user's choice
go to next player
while next player is AI:
perform automated move
go to next player
第二个更通用的选项是设置一个计时器,该计时器会定期触发以检查是否可以发生 AI 操作。
on user event:
change state according to user's choice
go to next player
on timer tick:
if current player is AI
perform automated move
go to next player
根据游戏机制,每一项都有自己的位置
以下是一个完整的 运行 实现轮流变换的代码。
它还建议进行一些改进和设计更改。请注意评论。
未实现游戏结束逻辑。
为了方便起见,可以将整个代码复制粘贴到一个文件中 (BoardGUI.java
) 和 运行:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class BoardGUI extends Application {
private final static int BOARD_SIZE = 15;
private final Tile[][] tileBoard = new Tile[BOARD_SIZE][BOARD_SIZE];
private final Pane root = new Pane();
private Parent createContent(Game game) {
root.setPrefSize(755, 755);
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
Tile tile = new Tile(i, j);
tile.setTranslateX(j * 50);
tile.setTranslateY(i * 50);
final int row = i, col = j;
tile.setOnMousePressed(e -> {
//the click causes a move
//game.playerMakeMove(game, row, col); //no need to pass a reference of Game to Game
game.playerMakeMove(row, col); //no need to pass a reference of Game to Game
});
root.getChildren().add(tile);
tileBoard[i][j] = tile;
}
}
return root;
}
@Override
public void start(Stage primaryStage) {
//there is no need to get a new instance of BoardGUI from Game.
//Game game = new Game();
//Scene scene = new Scene (game.gui.createContent(game));
//instead:
Game game = new Game(this);
Scene scene = new Scene (createContent(game));
primaryStage.setScene(scene);
primaryStage.setTitle("Gomoku");
primaryStage.show();
//the player should make a move (click) and it should trigger the next move
}
//method moved from Tile
void makeMove(Board board, int player, int row, int col) {
if (board.isMoveAvailable(row, col)) {
tileBoard[row][col].drawTile(player);
makeMoveMatrix(board, player, row, col);
}
}
//method moved from Tile
void makeMoveMatrix(Board board, int player, int row, int col) {
board.make_move(player, row, col);
}
Tile[][] getTileBoard() { return tileBoard; }
class Tile extends StackPane {
Text text = new Text();
int row, column;
Tile(int row, int col) {
this.row = row; column = col;
Rectangle border = new Rectangle(50, 50);
border.setFill(Color.BURLYWOOD);
border.setStroke(Color.BLACK);
text.setFont(Font.font(40));
setAlignment(Pos.CENTER);
getChildren().addAll(border, text);
}
void drawTile(int player) {
text.setText("O");
if (player == Game.PLAYER_ONE) {
text.setFill(Color.BLACK);
} else {
text.setFill(Color.WHITE);
}
}
int getTileRow() { return row; }
void setRow(int row) { this.row = row; }
void setColumn(int column) { this.column = column; }
int getTileCol() { return column; }
}
public static void main(String[] args) {
launch(null);
}
}
class Game {// there is no need for Game to extend BoardGUI
public static final int FREE = 0, PLAYER_ONE = 1, PLAYER_TWO = 2;
private final BoardGUI gui;
private final Board gameBoard;
private final int boardSize = 15, winLength = 5;
private final Random random = new Random(); //no need to create new Randon with every move
//replace this attribute with property so you could listen to it
//private boolean turn = true;
private final BooleanProperty playerTurn = new SimpleBooleanProperty(true);
private boolean isGameOver = false;
Game(BoardGUI gui) { //get a reference to BoardGUI rather than constructing it
gameBoard = new Board(boardSize, winLength);
this.gui = gui;
playerTurn.addListener( (obs,oldValue,newValue) ->{//listen to turn changes
if(!newValue) {
makeMoveAIRandom();
}
});
}
void makeMoveAIRandom() {
if( playerTurn.get() ) return; //run only if not player turn
List<int[]> availableMoves = gameBoard.getAvailableMoves();
int index = random.nextInt(availableMoves.size());
int[] move = availableMoves.get(index);
gui.makeMove(gameBoard, PLAYER_TWO, move[0], move[1]);
setPlayerTurnTrue();
System.out.println("AI taken turn " + move[0] +"-"+ move[1]);
}
//void playerMakeMove(Game game, int row, int col) { //no need to path reference to this
void playerMakeMove(int row, int col) {
if(! playerTurn.get() ) return; //run only if player turn
gui.makeMove(gameBoard, PLAYER_ONE, row, col);
setPlayerTurnFalse();
System.out.println("player taken turn " + row +"-"+col );
}
Board getGameBoard() { return gameBoard; }
int getBoardSize () { return boardSize; }
boolean isPlayerTurn() { return playerTurn.get(); }
private void setPlayerTurnFalse() { playerTurn.set(false); }
void setPlayerTurnTrue() { playerTurn.set(true); }
boolean getGameOver () { return isGameOver; }
private void setGameOver (boolean result) { isGameOver = result; }
}
class Board {
private final int[][] board_matrix;
private final int board_size, win_length;
Board(int board_size, int win_length) {
board_matrix = new int[board_size][board_size];
this.board_size = board_size;
this.win_length = win_length;
for (int i = 0; i < board_size; i++) {
for (int j = 0; j < board_size; j++) {
board_matrix[i][j] = Game.FREE;
}
}
}
boolean isMoveAvailable(int row, int col) {
return board_matrix[row][col] != Game.PLAYER_ONE && board_matrix[row][col] != Game.PLAYER_TWO ;
}
void make_move(int player, int x_pos, int y_pos) {
if (player == Game.PLAYER_ONE) {
board_matrix[x_pos][y_pos] = Game.PLAYER_ONE;
} else {
board_matrix[x_pos][y_pos] = Game.PLAYER_TWO;
}
}
List<int[]> getAvailableMoves(){
List<int[]> availableMoves = new ArrayList<>();
for (int row = 0; row < board_size; row++) {
for (int col = 0; col < board_size; col++) {
if (board_matrix[row][col] == Game.FREE){
availableMoves.add(new int[]{ row, col});
}
}
}
return availableMoves;
}
}