目录
题目:***16.31(游戏:四子连)
习题思路
代码示例
结果展示
题目:***16.31(游戏:四子连)
编程练习题8.20让两个玩家在控制台上可以玩四子连的游戏。为这个程序重写一个GUI版本,如图16-49c所示。这个程序让两个玩家轮流放置红色和黄色棋子。为了放置棋子,玩家需要在可用的格子上单击。可用的格子(available cell)是指不被占用的格子,而其下方临接的格子是被占用的格子。如果一个玩家胜了,这个程序就闪烁这四个赢的格子,如果所有的格子都被占用但还没有胜者,就报告无胜者。
-
习题思路
- 创建一个GridPane,把面板背景设为灰色, 创建一个Circle[7][6]并逐步添加到面板中,每一个圆初始都设置成白色,并同时为圆设置事件。
- 创建一个HBox,居中放置一个Label。
- 创建一个BorderPane,把GridPane设置在顶部,把HBox设置在底部。
- 定义一个下棋方法,在鼠标点击圆的时候更新圆的颜色并切换玩家,同时更新标签以显示当前玩家的回合。
- 定义一个游戏是否结束的方法,可以参考16.30题的代码。
- 创建一个TimeLine用来闪烁圆,可以把连续的棋子的坐标放在一个int[4][2]中,在事件内不断设置圆的本来颜色(黄/红)和另一个颜色(例如蓝色)。
-
代码示例
编程练习题16_31ConnectFour.java
package chapter_16;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class 编程练习题16_31ConnectFour extends Application{
private int[][] index = new int[4][2];
private int weidth = 7;//棋盘的长度
private int heigth = 6;//棋盘的宽度
private boolean end = false;
private int circleRadius = 20;//圆的半径
private int spacing = 8;
private Circle[][] circleList = new Circle[weidth][heigth];//定义一个棋盘
private Label lbText;//显示信息的标签
private boolean who = false;//决定该哪一方下棋
private boolean count = false;
EventHandler<ActionEvent> eventHandler = e -> {
for (int i = 0; i < 4; i++) {
Color color = who?Color.YELLOW:Color.RED;
int row = index[i][0];
int col = index[i][1];
System.out.println(i+" "+row+","+col);
Circle c = circleList[row][col];
if (c != null ) {
if(count) {
c.setFill(color);
}else {
c.setFill(Color.BLUE);
}
}
}
count = !count;
};
private Timeline t = new Timeline(new KeyFrame(Duration.millis(500), eventHandler));
@Override
public void start(Stage primaryStage) throws Exception {
t.setCycleCount(Timeline.INDEFINITE);
GridPane gridPane = new GridPane();
gridPane.setPadding(new Insets(10, 10, 10, 10));
gridPane.setStyle("-fx-background-color:Gray");
gridPane.setVgap(8);
gridPane.setHgap(8);
gridPane.setAlignment(Pos.CENTER);
for(int i = 0;i < circleList.length;i++) {
for(int j = 0;j < circleList[i].length;j++) {
circleList[i][j] = new Circle(circleRadius);
circleList[i][j].setFill(Color.WHITE);
circleList[i][j].setStroke(Color.BLACK);
circleList[i][j].setOnMouseClicked(e -> playChess(e));
gridPane.add(circleList[i][j], i, j);
}
}
lbText = new Label("X's turn to play");
HBox hBox = new HBox(lbText);
hBox.setAlignment(Pos.CENTER);
BorderPane borderPane = new BorderPane();
borderPane.setTop(gridPane);
borderPane.setBottom(hBox);
Scene scene = new Scene(borderPane,350, 330);
primaryStage.setTitle("编程练习题16_31ConnectFour");
primaryStage.setScene(scene);
primaryStage.show();
}
private void playChess(MouseEvent e) {
if (end) return; // 如果游戏已经结束,则不执行任何操作
Circle clickedCircle = (Circle) e.getSource();
// 遍历circleList以找到clickedCircle的索引
for (int i = 0; i < circleList.length; i++) {
for (int j = 0; j < circleList[i].length; j++) {
if (circleList[i][j] == clickedCircle) {
if (circleList[i][j].getFill() != Color.WHITE) {
return; // 如果圆已经被填充,则不执行任何操作
}
// 更新圆的颜色并切换玩家
if (who) {
circleList[i][j].setFill(Color.RED);
} else {
circleList[i][j].setFill(Color.YELLOW);
}
who = !who;
// 更新标签以显示当前玩家的回合(但在游戏结束时不会更新)
if (!end) {
lbText.setText(who ? "Yellow's turn to play" : "Red's turn to play");
}
// 检查游戏是否结束
end = isConsecutiveFour(circleList);
if (end) {
// 更新标签以反映哪一方获胜
lbText.setText(who ? "Yellow wins!" : "Red wins!");
// 这里可以停止Timeline或进行其他清理工作
t.play();
}
return; // 找到并更新后退出循环
}
}
}
// 如果没有找到匹配的圆,则抛出异常或记录日志
System.err.println("Failed to find clicked circle in array!");
}
public boolean isConsecutiveFour(Circle[][] values) {
if (values == null || values.length == 0 || values[0].length == 0) {
return false;
}
int rows = values.length;
int cols = values[0].length;
// 检查行
for (int i = 0; i < rows; i++) {
for (int j = 0; j <= cols - 4; j++) { // 只需检查到 cols-4
Color color = (Color) values[i][j].getFill();
if (color.equals(values[i][j + 1].getFill()) &&
color.equals(values[i][j + 2].getFill()) &&
color.equals(values[i][j + 3].getFill())) {
if(color!=Color.WHITE) {
for(int k = 0;k < 4;k++) {
index[k][0] = i;
index[k][1] = j+k;
System.out.println("("+i+","+j+")");
}
return true;
}
}
}
}
// 检查列
for (int j = 0; j < cols; j++) {
for (int i = 0; i <= rows - 4; i++) { // 只需检查到 rows-4
Color color =(Color) values[i][j].getFill();
if (color.equals(values[i + 1][j].getFill()) &&
color.equals(values[i + 2][j].getFill()) &&
color.equals(values[i + 3][j].getFill())) {
if(color!=Color.WHITE) {
for(int k = 0;k < 4;k++) {
index[k][0] = i+k;
index[k][1] = j;
System.out.println("("+i+","+j+")");
}
return true;
}
}
}
}
// 检查主对角线
for (int i = 0; i <= rows - 4; i++) {
for (int j = 0; j <= cols - 4; j++) {
Color color = (Color) values[i][j].getFill();
if (color.equals(values[i + 1][j + 1].getFill()) &&
color.equals(values[i + 2][j + 2].getFill()) &&
color.equals(values[i + 3][j + 3].getFill())) {
if(color!=Color.WHITE) {
for(int k = 0;k < 4;k++) {
index[k][0] = i+k;
index[k][1] = j+k;
}
return true;
}
}
}
}
// 检查副对角线
for (int i = 0; i <= rows - 4; i++) {
for (int j = 3; j < cols; j++) { // 注意起始点是3,因为是从右上角往左下角检查
Color color = (Color) values[i][j].getFill();
if (color.equals(values[i + 1][j - 1].getFill()) &&
color.equals(values[i + 2][j - 2].getFill()) &&
color.equals(values[i + 3][j - 3].getFill())) {
if(color!=Color.WHITE) {
for(int k = 0;k < 4;k++) {
index[k][0] = i+k;
index[k][1] = j-k;
}
return true;
}
}
}
}
// 如果没有找到连续的四个相同颜色的圆
return false;
}
public static void main(String[] args) {
Application.launch(args);
}
}