目录
题目:***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)); @Overridepublic 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);}
}