上一篇
java怎么写五子棋
- 后端开发
- 2025-07-10
- 1
Java写五子棋,需创建棋盘数组,处理玩家落子逻辑,判断胜负条件(横、竖、斜),
Java中实现五子棋游戏,主要涉及图形界面设计、事件处理、棋盘绘制、落子逻辑以及胜负判断等关键部分,以下是详细的实现步骤和代码示例:
项目结构与类设计
为了实现五子棋游戏,我们可以采用面向对象的设计思想,将不同的功能模块封装到不同的类中,主要类包括:
- GameUI:负责创建和管理游戏的主界面,包括棋盘面板和功能按钮。
- ChessBoard:继承自JPanel,负责绘制棋盘和棋子,并处理鼠标点击事件以实现落子。
- GameController:负责管理游戏状态,如当前玩家、棋盘数据、胜负判断等。
- Point:用于表示棋盘上的坐标点,存储棋子的位置信息。
- Shape(可选):用于保存棋子的数据,如位置和颜色,便于图形重绘。
详细实现步骤
创建游戏主界面(GameUI)
创建一个主窗口类GameUI
,继承自JFrame
,设置窗口的基本属性,如大小、标题、关闭操作等,添加一个自定义的棋盘面板ChessBoard
和一个功能按钮面板,用于放置“开始”、“悔棋”、“复盘”等按钮。
import javax.swing.; import java.awt.; import java.awt.event.; public class GameUI extends JFrame { private ChessBoard chessBoard; private JPanel eastPanel; private GameController controller; public GameUI() { setTitle("五子棋游戏"); setSize(1000, 1000); setLocationRelativeTo(null); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 初始化控制器 controller = new GameController(this); // 创建棋盘面板 chessBoard = new ChessBoard(controller); add(chessBoard, BorderLayout.CENTER); // 创建功能按钮面板 eastPanel = new JPanel(); eastPanel.setPreferredSize(new Dimension(80, 0)); add(eastPanel, BorderLayout.EAST); // 添加功能按钮 String[] buttonNames = {"开始", "悔棋", "复盘"}; for (String name : buttonNames) { JButton button = new JButton(name); button.addActionListener(controller); eastPanel.add(button); } setVisible(true); } public static void main(String[] args) { new GameUI(); } }
绘制棋盘与棋子(ChessBoard)
ChessBoard
类继承自JPanel
,重写paintComponent
方法以绘制棋盘和棋子,通过MouseListener
监听鼠标点击事件,实现落子功能。
import javax.swing.; import java.awt.; import java.awt.event.; import java.util.ArrayList; public class ChessBoard extends JPanel implements MouseListener { private static final int MARGIN = 50; // 边距 private static final int GRID_SIZE = 30; // 格子大小 private static final int ROWS = 15; // 行数 private static final int COLS = 15; // 列数 private GameController controller; private boolean isBlack = true; // 当前玩家,黑棋先手 private boolean gameOver = false; // 游戏是否结束 private Point[] chessList = new Point[ROWS COLS]; // 存储棋子位置 private int chessCount = 0; // 当前棋子数量 public ChessBoard(GameController controller) { this.controller = controller; setBackground(Color.WHITE); addMouseListener(this); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // 绘制棋盘 g.setColor(Color.BLACK); for (int i = 0; i <= ROWS; i++) { g.drawLine(MARGIN, MARGIN + i GRID_SIZE, MARGIN + COLS GRID_SIZE, MARGIN + i GRID_SIZE); g.drawLine(MARGIN + i GRID_SIZE, MARGIN, MARGIN + i GRID_SIZE, MARGIN + ROWS GRID_SIZE); } // 绘制棋子 for (int i = 0; i < chessCount; i++) { Point p = chessList[i]; if (p != null) { g.setColor(isBlack ? Color.BLACK : Color.WHITE); g.fillOval(p.x GRID_SIZE / 2, p.y GRID_SIZE / 2, GRID_SIZE, GRID_SIZE); } } } @Override public void mouseClicked(MouseEvent e) { if (gameOver || chessCount == ROWS COLS || !controller.isStarted()) { return; } int x = e.getX(); int y = e.getY(); // 计算点击的格子位置 int row = (y MARGIN) / GRID_SIZE; int col = (x MARGIN) / GRID_SIZE; // 检查是否在棋盘范围内 if (row >= 0 && row < ROWS && col >= 0 && col < COLS) { // 检查该位置是否已有棋子 for (int i = 0; i < chessCount; i++) { Point p = chessList[i]; if (p != null && p.x == col GRID_SIZE + MARGIN && p.y == row GRID_SIZE + MARGIN) { JOptionPane.showMessageDialog(this, "该位置已有棋子!"); return; } } // 落子 chessList[chessCount++] = new Point(col GRID_SIZE + MARGIN, row GRID_SIZE + MARGIN); isBlack = !isBlack; // 切换玩家 repaint(); // 判断胜负 if (checkWin(row, col)) { gameOver = true; String winner = isBlack ? "白棋" : "黑棋"; JOptionPane.showMessageDialog(this, winner + "获胜!"); controller.resetGame(); } } } // 其他MouseListener方法空实现 @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {} // 判断是否有五子连珠 private boolean checkWin(int row, int col) { int[][] directions = {{1, 0}, {0, 1}, {1, 1}, {1, -1}}; // 四个方向 for (int[] dir : directions) { int count = 1; // 向一个方向搜索 int r = row + dir[0]; int c = col + dir[1]; while (r >= 0 && r < ROWS && c >= 0 && c < COLS) { boolean hasChess = false; for (int i = 0; i < chessCount; i++) { Point p = chessList[i]; if (p != null && p.x == c GRID_SIZE + MARGIN && p.y == r GRID_SIZE + MARGIN) { hasChess = true; break; } } if (hasChess) { count++; r += dir[0]; c += dir[1]; } else { break; } } // 向相反方向搜索 r = row dir[0]; c = col dir[1]; while (r >= 0 && r < ROWS && c >= 0 && c < COLS) { boolean hasChess = false; for (int i = 0; i < chessCount; i++) { Point p = chessList[i]; if (p != null && p.x == c GRID_SIZE + MARGIN && p.y == r GRID_SIZE + MARGIN) { hasChess = true; break; } } if (hasChess) { count++; r -= dir[0]; c -= dir[1]; } else { break; } } if (count >= 5) { return true; } } return false; } }
游戏控制器(GameController)
GameController
类负责管理游戏状态,包括游戏是否开始、重置游戏等,它还作为按钮的事件监听器,处理“开始”、“悔棋”、“复盘”等功能。
import java.awt.event.; import javax.swing.; public class GameController implements ActionListener { private GameUI ui; private boolean started = false; // 游戏是否开始 private ChessBoard board; private Point[] undoStack = new Point[225]; // 用于悔棋,假设最多悔棋225步 private int undoIndex = -1; // 悔棋栈指针 public GameController(GameUI ui) { this.ui = ui; this.board = (ChessBoard) ui.chessBoard; // 获取棋盘面板引用 } @Override public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); switch (command) { case "开始": startGame(); break; case "悔棋": regret(); break; case "复盘": replay(); break; default: break; } } // 开始游戏或重置游戏 public void startGame() { started = true; board.resetGame(); // 重置棋盘状态,包括清空棋子、重置标志位等 undoIndex = -1; // 清空悔棋栈 JOptionPane.showMessageDialog(ui, "游戏开始!"); } // 判断游戏是否已开始 public boolean isStarted() { return started; } // 重置游戏状态(由棋盘调用) public void resetGame() { started = false; // 游戏结束,重置开始标志 board.resetGame(); // 清空棋盘和棋子列表,重置标志位等 } // 悔棋功能 public void regret() { if (!started || undoIndex == -1) { JOptionPane.showMessageDialog(ui, "游戏未开始或无法悔棋!"); return; } // 移除最后一个棋子并记录到悔棋栈 Point lastMove = board.removeLastChess(); // 假设有此方法,返回被移除的棋子位置 if (lastMove != null) { undoStack[++undoIndex] = lastMove; // 压入悔棋栈 board.repaint(); // 重绘棋盘,显示悔棋后的状态 } else { JOptionPane.showMessageDialog(ui, "没有可悔棋的步数!"); } } // 复盘功能(简单实现为重新下一遍所有棋子) public void replay() { if (!started || undoIndex == -1) { JOptionPane.showMessageDialog(ui, "游戏未开始或无法复盘!"); return; } // 清空棋盘并禁用用户输入以防止干扰复盘过程(此处简化处理) board.clearAllChess(); // 清空棋盘上的所有棋子,但保留内部数据结构以便复盘使用(需在ChessBoard中实现) board.setReplaying(true); // 设置复盘模式,防止用户手动落子干扰(需在ChessBoard中实现) // TODO: 需要根据具体实现调整或删除此行代码,因为原问题中未提及相关方法或属性,这里仅为示意,实际使用时可能需要修改ChessBoard类以支持此功能,例如添加一个布尔属性isReplaying来控制是否允许用户手动落子,并在mouseClicked方法中检查该属性,由于原问题中未提供相关细节,这里仅作示意性说明,实际应用时请根据实际情况调整,以下代码假设ChessBoard中有相应的方法支持这些操作,如果不是这样,请忽略或修改这部分代码以适应您的实际实现,您可能需要在ChessBoard中添加一个方法来设置是否处于复盘模式,并在mouseClicked方法中检查该模式以决定是否允许用户落子,还需要确保在复盘过程中正确地恢复每个棋子的位置和颜色等信息,这可能涉及到遍历保存的棋子列表并按顺序重新绘制它们到棋盘上,由于这部分功能较为复杂且依赖于具体的实现细节,因此在此不再给出完整的示例代码,但基本思路是:在复盘时,按照保存的棋子顺序依次将它们重新添加到棋盘上,并适当延迟以确保用户可以看到每一步的变化过程,您可以使用Timer或线程来实现这种延迟效果,当所有棋子都重新绘制完毕后,退出复盘模式并允许用户继续正常游戏,注意:上述代码中的一些方法和属性(如setReplaying、isReplaying、clearAllChess等)需要在ChessBoard类中进行相应的定义和实现才能正常工作,如果您的ChessBoard类中尚未包含这些内容,请根据需要进行添加和修改,请注意处理好各种边界情况和异常情况以确保程序的稳定性和健壮性,在复盘过程中如果用户尝试手动落子应该如何处理?是否需要暂停复盘过程?这些都是在实际开发中需要考虑的问题,由于篇幅所限,这里无法给出所有可能的情况的处理代码,建议您根据实际需求