Skip to content

Commit c084a67

Browse files
committed
Add classic game of life as example using the new os.sleep
1 parent 44e4c65 commit c084a67

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed

examples/gameoflife.nelua

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
require 'math'
2+
require 'os'
3+
require 'io'
4+
5+
local GRID_WIDTH <comptime> = 40
6+
local GRID_HEIGHT <comptime> = 15
7+
8+
-- Two-dimensional field of cells.
9+
local CellField = @record{
10+
cells: [GRID_HEIGHT][GRID_WIDTH]boolean,
11+
}
12+
13+
-- Returns an empty field.
14+
function CellField.new(): *CellField
15+
return new(@CellField)
16+
end
17+
18+
-- Sets the state of the specified cell to the given value..
19+
function CellField:set_alive(x: integer, y: integer, b: boolean)
20+
self.cells[y][x] = b
21+
end
22+
23+
--[[
24+
Reports whether the specified cell is alive.
25+
If the x or y coordinates are outside the field boundaries they are wrapped.
26+
]]
27+
function CellField:is_alive(x: integer, y: integer)
28+
return self.cells[(y + GRID_HEIGHT) % GRID_HEIGHT][(x + GRID_WIDTH) % GRID_WIDTH]
29+
end
30+
31+
-- Returns the state of the specified cell at the next time step.
32+
function CellField:next(x: integer, y: integer): boolean
33+
-- Count adjacent cells that are alive.
34+
local alive = 0
35+
for i=-1,1 do
36+
for j=-1,1 do
37+
if (j ~= 0 or i ~= 0) and self:is_alive(x+i, y+j) then
38+
alive = alive + 1
39+
end
40+
end
41+
end
42+
--[[
43+
Returns next state according to the game rules:
44+
- exactly 3 neighbors: on
45+
- exactly 2 neighbors: maintain current state
46+
- otherwise: off
47+
]]
48+
return alive == 3 or (alive == 2 and self:is_alive(x, y))
49+
end
50+
51+
-- Stores round state of Conway's Game of Life.
52+
local GameState = @record{
53+
a: *CellField, b: *CellField
54+
}
55+
56+
-- Returns a new game state with a random initial cells.
57+
function GameState.new(seed: integer): GameState
58+
math.randomseed(seed)
59+
local a = CellField.new()
60+
for i=1,GRID_WIDTH*GRID_HEIGHT/4 do
61+
a:set_alive(math.random(0, GRID_WIDTH-1), math.random(0, GRID_HEIGHT-1), true)
62+
end
63+
return (@GameState){a=a, b=CellField.new()}
64+
end
65+
66+
-- Advances the game by one instant, recomputing and updating all cells.
67+
function GameState:step()
68+
for y=0,GRID_HEIGHT-1 do
69+
for x=0,GRID_WIDTH-1 do
70+
self.b:set_alive(x, y, self.a:next(x, y))
71+
end
72+
end
73+
self.a, self.b = self.b, self.a -- swap fields
74+
end
75+
76+
-- Returns the game board as a string.
77+
function GameState:render()
78+
io.write("\27c") -- clear screen
79+
for y=0,GRID_HEIGHT-1 do
80+
for x=0,GRID_WIDTH-1 do
81+
io.write(self.a:is_alive(x, y) and 'O' or ' ') -- draw cell
82+
end
83+
io.write('\n')
84+
end
85+
io.flush() -- flush screen
86+
end
87+
88+
-- Create new game.
89+
local l = GameState.new(1)
90+
91+
-- Run game of life for 300 frames.
92+
for i=1,300 do
93+
l:step()
94+
l:render()
95+
os.sleep(1/24)
96+
end

0 commit comments

Comments
 (0)