用Java写一个可视化的五子棋人机对弈小程序
时间: 2023-12-05 20:03:32 浏览: 124
好的,下面是一个简单的五子棋人机对弈小程序的示例代码,基于 Java Swing 编写。
```java
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Gobang extends JFrame implements ActionListener, MouseListener {
private static final long serialVersionUID = 1L;
private JPanel panel;
private JButton button;
private JLabel label1, label2;
private int[][] chessBoard;
private boolean isBlack = true;
private boolean gameOver = false;
private final int ROWS = 15;
private final int COLS = 15;
private final int SIZE = 30;
private final int MARGIN = 30;
public Gobang() {
setTitle("五子棋");
setSize(600, 600);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
init();
setVisible(true);
}
private void init() {
panel = new JPanel();
panel.setBackground(new Color(255, 204, 102));
panel.setLayout(null);
panel.addMouseListener(this);
button = new JButton("重新开始");
button.addActionListener(this);
button.setBounds(450, 120, 100, 40);
label1 = new JLabel("黑方先手");
label1.setFont(new Font("宋体", Font.BOLD, 20));
label1.setBounds(450, 200, 150, 40);
label2 = new JLabel("轮到黑方");
label2.setFont(new Font("宋体", Font.BOLD, 20));
label2.setBounds(450, 250, 150, 40);
panel.add(button);
panel.add(label1);
panel.add(label2);
add(panel);
chessBoard = new int[ROWS][COLS];
}
private void drawChessBoard(Graphics g) {
for (int i = 0; i <= ROWS; i++) {
g.drawLine(MARGIN, MARGIN + i * SIZE, MARGIN + COLS * SIZE, MARGIN + i * SIZE);
}
for (int i = 0; i <= COLS; i++) {
g.drawLine(MARGIN + i * SIZE, MARGIN, MARGIN + i * SIZE, MARGIN + ROWS * SIZE);
}
}
private void drawChessPiece(Graphics g, int row, int col, boolean isBlack) {
int x = MARGIN + col * SIZE;
int y = MARGIN + row * SIZE;
g.setColor(isBlack ? Color.BLACK : Color.WHITE);
g.fillOval(x - SIZE / 2, y - SIZE / 2, SIZE, SIZE);
}
private boolean checkWin(int row, int col) {
int count = 1;
int color = chessBoard[row][col];
int r, c;
// 检查水平方向
r = row;
c = col - 1;
while (c >= 0 && chessBoard[r][c] == color) {
count++;
c--;
}
c = col + 1;
while (c < COLS && chessBoard[r][c] == color) {
count++;
c++;
}
if (count >= 5) {
return true;
}
// 检查竖直方向
count = 1;
r = row - 1;
c = col;
while (r >= 0 && chessBoard[r][c] == color) {
count++;
r--;
}
r = row + 1;
while (r < ROWS && chessBoard[r][c] == color) {
count++;
r++;
}
if (count >= 5) {
return true;
}
// 检查左斜方向
count = 1;
r = row - 1;
c = col - 1;
while (r >= 0 && c >= 0 && chessBoard[r][c] == color) {
count++;
r--;
c--;
}
r = row + 1;
c = col + 1;
while (r < ROWS && c < COLS && chessBoard[r][c] == color) {
count++;
r++;
c++;
}
if (count >= 5) {
return true;
}
// 检查右斜方向
count = 1;
r = row - 1;
c = col + 1;
while (r >= 0 && c < COLS && chessBoard[r][c] == color) {
count++;
r--;
c++;
}
r = row + 1;
c = col - 1;
while (r < ROWS && c >= 0 && chessBoard[r][c] == color) {
count++;
r++;
c--;
}
if (count >= 5) {
return true;
}
return false;
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == button) {
chessBoard = new int[ROWS][COLS];
isBlack = true;
gameOver = false;
label1.setText("黑方先手");
label2.setText("轮到黑方");
panel.repaint();
}
}
@Override
public void mouseClicked(MouseEvent e) {
if (gameOver) {
return;
}
int x = e.getX();
int y = e.getY();
if (x < MARGIN || x > MARGIN + COLS * SIZE || y < MARGIN || y > MARGIN + ROWS * SIZE) {
return;
}
int row = Math.round((float) (y - MARGIN) / SIZE);
int col = Math.round((float) (x - MARGIN) / SIZE);
if (chessBoard[row][col] != 0) {
return;
}
chessBoard[row][col] = isBlack ? 1 : 2;
panel.repaint();
if (checkWin(row, col)) {
gameOver = true;
String winner = isBlack ? "黑方" : "白方";
JOptionPane.showMessageDialog(panel, winner + "获胜!", "游戏结束", JOptionPane.INFORMATION_MESSAGE);
return;
}
isBlack = !isBlack;
label1.setText(isBlack ? "黑方先手" : "白方先手");
label2.setText(isBlack ? "轮到黑方" : "轮到白方");
if (!isBlack) {
// AI 下棋
int[] pos = computeNextMove();
row = pos[0];
col = pos[1];
chessBoard[row][col] = 2;
panel.repaint();
if (checkWin(row, col)) {
gameOver = true;
JOptionPane.showMessageDialog(panel, "白方获胜!", "游戏结束", JOptionPane.INFORMATION_MESSAGE);
return;
}
isBlack = !isBlack;
label1.setText(isBlack ? "黑方先手" : "白方先手");
label2.setText(isBlack ? "轮到黑方" : "轮到白方");
}
}
private int[] computeNextMove() {
int[] pos = new int[2];
// TODO: AI 算法
return pos;
}
@Override
public void paint(Graphics g) {
super.paint(g);
drawChessBoard(g);
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
if (chessBoard[i][j] == 1) {
drawChessPiece(g, i, j, true);
} else if (chessBoard[i][j] == 2) {
drawChessPiece(g, i, j, false);
}
}
}
}
@Override
public void mousePressed(MouseEvent e) {}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
public static void main(String[] args) {
new Gobang();
}
}
```
这个程序由一个主窗口和一个 JPanel 组成。主窗口负责创建并显示 JPanel,JPanel 则绘制棋盘和棋子,并处理用户交互和游戏逻辑。
在 JPanel 的构造函数中,我们初始化了棋盘数组 `chessBoard`,表示棋盘上每个格子的状态。1 表示黑子,2 表示白子,0 表示空格。我们还添加了一个按钮和两个标签,用于重新开始游戏和显示游戏状态。
在 `drawChessBoard` 方法中,我们使用 Graphics 类的 `drawLine` 方法绘制棋盘的线条。
在 `drawChessPiece` 方法中,我们使用 Graphics 类的 `fillOval` 方法绘制棋子。黑子用黑色填充,白子用白色填充。
在 `checkWin` 方法中,我们检查棋盘上某个格子所处的行、列、左斜方向和右斜方向是否有连续五个相同颜色的棋子。如果有,则游戏结束。
在 `actionPerformed` 方法中,我们对重新开始按钮的点击事件进行处理。重新初始化棋盘数组、重置游戏状态和标签,并调用 JPanel 的 `repaint` 方法刷新界面。
在 `mouseClicked` 方法中,我们处理鼠标点击事件。如果游戏已经结束或点击了棋盘外部或已经有棋子存在,则不做任何处理。否则,我们根据鼠标点击坐标计算出所在的行和列,将这个位置设为当前玩家下的棋子。然后检查游戏是否结束,并切换当前玩家。如果当前玩家是电脑,则调用 `computeNextMove` 方法计算出下一个位置,并执行相同的操作。
在 `paint` 方法中,我们使用 Graphics 类的 `paint` 方法绘制棋盘和棋子。
在 `computeNextMove` 方法中,我们需要实现一个 AI 算法,来计算出电脑下一步应该走的位置。这里我们暂时留空,可以自己实现一个简单的算法,比如随机生成一个空白位置,作为电脑的下一步。
最后,在 `main` 方法中,我们创建一个新的 Gobang 对象,启动程序。
阅读全文