1.代码
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# 定义细胞的状态常量
ALIVE = 1
DEAD = 0
# 定义网格的大小和细胞的初始状态
grid_size = 100
init_config = np.random.choice([ALIVE, DEAD], size=(grid_size, grid_size))
# 定义细胞自动机的规则
def get_new_state(grid, i, j):
# 获取相邻细胞的状态
neighbors = grid[max(i - 1, 0):min(i + 2, grid_size), max(j - 1, 0):min(j + 2, grid_size)]
# 计算相邻活细胞的数量
alive_neighbors = np.count_nonzero(neighbors) - grid[i, j]
# 更新细胞状态
if grid[i, j] == ALIVE and 2 <= alive_neighbors <= 3:
return ALIVE
elif grid[i, j] == DEAD and alive_neighbors == 3:
return ALIVE
else:
return DEAD
# 初始化细胞状态
grid = init_config
# 初始化可视化
fig, ax = plt.subplots()
im = ax.imshow(grid, cmap='Greys', interpolation='nearest')
# 更新细胞状态的回调函数
def update(frameNum, grid, im):
new_grid = np.zeros((grid_size, grid_size))
for i in range(grid_size):
for j in range(grid_size):
new_grid[i, j] = get_new_state(grid, i, j)
im.set_data(new_grid)
grid[:] = new_grid[:]
return im,
# 使用 FuncAnimation 实现动画
ani = animation.FuncAnimation(fig, update, fargs=(grid, im), frames=100, interval=50, blit=True)
plt.show()
这段代码实现了一个生命游戏的动画,生命游戏是一种细胞自动机,它由一个二维的网格和一些简单的规则组成。这些规则决定了每个细胞在下一次迭代中是否存活或死亡。
在这段代码中,首先定义了细胞的状态常量,然后生成了一个随机的初始配置。接着定义了一个函数来计算每个细胞的新状态。这个函数会获取相邻细胞的状态,并根据规则计算新的状态。然后在主函数中初始化了细胞状态和可视化,并使用 FuncAnimation 实现了动画。在动画中,每一帧都会调用 update 函数来更新细胞的状态,并将更新后的状态显示在可视化中。
2.HTML
<!DOCTYPE html>
<html>
<head>
<title>元胞自动机</title>
</head>
<body style="background-color: #d8d8d8;">
<canvas id="canvas"></canvas>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const width = 576;
const height = 864;
canvas.width = width;
canvas.height = height;
let cells = [];
for (let i = 0; i < width; i++) {
cells[i] = [];
}
for (let i = 0; i < width; i++) {
for (let j = 0; j < height; j++) {
cells[i][j] = Math.floor(Math.random() * 2);
}
}
function update() {
let newCells = [];
for (let i = 0; i < width; i++) {
newCells[i] = [];
}
for (let i = 0; i < width; i++) {
for (let j = 0; j < height; j++) {
const neighbors = countNeighbors(cells, i, j);
if (cells[i][j] === 0 && neighbors === 3) {
newCells[i][j] = 1;
} else if (cells[i][j] === 1 && (neighbors < 2 || neighbors > 3)) {
newCells[i][j] = 0;
} else {
newCells[i][j] = cells[i][j];
}
}
}
cells = newCells;
}
function countNeighbors(cells, x, y) {
let count = 0;
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
const row = (x + i + width) % width;
const col = (y + j + height) % height;
if (cells[row][col] === 1) {
count++;
}
}
}
return count;
}
function render() {
ctx.clearRect(0, 0, width, height);
for (let i = 0; i < width; i++) {
for (let j = 0; j < height; j++) {
if (cells[i][j] === 1) {
ctx.fillStyle = 'black';
} else {
ctx.fillStyle = '#79c995';
}
ctx.fillRect(i, j, 1, 1);
}
}
}
setInterval(function () {
update();
render();
}, 100);
</script>
</body>
</html>