Java康威生命游戏(Conway‘s Game of Life)

发布于:2025-03-31 ⋅ 阅读:(25) ⋅ 点赞:(0)

这段 Java 代码实现了一个三维版本的康威生命游戏(Conway's Game of Life)的图形用户界面(GUI)程序。康威生命游戏是一个零玩家游戏,它包括一个二维或多维的网格,每个网格中的细胞有存活或死亡两种状态,根据其周围细胞的存活情况按照一定规则进行迭代更新。此程序模拟了一个三维的细胞世界,并且通过 JFrame 和 JPanel 提供了可视化的界面,以一定的时间间隔展示细胞状态的演化。

类和成员变量说明

类定义

java

public class ThreeDimensionalConwayGameOfLifeGUI extends JFrame {

  • ThreeDimensionalConwayGameOfLifeGUI 类继承自 JFrame,这意味着它是一个窗口,用于承载游戏的可视化界面。
静态常量

java

private static final int SIZE_X = 20;
private static final int SIZE_Y = 20;
private static final int SIZE_Z = 20;
private static final int CELL_SIZE = 10;
private static final int DELAY = 500;

  • SIZE_XSIZE_Y 和 SIZE_Z:分别表示三维网格在 x、y、z 三个方向上的大小,即细胞世界的尺寸。
  • CELL_SIZE:每个细胞在界面上显示的大小(像素)。
  • DELAY:定时器的延迟时间(毫秒),控制细胞状态更新的时间间隔。
成员变量

java

private boolean[][][] currentGeneration;
private boolean[][][] nextGeneration;
private GamePanel gamePanel;
private Timer timer;

  • currentGeneration:一个三维布尔数组,用于存储当前代细胞的存活状态。
  • nextGeneration:同样是三维布尔数组,用于存储下一代细胞的存活状态。
  • gamePanelGamePanel 类的实例,用于绘制细胞的可视化界面。
  • timerTimer 类的实例,用于定时触发细胞状态的更新和界面的重绘。

方法说明

构造函数 ThreeDimensionalConwayGameOfLifeGUI()

java

public ThreeDimensionalConwayGameOfLifeGUI() {
    currentGeneration = new boolean[SIZE_X][SIZE_Y][SIZE_Z];
    nextGeneration = new boolean[SIZE_X][SIZE_Y][SIZE_Z];
    initializeRandomly();

    gamePanel = new GamePanel();
    add(gamePanel);

    timer = new Timer(DELAY, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            evolve();
            gamePanel.repaint();
        }
    });
    timer.start();

    setTitle("三维康威生命游戏");
    setSize(SIZE_X * CELL_SIZE, SIZE_Y * CELL_SIZE);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    setVisible(true);
}

  • 初始化 currentGeneration 和 nextGeneration 数组。
  • 调用 initializeRandomly() 方法随机初始化当前代细胞的存活状态。
  • 创建 GamePanel 实例并添加到窗口中。
  • 创建一个 Timer 对象,设置延迟时间为 DELAY 毫秒,每次触发时调用 evolve() 方法更新细胞状态并调用 gamePanel.repaint() 方法重绘界面。
  • 设置窗口的标题、大小、关闭操作、位置并使其可见。
initializeRandomly() 方法

java

private void initializeRandomly() {
    Random random = new Random();
    for (int x = 0; x < SIZE_X; x++) {
        for (int y = 0; y < SIZE_Y; y++) {
            for (int z = 0; z < SIZE_Z; z++) {
                currentGeneration[x][y][z] = random.nextBoolean();
            }
        }
    }
}

  • 使用 Random 类随机为 currentGeneration 数组中的每个元素赋值(true 或 false),以此随机初始化细胞的存活状态。
countNeighbors(int x, int y, int z) 方法

java

private int countNeighbors(int x, int y, int z) {
    int count = 0;
    for (int dx = -1; dx <= 1; dx++) {
        for (int dy = -1; dy <= 1; dy++) {
            for (int dz = -1; dz <= 1; dz++) {
                if (dx == 0 && dy == 0 && dz == 0) {
                    continue;
                }
                int newX = x + dx;
                int newY = y + dy;
                int newZ = z + dz;
                if (isValidCoordinate(newX, newY, newZ) && currentGeneration[newX][newY][newZ]) {
                    count++;
                }
            }
        }
    }
    return count;
}

  • 计算指定坐标 (x, y, z) 处细胞的存活邻居数量。
  • 通过三层嵌套循环遍历该细胞周围的 26 个邻居(除去自身),调用 isValidCoordinate() 方法检查邻居坐标是否有效,若有效且邻居细胞存活则计数器加 1。
isValidCoordinate(int x, int y, int z) 方法

java

private boolean isValidCoordinate(int x, int y, int z) {
    return x >= 0 && x < SIZE_X && y >= 0 && y < SIZE_Y && z >= 0 && z < SIZE_Z;
}

  • 检查给定的坐标 (x, y, z) 是否在三维网格的有效范围内。
  • 如果坐标在范围内返回 true,否则返回 false
evolve() 方法

java

public void evolve() {
    for (int x = 0; x < SIZE_X; x++) {
        for (int y = 0; y < SIZE_Y; y++) {
            for (int z = 0; z < SIZE_Z; z++) {
                int neighbors = countNeighbors(x, y, z);
                if (currentGeneration[x][y][z]) {
                    // 存活细胞规则
                    nextGeneration[x][y][z] = neighbors == 3 || neighbors == 4 || neighbors == 5;
                } else {
                    // 死亡细胞规则
                    nextGeneration[x][y][z] = neighbors == 4;
                }
            }
        }
    }
    // 更新当前代
    for (int x = 0; x < SIZE_X; x++) {
        for (int y = 0; y < SIZE_Y; y++) {
            for (int z = 0; z < SIZE_Z; z++) {
                currentGeneration[x][y][z] = nextGeneration[x][y][z];
            }
        }
    }
}

  • 进行细胞状态的更新,模拟一代的演化。
  • 首先遍历整个三维网格,对于每个细胞,调用 countNeighbors() 方法计算其存活邻居数量。
  • 根据存活邻居数量和当前细胞状态,按照规则更新 nextGeneration 数组:
    • 若当前细胞存活,当邻居数量为 3、4 或 5 时,下一代细胞存活,否则死亡。
    • 若当前细胞死亡,当邻居数量为 4 时,下一代细胞存活,否则死亡。
  • 最后将 nextGeneration 数组的值复制到 currentGeneration 数组中,完成当前代的更新。
GamePanel 内部类

java

private class GamePanel extends JPanel {
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (int x = 0; x < SIZE_X; x++) {
            for (int y = 0; y < SIZE_Y; y++) {
                for (int z = 0; z < SIZE_Z; z++) {
                    if (currentGeneration[x][y][z]) {
                        g.setColor(Color.BLACK);
                    } else {
                        g.setColor(Color.WHITE);
                    }
                    g.fillRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
                }
            }
        }
    }
}

  • GamePanel 类继承自 JPanel,用于绘制细胞的可视化界面。
  • 重写 paintComponent() 方法,遍历 currentGeneration 数组,根据细胞的存活状态设置绘制颜色(存活为黑色,死亡为白色),并在界面上绘制相应的矩形。
main() 方法

java

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            new ThreeDimensionalConwayGameOfLifeGUI();
        }
    });
}

  • 使用 SwingUtilities.invokeLater() 方法确保在事件调度线程中创建和显示 GUI,避免线程安全问题。
  • 创建 ThreeDimensionalConwayGameOfLifeGUI 类的实例,启动游戏。

完整代码

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

public class ThreeDimensionalConwayGameOfLifeGUI extends JFrame {
    private static final int SIZE_X = 20;
    private static final int SIZE_Y = 20;
    private static final int SIZE_Z = 20;
    private static final int CELL_SIZE = 10;
    private static final int DELAY = 500;
    private boolean[][][] currentGeneration;
    private boolean[][][] nextGeneration;
    private GamePanel gamePanel;
    private Timer timer;

    public ThreeDimensionalConwayGameOfLifeGUI() {
        currentGeneration = new boolean[SIZE_X][SIZE_Y][SIZE_Z];
        nextGeneration = new boolean[SIZE_X][SIZE_Y][SIZE_Z];
        initializeRandomly();

        gamePanel = new GamePanel();
        add(gamePanel);

        timer = new Timer(DELAY, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                evolve();
                gamePanel.repaint();
            }
        });
        timer.start();

        setTitle("三维康威生命游戏");
        setSize(SIZE_X * CELL_SIZE, SIZE_Y * CELL_SIZE);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private void initializeRandomly() {
        Random random = new Random();
        for (int x = 0; x < SIZE_X; x++) {
            for (int y = 0; y < SIZE_Y; y++) {
                for (int z = 0; z < SIZE_Z; z++) {
                    currentGeneration[x][y][z] = random.nextBoolean();
                }
            }
        }
    }

    private int countNeighbors(int x, int y, int z) {
        int count = 0;
        for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                for (int dz = -1; dz <= 1; dz++) {
                    if (dx == 0 && dy == 0 && dz == 0) {
                        continue;
                    }
                    int newX = x + dx;
                    int newY = y + dy;
                    int newZ = z + dz;
                    if (isValidCoordinate(newX, newY, newZ) && currentGeneration[newX][newY][newZ]) {
                        count++;
                    }
                }
            }
        }
        return count;
    }

    private boolean isValidCoordinate(int x, int y, int z) {
        return x >= 0 && x < SIZE_X && y >= 0 && y < SIZE_Y && z >= 0 && z < SIZE_Z;
    }

    public void evolve() {
        for (int x = 0; x < SIZE_X; x++) {
            for (int y = 0; y < SIZE_Y; y++) {
                for (int z = 0; z < SIZE_Z; z++) {
                    int neighbors = countNeighbors(x, y, z);
                    if (currentGeneration[x][y][z]) {
                        // 存活细胞规则
                        nextGeneration[x][y][z] = neighbors == 3 || neighbors == 4 || neighbors == 5;
                    } else {
                        // 死亡细胞规则
                        nextGeneration[x][y][z] = neighbors == 4;
                    }
                }
            }
        }
        // 更新当前代
        for (int x = 0; x < SIZE_X; x++) {
            for (int y = 0; y < SIZE_Y; y++) {
                for (int z = 0; z < SIZE_Z; z++) {
                    currentGeneration[x][y][z] = nextGeneration[x][y][z];
                }
            }
        }
    }

    private class GamePanel extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            for (int x = 0; x < SIZE_X; x++) {
                for (int y = 0; y < SIZE_Y; y++) {
                    for (int z = 0; z < SIZE_Z; z++) {
                        if (currentGeneration[x][y][z]) {
                            g.setColor(Color.BLACK);
                        } else {
                            g.setColor(Color.WHITE);
                        }
                        g.fillRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new ThreeDimensionalConwayGameOfLifeGUI();
            }
        });
    }
}