标签搜索

javafx实现五子棋游戏

ATAO
2022-04-04 / 0 评论 / 55 阅读 / 正在检测是否收录...

设计一个五子棋游戏,实现悔棋、保存棋谱、棋谱复盘等功能。

窗口程序依赖于javafx,编译运行请使用jdk1.8。

完成结果如下图:

完整代码:

  • 棋子类

import javafx.scene.paint.Color;

/**
 * 棋子描述类
 */
public class Chess {
    /**
     * 棋子横坐标
     */
    private final int x;
    /**
     * 棋子纵坐标
     */
    private final int y;
    /**
     * 棋子颜色
     */
    private final Color color;

    public Chess(int x, int y, Color color) {
        this.x = x;
        this.y = y;
        this.color = color;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public Color getColor() {
        return color;
    }

    @Override
    public String toString() {
        return "Chess [x=" + x + ", y=" + y + ", color=" + color + "]";
    }
}
  • 主框架类
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.stage.FileChooser;
import javafx.stage.FileChooser.ExtensionFilter;
import javafx.stage.Stage;

import java.io.*;
import java.util.ArrayList;
import java.util.Optional;
import java.util.function.Predicate;

/**
 * 主框架类
 */
public class MyChessApp extends Application {
    /**
     * 棋盘宽度
     */
    private static final int WIDTH = 600;
    /**
     * 棋盘高度
     */
    private static final int HEIGHT = 600;
    /**
     * 棋盘中线与线之间的距离
     */
    private static final int PADDING = 40;
    /**
     * 棋盘与边框之间的距离
     */
    private static final int MARGIN = 20;
    /**
     * 棋盘中水平线与垂直线的个数
     */
    private static final int LINE_COUNT = 14;
    /**
     * 棋盘对象
     */
    private Pane pane;
    /**
     * 当前落子是否为黑子
     */
    private boolean isBlack = true;
    /**
     * 记录棋盘
     */
    private Chess[][] chesses = new Chess[LINE_COUNT][LINE_COUNT];
    /**
     * 记录棋子顺序
     */
    private Chess[] cs = new Chess[LINE_COUNT * LINE_COUNT];
    /**
     * 棋盘上棋子个数
     */
    private int count = 0;
    /**
     * 是否胜利
     */
    private boolean isWin = false;
    /**
     * 舞台对象
     */
    private Stage stage;

    @Override
    public void start(Stage stage) {
        this.stage = stage;
        // 获取画板对象
        this.pane = getPane();
        // 落子
        moveInChess();
        // 创建场景对象
        Scene scene = new Scene(pane, WIDTH, HEIGHT);
        stage.setScene(scene);
        stage.setTitle("五子棋");
        stage.setOnCloseRequest(event -> {
            Alert alert = new Alert(AlertType.CONFIRMATION);
            alert.setTitle("退出");
            alert.setHeaderText("确认提出吗?");
            Optional<ButtonType> optional = alert.showAndWait();
            if (optional.isPresent() && optional.get() == ButtonType.CANCEL) {
                event.consume();
            }
        });
        stage.show();
    }

    /**
     * 落子功能
     */
    private void moveInChess() {
        // 给画板对象绑定鼠标点击事件
        pane.setOnMouseClicked(event -> {
            if (isWin) {
                return;
            }
            // 获取鼠标点击的坐标
            double x = event.getX();
            double y = event.getY();
//                System.out.println(x + " " + y);
            if (!(x >= MARGIN && x <= MARGIN + (LINE_COUNT - 1) * PADDING && y >= MARGIN
                    && y <= MARGIN + (LINE_COUNT - 1) * PADDING)) {
                return;
            }
            // 根据鼠标点击位置计算棋子坐标
            int chessX = ((int) x - MARGIN + PADDING / 2) / PADDING;
            int chessY = ((int) y - MARGIN + PADDING / 2) / PADDING;
//                System.out.println(_x + " " + _y);

            if (chesses[chessX][chessY] != null) {
//                    System.out.println("已经有棋子了");
                return;
            }

            // 绘制棋子
            Chess chess = drawChess(chessX, chessY);

            if (isWin(chess)) {
                Alert alert = new Alert(AlertType.INFORMATION);
                alert.setTitle("游戏结束");
                String name;
                if (chess.getColor() == Color.BLACK) {
                    name = "黑子";
                } else {
                    name = "白子";
                }
                alert.setHeaderText(name + "胜利了");
                alert.showAndWait();
                isWin = true;
            }
        });
    }

    /**
     * 绘制棋子
     */
    private Chess drawChess(int chessX, int chessY) {
        Circle circle;
        Chess chess;
        if (isBlack) {
            circle = new Circle(chessX * PADDING + MARGIN, chessY * PADDING + MARGIN, 15, Color.BLACK);
            chess = new Chess(chessX, chessY, Color.BLACK);
            isBlack = false;
        } else {
            circle = new Circle(chessX * PADDING + MARGIN, chessY * PADDING + MARGIN, 15, Color.WHITE);
            chess = new Chess(chessX, chessY, Color.WHITE);
            isBlack = true;
        }
        chesses[chessX][chessY] = chess;
        cs[count++] = chess;
        pane.getChildren().add(circle);
        return chess;
    }

    /**
     * 创建画板对象
     */
    private Pane getPane() {
        // 创建画板对象
        Pane pane = new Pane();
        // 设置画板背景颜色
        pane.setBackground(new Background(new BackgroundFill(Color.BEIGE, null, null)));
        // 绘制棋盘
        int increment = 0;
        for (int i = 0; i < LINE_COUNT; i++) {
            Line rowLine = new Line(MARGIN, MARGIN + increment, MARGIN + (LINE_COUNT - 1) * PADDING,
                    MARGIN + increment);
            Line colLine = new Line(MARGIN + increment, MARGIN, MARGIN + increment,
                    MARGIN + (LINE_COUNT - 1) * PADDING);
            pane.getChildren().add(rowLine);
            pane.getChildren().add(colLine);
            increment += PADDING;
        }
        // 再来一局按钮
        Button startButton = getStartButton();
        // 悔棋按钮
        Button retractButton = getRetractButton();
        // 退出按钮
        Button quitButton = getQuitButton();
        // 保存棋谱按钮
        Button saveButton = getSaveButton();
        // 保存打谱按钮
        Button scoreButton = getScoreButton();
        pane.getChildren().add(startButton);
        pane.getChildren().add(retractButton);
        pane.getChildren().add(quitButton);
        pane.getChildren().add(saveButton);
        pane.getChildren().add(scoreButton);
        return pane;
    }

    /**
     * 获取打谱按钮
     */
    private Button getScoreButton() {
        Button scoreButton = new Button("棋谱复盘");
        scoreButton.setPrefSize(80, 30);
        scoreButton.setLayoutX(WIDTH / 15.0 + 100 * 3);
        scoreButton.setLayoutY(HEIGHT - 40);
        scoreButton.setOnAction(event -> {
            FileChooser fileChooser = new FileChooser();
            fileChooser.getExtensionFilters().addAll(new ExtensionFilter("棋谱文件", "*.qipu"),
                    new ExtensionFilter("所有文件", "*.*"));
            File file = fileChooser.showOpenDialog(stage);

            if (file == null) {
                return;
            }

            try {
                BufferedReader br = new BufferedReader(new FileReader(file));
                String line;
                ArrayList<String> cheesiness = new ArrayList<>();
                while ((line = br.readLine()) != null) {
                    cheesiness.add(line);
                }
                br.close();
                resetChessBoard();
                Button next = new Button(">");
                next.setPrefSize(40, 40);
                next.setLayoutX(WIDTH - 40);
                next.setLayoutY(100);
                next.setOnAction(event13 -> {
                    if (count >= cheesiness.size()) {
                        Alert alert = new Alert(AlertType.INFORMATION);
                        alert.setTitle("提示");
                        alert.setHeaderText("没有下一步了");
                        alert.showAndWait();
                        return;
                    }
                    String[] info = cheesiness.get(count).split(",");
                    drawChess(Integer.parseInt(info[0]), Integer.parseInt(info[1]));
                });
                pane.getChildren().add(next);

                Button pre = new Button("<");
                pre.setPrefSize(40, 40);
                pre.setLayoutX(WIDTH - 40);
                pre.setLayoutY(150);
                pre.setOnAction(event12 -> retract());
                pane.getChildren().add(pre);

                Button exit = new Button("x");
                exit.setPrefSize(40, 40);
                exit.setLayoutX(WIDTH - 40);
                exit.setLayoutY(200);
                exit.setOnAction(event1 -> {
                    Alert alert = new Alert(AlertType.CONFIRMATION);
                    alert.setTitle("提示");
                    alert.setHeaderText("确定退出打谱?");
                    Optional<ButtonType> optional = alert.showAndWait();
                    if (optional.isPresent() && optional.get() == ButtonType.OK) {
                        resetChessBoard();
                        pane.getChildren().remove(pane.getChildren().size() - 3, pane.getChildren().size());
                    }
                });
                pane.getChildren().add(exit);

            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        return scoreButton;
    }

    /**
     * 获取保存棋谱按钮
     */
    private Button getSaveButton() {
        Button saveButton = new Button("保存棋谱");
        saveButton.setPrefSize(80, 30);
        saveButton.setLayoutX(WIDTH / 15.0 + 100 * 2);
        saveButton.setLayoutY(HEIGHT - 40);
        saveButton.setOnAction(event -> {
            FileChooser fileChooser = new FileChooser();
            fileChooser.getExtensionFilters().addAll(new ExtensionFilter("棋谱文件", "*.qipu"),
                    new ExtensionFilter("所有文件", "*.*"));
            File file = fileChooser.showSaveDialog(stage);
            if (file == null) {
                return;
            }
            try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
                for (int i = 0; i < count; i++) {
                    bw.write(cs[i].getX() + "," + cs[i].getY() + "," + cs[i].getColor());
                    bw.newLine();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        return saveButton;
    }

    /**
     * 获取退出按钮
     */
    private Button getQuitButton() {
        Button quitButton = new Button("退出");
        quitButton.setPrefSize(80, 30);
        quitButton.setLayoutX(WIDTH / 15.0 + 100 * 4);
        quitButton.setLayoutY(HEIGHT - 40);
        quitButton.setOnAction(event -> {
            Alert alert = new Alert(AlertType.CONFIRMATION);
            alert.setTitle("退出");
            alert.setHeaderText("确认提出吗?");
            Optional<ButtonType> optional = alert.showAndWait();
            if (optional.isPresent() && optional.get() == ButtonType.OK) {
                System.exit(0);
            }
        });
        return quitButton;
    }

    /**
     * 获取悔棋按钮
     */
    private Button getRetractButton() {
        Button retractButton = new Button("悔棋");
        retractButton.setPrefSize(80, 30);
        retractButton.setLayoutX(WIDTH / 15.0 + 100);
        retractButton.setLayoutY(HEIGHT - 40);
        retractButton.setOnAction(event -> retract());
        return retractButton;
    }

    /**
     * 获取再来一局按钮
     */
    private Button getStartButton() {
        // 添加按钮对象
        Button startButton = new Button("再来一局");
        startButton.setPrefSize(80, 30);
        startButton.setLayoutX(WIDTH / 15.0);
        startButton.setLayoutY(HEIGHT - 40);
        // 给按钮对象绑定鼠标点击事件
        startButton.setOnAction(event -> resetChessBoard());
        return startButton;
    }

    /**
     * 悔棋
     */
    private void retract() {
        if (isWin) {
            return;
        }
        if (count > 0) {
            pane.getChildren().remove(pane.getChildren().size() - 1);
            isBlack = !isBlack;
            Chess chess = cs[--count];
            chesses[chess.getX()][chess.getY()] = null;
            cs[count] = null;
        }
    }

    /**
     * 重置棋盘
     */
    private void resetChessBoard() {
        pane.getChildren().removeIf((Predicate<Object>) t -> t instanceof Circle);
        count = 0;
        chesses = new Chess[LINE_COUNT][LINE_COUNT];
        cs = new Chess[LINE_COUNT * LINE_COUNT];
        isBlack = true;
        isWin = false;
    }

    /**
     * 判断胜负
     */
    private boolean isWin(Chess chess) {
        int x = chess.getX();
        int y = chess.getY();
        Color color = chess.getColor();
        // 向右横向判断
        for (int i = x + 1; i <= x + 4 && i < LINE_COUNT; i++) {
            Chess c = chesses[i][y];
            if (c == null || !color.equals(c.getColor())) {
                break;
            }
            if (i == x + 4) {
                return true;
            }
        }
        // 向左横向判断
        for (int i = x - 1; i >= x - 4 && i >= 0; i--) {
            Chess c = chesses[i][y];
            if (c == null || !color.equals(c.getColor())) {
                break;
            }
            if (i == x - 4) {
                return true;
            }
        }
        // 向上纵向判断
        for (int i = y - 1; i >= y - 4 && i >= 0; i--) {
            Chess c = chesses[x][i];
            if (c == null || !color.equals(c.getColor())) {
                break;
            }
            if (i == y - 4) {
                return true;
            }
        }
        // 向下纵向判断
        for (int i = y + 1; i <= y + 4 && i < LINE_COUNT; i++) {
            Chess c = chesses[x][i];
            if (c == null || !color.equals(c.getColor())) {
                break;
            }
            if (i == y + 4) {
                return true;
            }
        }
        // 向右上斜向判断
        for (int i = x + 1, j = y - 1; i <= x + 4 && j >= y - 4 && i < LINE_COUNT && j >= 0; i++, j--) {
            Chess c = chesses[i][j];
            if (c == null || !color.equals(c.getColor())) {
                break;
            }
            if (i == x + 4 && j == y - 4) {
                return true;
            }
        }
        // 向左上斜向判断
        for (int i = x - 1, j = y - 1; i >= x - 4 && j >= y - 4 && i >= 0 && j >= 0; i--, j--) {
            Chess c = chesses[i][j];
            if (c == null || !color.equals(c.getColor())) {
                break;
            }
            if (i == x - 4 && j == y - 4) {
                return true;
            }
        }
        // 向左下斜向判断
        for (int i = x - 1, j = y + 1; i >= x - 4 && j <= y + 4 && i >= 0 && j < LINE_COUNT; i--, j++) {
            Chess c = chesses[i][j];
            if (c == null || !color.equals(c.getColor())) {
                break;
            }
            if (i == x - 4 && j == y + 4) {
                return true;
            }
        }
        // 向右下斜向判断
        for (int i = x + 1, j = y + 1; i <= x + 4 && j <= y + 4 && i < LINE_COUNT && j < LINE_COUNT; i++, j++) {
            Chess c = chesses[i][j];
            if (c == null || !color.equals(c.getColor())) {
                break;
            }
            if (i == x + 4 && j == y + 4) {
                return true;
            }
        }
        return false;
    }

    public static void main(String[] args) {
        launch(args);
    }
}
1

评论 (0)

取消