You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助实现双人对战版井字棋功能及代码优化建议

双人井字棋实现与代码优化方案

嘿,我来帮你搞定这个双人井字棋的问题,同时给你一些靠谱的代码精简建议!结合你用Swing框架的现状,我拆解成核心功能补全和代码优化两部分来讲:

一、核心功能补全:双人玩家切换与胜负判定

首先解决你卡壳的双人操作和胜负判定问题,直接给你可落地的逻辑:

1. 玩家状态管理

在你的类里加一个boolean变量private boolean isPlayerX = true;,用来标记当前轮到哪个玩家——true是X,false是O。每次玩家落子后切换这个状态,就能实现轮流操作。

2. 胜负判定逻辑

写一个独立的checkWin()方法,专门检查横、竖、对角线是否有三连相同标记,用二维数组记录棋盘状态的话,逻辑会很清晰:

private boolean checkWin(char[][] board) {
    // 检查横排三连
    for (int i = 0; i < 3; i++) {
        if (board[i][0] != ' ' && board[i][0] == board[i][1] && board[i][1] == board[i][2]) {
            return true;
        }
    }
    // 检查竖排三连
    for (int j = 0; j < 3; j++) {
        if (board[0][j] != ' ' && board[0][j] == board[1][j] && board[1][j] == board[2][j]) {
            return true;
        }
    }
    // 检查两条对角线
    return (board[0][0] != ' ' && board[0][0] == board[1][1] && board[1][1] == board[2][2])
            || (board[0][2] != ' ' && board[0][2] == board[1][1] && board[1][1] == board[2][0]);
}

别忘了加个平局判断的方法isBoardFull(),检查所有格子是否都被填满:

private boolean isBoardFull(char[][] board) {
    for (char[] row : board) {
        for (char c : row) {
            if (c == ' ') return false;
        }
    }
    return true;
}

3. 双人操作整合到点击事件里

在按钮的点击监听器中,先判断当前格子是否为空,然后根据玩家状态落子,之后切换玩家,再调用胜负和平局判断:

ActionListener buttonListener = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        JButton clickedBtn = (JButton) e.getSource();
        if (clickedBtn.getText().isEmpty()) {
            char mark = isPlayerX ? 'X' : 'O';
            clickedBtn.setText(String.valueOf(mark));
            updateBoard(clickedBtn, mark); // 同步更新棋盘数组

            if (checkWin(board)) {
                JOptionPane.showMessageDialog(TicTacToe.this, "玩家 " + mark + " 获胜!");
                resetBoard();
            } else if (isBoardFull(board)) {
                JOptionPane.showMessageDialog(TicTacToe.this, "平局!");
                resetBoard();
            }
            isPlayerX = !isPlayerX; // 切换玩家
        }
    }
};

二、代码精简优化建议

你的代码冗长主要是因为重复初始化和冗余逻辑,这几个点可以大幅优化:

1. 去掉重复的JFrame实例

你已经让类继承了JFrame,就没必要再创建JFrame f = new JFrame(...)了,直接用this操作当前窗口就行,比如this.setTitle("井字棋");,避免重复创建对象。

2. 用循环批量创建棋盘按钮

别一个个写9个按钮的初始化代码,用嵌套循环生成二维数组的按钮,既简洁又方便后续操作:

JButton[][] buttons = new JButton[3][3];
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        buttons[i][j] = new JButton();
        buttons[i][j].setFont(new Font("Arial", Font.PLAIN, 40));
        buttons[i][j].addActionListener(buttonListener); // 共用同一个监听器
        this.add(buttons[i][j]);
    }
}

3. 提取重复逻辑为独立方法

比如重置棋盘、初始化棋盘、更新棋盘状态这些操作,都写成单独的方法,避免在多个地方重复写相同代码。比如重置棋盘:

private void resetBoard() {
    // 重置棋盘数组
    for (int i = 0; i < 3; i++) {
        Arrays.fill(board[i], ' ');
    }
    // 清空所有按钮文本
    for (JButton[] row : buttons) {
        for (JButton btn : row) {
            btn.setText("");
        }
    }
    isPlayerX = true; // 回到X玩家先手
}

4. 共用事件监听器实例

不要给每个按钮都新建匿名内部类的监听器,创建一个单独的监听器实例,所有按钮都用它,减少内存占用和代码冗余。

三、完整优化后的核心代码

我把上面的逻辑整合起来,给你一个精简后的完整代码片段,你可以直接参考:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;

public class TicTacToe extends JFrame {
    private JButton[][] buttons = new JButton[3][3];
    private char[][] board = new char[3][3];
    private boolean isPlayerX = true;

    public TicTacToe() {
        initUI();
        initBoard();
    }

    private void initUI() {
        this.setTitle("双人井字棋");
        this.setSize(400, 400);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setLayout(new GridLayout(3, 3));

        // 共用的按钮点击监听器
        ActionListener buttonListener = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JButton clickedBtn = (JButton) e.getSource();
                if (clickedBtn.getText().isEmpty()) {
                    char mark = isPlayerX ? 'X' : 'O';
                    clickedBtn.setText(String.valueOf(mark));
                    updateBoard(clickedBtn, mark);

                    if (checkWin(board)) {
                        JOptionPane.showMessageDialog(TicTacToe.this, "玩家 " + mark + " 获胜!");
                        resetBoard();
                    } else if (isBoardFull(board)) {
                        JOptionPane.showMessageDialog(TicTacToe.this, "平局!");
                        resetBoard();
                    }
                    isPlayerX = !isPlayerX;
                }
            }
        };

        // 循环创建棋盘按钮
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                buttons[i][j] = new JButton();
                buttons[i][j].setFont(new Font("Arial", Font.PLAIN, 40));
                buttons[i][j].addActionListener(buttonListener);
                this.add(buttons[i][j]);
            }
        }
    }

    // 初始化棋盘数组
    private void initBoard() {
        for (int i = 0; i < 3; i++) {
            Arrays.fill(board[i], ' ');
        }
    }

    // 根据点击的按钮更新棋盘数组
    private void updateBoard(JButton btn, char mark) {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (buttons[i][j] == btn) {
                    board[i][j] = mark;
                    return;
                }
            }
        }
    }

    // 胜负判定
    private boolean checkWin(char[][] board) {
        // 横排检查
        for (int i = 0; i < 3; i++) {
            if (board[i][0] != ' ' && board[i][0] == board[i][1] && board[i][1] == board[i][2]) {
                return true;
            }
        }
        // 竖排检查
        for (int j = 0; j < 3; j++) {
            if (board[0][j] != ' ' && board[0][j] == board[1][j] && board[1][j] == board[2][j]) {
                return true;
            }
        }
        // 对角线检查
        return (board[0][0] != ' ' && board[0][0] == board[1][1] && board[1][1] == board[2][2])
                || (board[0][2] != ' ' && board[0][2] == board[1][1] && board[1][1] == board[2][0]);
    }

    // 平局判定
    private boolean isBoardFull(char[][] board) {
        for (char[] row : board) {
            for (char c : row) {
                if (c == ' ') return false;
            }
        }
        return true;
    }

    // 重置棋盘
    private void resetBoard() {
        initBoard();
        for (JButton[] row : buttons) {
            for (JButton btn : row) {
                btn.setText("");
            }
        }
        isPlayerX = true;
    }

    public static void main(String[] args) {
        // Swing线程安全启动
        SwingUtilities.invokeLater(() -> {
            TicTacToe game = new TicTacToe();
            game.setVisible(true);
        });
    }
}

这个版本的代码结构更清晰,冗余代码被大量精简,同时完整实现了双人对战、胜负判定和平局处理的功能,你可以直接替换你的现有代码或者参考修改。

内容的提问来源于stack exchange,提问作者RamboCode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:40:49