用lua语言实现康威生命游戏
用lua语言实现康威生命游戏
康威生命游戏1
这个游戏简单讲就是一个自动机,每个格子的细胞状态取决于周围八个格子的细胞
- 当细胞存活时
- 周围活细胞少于两个,会因孤独而死
- 周围活细胞多于三个,会因竞争而死
- 周围活细胞为二或三个时,则继续存活
- 当细胞死亡时
- 周围有三个活细胞,则复活(繁殖)
实现
1
2
3
4
5
env
OS: openSUSE Tumbleweed on Windows 10 x86_64
Kernel: 5.15.90.1-microsoft-standard-wsl2
Lua: Lua 5.4.6
Lua: LuaRocks 3.9.1
初始化棋盘和细胞
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- 定义细胞状态
local ALIVE = "⚫️"
local DEAD = " "
-- 创建游戏盘面
local width = 40
local height = 40
local board = {} -- 存储细胞(二维数组)
-- 初始化盘面
for i = 1, width do
board[i] = {}
for j = 1, height do
local r = math.random(1,10)
board[i][j] = ALIVE
if r<=7 then
board[i][j] = DEAD
end
end
end
......
在这我们使用二维数组存储每个细胞的状态,并且其中七成是死细胞
显示盘面
1
2
3
4
5
6
7
8
9
10
......
local function displayBoard()
for i = 1, width do
for j = 1, height do
io.write(board[i][j])
end
io.write("\n")
end
end
......
其实就是遍历所有细胞并且打印
统计周围细胞状态
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
......
function countAliveNeighbors(x, y)
local count = 0
-- 相邻格子的相对位置
local neighbors = {
{x - 1, y - 1}, {x, y - 1}, {x + 1, y - 1},
{x - 1, y}, {x + 1, y},
{x - 1, y + 1}, {x, y + 1}, {x + 1, y + 1}
}
for _, neighbor in ipairs(neighbors) do
local nx, ny = table.unpack(neighbor)
-- 判断相邻格子是否在边界内且为活细胞
if nx >= 1 and nx <= width and ny >= 1 and ny <= height and board[nx][ny] == ALIVE then
count = count + 1
end
end
return count
end
......
这个函数中ipairs(table)
将索引和可迭代对象绑定,即(1, table[1]), (2, table[2]), ...
table.unpack()
函数在 lua51 版本之前没有封装到 table 里,可以直接调用
更新盘面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
......
local function updateBoard()
local newBoard = {} -- 存储更新后细胞状态
for i = 1, width do
newBoard[i] = {}
for j = 1, height do
local aliveNeighbors = countAliveNeighbors(i, j)
if board[i][j] == ALIVE then
-- 活细胞周围活细胞数量不符合生存规则,则细胞死亡
if aliveNeighbors < 2 or aliveNeighbors > 3 then
newBoard[i][j] = DEAD
else
newBoard[i][j] = ALIVE
end
else
-- 死细胞周围有3个活细胞,则细胞复活
if aliveNeighbors == 3 then
newBoard[i][j] = ALIVE
else
newBoard[i][j] = DEAD
end
end
end
end
-- 更新盘面
board = newBoard
end
......
主循环
1
2
3
4
5
6
7
......
while true do
io.write("\27[2J\27[1;1H") -- 清空控制台输出
displayBoard()
updateBoard()
os.execute("sleep 1") -- 控制刷新速度
end
把以上内容拼到一起就可以得到一个能运行的生命游戏了
但是它真的只能运行而不能停下来
因为 lua 语言自身,它常常是嵌入在别的语言中,默认并不监听系统信号。
因此,我们要手动创建POSIX信号事件。
这里我们使用第三方的
luaposix
可以用lua包管理工具luarocks
安装
luarocks install luaposix
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
......
--引入POSIX模块
local posix = require("posix")
--退出标志
local exitKeyPressed = false
--信号处理回调函数
local function signalHandler(signal)
if signal == posix.SIGINT or signal == posix.SIGTERM then
exitKeyPressed = true
end
end
--注册信号处理函数
posix.signal(posix.SIGINT, signalHandler)
posix.signal(posix.SIGTERM, signalHandler)
......
并且修改主循环入口判断条件
1
2
3
4
5
6
7
......
while not exitKeyPressed do
io.write("\27[2J\27[1;1H") -- 清空控制台输出
displayBoard()
updateBoard()
posix.sleep(1) -- 使用posix控制速度,并监听信号
end
这样我们就可以使用ctrl-c
退出游戏了
ENDING
生生不息
本文由作者按照 CC BY 4.0 进行授权