pixels.lua
· 6.9 KiB · Lua
Ham
Playground
local pprint = require "pprint"
love.graphics.setDefaultFilter("nearest", "nearest")
local read, write = 1, 1
local active_buffer, back_buffer, rule_book = {}, {}, {}
local function parse(str)
local symbols = {}
for symbol in str:gmatch("%S+") do
table.insert(symbols, symbol)
end
return symbols
end
local function queue_up(string)
for _, symbol in ipairs(parse(string)) do
table.insert(active_buffer, symbol)
end
end
local function add_rule(wants)
return function(gives)
table.insert(rule_book, {parse(wants), type(gives) == "string" and parse(gives) or gives})
end
end
local function match(wants)
for i = 1, #wants do
if wants[i] ~= active_buffer[i + read - 1] then return false end
end
return true
end
local function consume(n)
read = read + n
end
local function peek(n)
local symbols = {}
for i = 0, n - 1 do
table.insert(symbols, active_buffer[read + i])
end
return symbols
end
local function take_next(n)
n = n or 1
local symbol = active_buffer[read]
read = read + 1
return symbol
end
local function produce(gives)
for _, symbol in ipairs(gives) do
back_buffer[write] = symbol
write = write + 1
end
end
local function advance()
back_buffer[write], active_buffer[read] = active_buffer[read], nil
write, read = write + 1, read + 1
end
local function run_cycle()
local rule_matched = false
repeat
local rule_fired = false
for _, rule in ipairs(rule_book) do
local wants, gives = rule[1], rule[2]
if match(wants) then
consume(#wants)
if type(gives) == "function" then
gives(active_buffer, read)
else
produce(gives)
end
rule_fired, rule_matched = true, true
break
end
end
if not rule_fired then advance() end
until not active_buffer[read]
return rule_matched
end
local function exchange_buffers()
active_buffer, back_buffer = back_buffer, {}
read, write = 1, 1
end
local cycles, MAX_CYCLES = 0, 10000
local function run()
while run_cycle() and cycles < MAX_CYCLES do
print(table.concat(back_buffer, " "))
exchange_buffers()
cycles = cycles + 1
end
end
local current_sprite
local sprites = {}
local screen = love.graphics.newCanvas()
add_rule "@ sprite [" (function()
current_sprite = { data = {{}} }
produce {"sprite>"}
end)
add_rule "sprite> name is" (function()
current_sprite.name = take_next()
produce { "sprite>" }
end)
add_rule "sprite> symbol is" (function()
current_sprite.symbol = take_next()
produce { "sprite>" }
end)
add_rule "sprite> ;" (function()
table.insert(current_sprite.data, {})
produce { "sprite>" }
end)
add_rule "sprite> ]" (function()
-- find longest row in data
local longest_row = -1
for _, row in ipairs(current_sprite.data) do
if #row > longest_row then longest_row = #row end
end
-- pad out other rows
for _, row in ipairs(current_sprite.data) do
while #row < longest_row do
table.insert(row, ".")
end
end
-- construct a canvas for our sprite
print(#current_sprite.data)
local sprite = love.graphics.newCanvas(longest_row, #current_sprite.data)
love.graphics.setCanvas(sprite)
local x, y = 0, 0
for _, row in ipairs(current_sprite.data) do
for _, data in ipairs(row) do
if data == "#" then
love.graphics.points(x + 0.5, y + 0.5)
end
x = x + 1
end
x, y = 0, y + 1
end
love.graphics.setCanvas()
sprites[current_sprite.symbol] = sprite
produce {"@"}
end)
add_rule "sprite>" (function()
table.insert(current_sprite.data[#current_sprite.data], take_next())
produce { "sprite>" }
end)
add_rule "@ draw sprite [" (function()
local symbol = take_next()
consume(2)
local x = tonumber(take_next())
consume(1)
local y = tonumber(take_next())
consume(1)
love.graphics.setCanvas(screen)
love.graphics.draw(sprites[symbol], x * 16, y * 16)
love.graphics.setCanvas()
produce {"@"}
end)
queue_up [[
@ sprite [
symbol is p
. . . . . # # # # # . . . . . . ;
. . . . . . . . . . . . . . . . ;
. . . . . # # # # # . . . . . . ;
. . # # # # # # . # # . . . . . ;
. . . . # # # # . # # # # # . . ;
. . . . . # # # # # # # # # . . ;
. . . . . . # # # # . . . . . . ;
. . . . . # # # # # # . . . . . ;
. . . . # . # # # # . # . . . . ;
. . . . # . # # # # . # . . . . ;
. . . . # . # # # # . # . . . . ;
. . . . . . # . . # . . . . . . ;
. . . . . . # . . # . . . . . . ;
. . . . . . # . . # . . . . . . ;
. . . . . . # . . # . . . . . . ;
. . . . . . # . . # . . . . . . ]
sprite [
symbol is w
. . # # # # # # # # # # # # . . ;
. # . # . # . # . # . # . # # . ;
# . # . # . # . # . # . # . # # ;
# # . # . # . # . # . # . # . # ;
# . # . # . # . # . # . # . # # ;
# # . # . # . # . # . # . # . # ;
# . # . # . # . # . # . # . # # ;
# # . # . # . # . # . # . # . # ;
# . # . # . # . # . # . # . # # ;
# # . # . # . # . # . # . # . # ;
# . # . # . # . # . # . # . # # ;
# # . # . # . # . # . # . # . # ;
# . # . # . # . # . # . # . # # ;
# # . # . # . # . # . # . # . # ;
. # # . # . # . # . # . # . # . ;
. . # # # # # # # # # # # # . . ]
draw sprite [ p at x 5 y 4 ]
draw sprite [ w at x 5 y 5 ]
draw sprite [ w at x 4 y 6 ]
draw sprite [ w at x 5 y 6 ]
draw sprite [ w at x 6 y 6 ]
draw sprite [ w at x 3 y 7 ]
draw sprite [ w at x 4 y 7 ]
draw sprite [ w at x 5 y 7 ]
draw sprite [ w at x 6 y 7 ]
draw sprite [ w at x 7 y 7 ]
draw sprite [ w at x 2 y 8 ]
draw sprite [ w at x 3 y 8 ]
draw sprite [ w at x 4 y 8 ]
draw sprite [ w at x 5 y 8 ]
draw sprite [ w at x 6 y 8 ]
draw sprite [ w at x 7 y 8 ]
draw sprite [ w at x 8 y 8 ]
draw sprite [ w at x 1 y 9 ]
draw sprite [ w at x 2 y 9 ]
draw sprite [ w at x 3 y 9 ]
draw sprite [ w at x 4 y 9 ]
draw sprite [ w at x 5 y 9 ]
draw sprite [ w at x 6 y 9 ]
draw sprite [ w at x 7 y 9 ]
draw sprite [ w at x 8 y 9 ]
draw sprite [ w at x 9 y 9 ]
draw sprite [ w at x 0 y 10 ]
draw sprite [ w at x 1 y 10 ]
draw sprite [ w at x 2 y 10 ]
draw sprite [ w at x 3 y 10 ]
draw sprite [ w at x 4 y 10 ]
draw sprite [ w at x 5 y 10 ]
draw sprite [ w at x 6 y 10 ]
draw sprite [ w at x 7 y 10 ]
draw sprite [ w at x 8 y 10 ]
draw sprite [ w at x 9 y 10 ]
draw sprite [ w at x 10 y 10 ]
]]
run()
function love.draw()
love.graphics.draw(screen, 0, 0, 0, 4, 4)
end
1 | local pprint = require "pprint" |
2 | love.graphics.setDefaultFilter("nearest", "nearest") |
3 | local read, write = 1, 1 |
4 | local active_buffer, back_buffer, rule_book = {}, {}, {} |
5 | local function parse(str) |
6 | local symbols = {} |
7 | for symbol in str:gmatch("%S+") do |
8 | table.insert(symbols, symbol) |
9 | end |
10 | return symbols |
11 | end |
12 | |
13 | local function queue_up(string) |
14 | for _, symbol in ipairs(parse(string)) do |
15 | table.insert(active_buffer, symbol) |
16 | end |
17 | end |
18 | local function add_rule(wants) |
19 | return function(gives) |
20 | table.insert(rule_book, {parse(wants), type(gives) == "string" and parse(gives) or gives}) |
21 | end |
22 | end |
23 | |
24 | local function match(wants) |
25 | for i = 1, #wants do |
26 | if wants[i] ~= active_buffer[i + read - 1] then return false end |
27 | end |
28 | return true |
29 | end |
30 | |
31 | local function consume(n) |
32 | read = read + n |
33 | end |
34 | |
35 | local function peek(n) |
36 | local symbols = {} |
37 | for i = 0, n - 1 do |
38 | table.insert(symbols, active_buffer[read + i]) |
39 | end |
40 | return symbols |
41 | end |
42 | |
43 | local function take_next(n) |
44 | n = n or 1 |
45 | local symbol = active_buffer[read] |
46 | read = read + 1 |
47 | return symbol |
48 | end |
49 | |
50 | |
51 | local function produce(gives) |
52 | for _, symbol in ipairs(gives) do |
53 | back_buffer[write] = symbol |
54 | write = write + 1 |
55 | end |
56 | end |
57 | |
58 | local function advance() |
59 | back_buffer[write], active_buffer[read] = active_buffer[read], nil |
60 | write, read = write + 1, read + 1 |
61 | end |
62 | |
63 | local function run_cycle() |
64 | local rule_matched = false |
65 | repeat |
66 | local rule_fired = false |
67 | for _, rule in ipairs(rule_book) do |
68 | local wants, gives = rule[1], rule[2] |
69 | if match(wants) then |
70 | consume(#wants) |
71 | if type(gives) == "function" then |
72 | gives(active_buffer, read) |
73 | else |
74 | produce(gives) |
75 | end |
76 | rule_fired, rule_matched = true, true |
77 | break |
78 | end |
79 | end |
80 | if not rule_fired then advance() end |
81 | until not active_buffer[read] |
82 | return rule_matched |
83 | end |
84 | |
85 | |
86 | local function exchange_buffers() |
87 | active_buffer, back_buffer = back_buffer, {} |
88 | read, write = 1, 1 |
89 | end |
90 | |
91 | local cycles, MAX_CYCLES = 0, 10000 |
92 | local function run() |
93 | while run_cycle() and cycles < MAX_CYCLES do |
94 | print(table.concat(back_buffer, " ")) |
95 | exchange_buffers() |
96 | cycles = cycles + 1 |
97 | end |
98 | end |
99 | |
100 | local current_sprite |
101 | local sprites = {} |
102 | local screen = love.graphics.newCanvas() |
103 | |
104 | add_rule "@ sprite [" (function() |
105 | current_sprite = { data = {{}} } |
106 | produce {"sprite>"} |
107 | end) |
108 | |
109 | add_rule "sprite> name is" (function() |
110 | current_sprite.name = take_next() |
111 | produce { "sprite>" } |
112 | end) |
113 | |
114 | add_rule "sprite> symbol is" (function() |
115 | current_sprite.symbol = take_next() |
116 | produce { "sprite>" } |
117 | end) |
118 | |
119 | |
120 | add_rule "sprite> ;" (function() |
121 | table.insert(current_sprite.data, {}) |
122 | produce { "sprite>" } |
123 | end) |
124 | |
125 | add_rule "sprite> ]" (function() |
126 | -- find longest row in data |
127 | local longest_row = -1 |
128 | for _, row in ipairs(current_sprite.data) do |
129 | if #row > longest_row then longest_row = #row end |
130 | end |
131 | |
132 | -- pad out other rows |
133 | for _, row in ipairs(current_sprite.data) do |
134 | while #row < longest_row do |
135 | table.insert(row, ".") |
136 | end |
137 | end |
138 | |
139 | -- construct a canvas for our sprite |
140 | print(#current_sprite.data) |
141 | local sprite = love.graphics.newCanvas(longest_row, #current_sprite.data) |
142 | love.graphics.setCanvas(sprite) |
143 | local x, y = 0, 0 |
144 | for _, row in ipairs(current_sprite.data) do |
145 | for _, data in ipairs(row) do |
146 | if data == "#" then |
147 | love.graphics.points(x + 0.5, y + 0.5) |
148 | end |
149 | x = x + 1 |
150 | end |
151 | x, y = 0, y + 1 |
152 | end |
153 | love.graphics.setCanvas() |
154 | sprites[current_sprite.symbol] = sprite |
155 | produce {"@"} |
156 | end) |
157 | |
158 | add_rule "sprite>" (function() |
159 | table.insert(current_sprite.data[#current_sprite.data], take_next()) |
160 | produce { "sprite>" } |
161 | end) |
162 | |
163 | add_rule "@ draw sprite [" (function() |
164 | local symbol = take_next() |
165 | consume(2) |
166 | local x = tonumber(take_next()) |
167 | consume(1) |
168 | local y = tonumber(take_next()) |
169 | consume(1) |
170 | love.graphics.setCanvas(screen) |
171 | love.graphics.draw(sprites[symbol], x * 16, y * 16) |
172 | love.graphics.setCanvas() |
173 | produce {"@"} |
174 | end) |
175 | |
176 | |
177 | |
178 | queue_up [[ |
179 | @ sprite [ |
180 | symbol is p |
181 | . . . . . # # # # # . . . . . . ; |
182 | . . . . . . . . . . . . . . . . ; |
183 | . . . . . # # # # # . . . . . . ; |
184 | . . # # # # # # . # # . . . . . ; |
185 | . . . . # # # # . # # # # # . . ; |
186 | . . . . . # # # # # # # # # . . ; |
187 | . . . . . . # # # # . . . . . . ; |
188 | . . . . . # # # # # # . . . . . ; |
189 | . . . . # . # # # # . # . . . . ; |
190 | . . . . # . # # # # . # . . . . ; |
191 | . . . . # . # # # # . # . . . . ; |
192 | . . . . . . # . . # . . . . . . ; |
193 | . . . . . . # . . # . . . . . . ; |
194 | . . . . . . # . . # . . . . . . ; |
195 | . . . . . . # . . # . . . . . . ; |
196 | . . . . . . # . . # . . . . . . ] |
197 | |
198 | sprite [ |
199 | symbol is w |
200 | . . # # # # # # # # # # # # . . ; |
201 | . # . # . # . # . # . # . # # . ; |
202 | # . # . # . # . # . # . # . # # ; |
203 | # # . # . # . # . # . # . # . # ; |
204 | # . # . # . # . # . # . # . # # ; |
205 | # # . # . # . # . # . # . # . # ; |
206 | # . # . # . # . # . # . # . # # ; |
207 | # # . # . # . # . # . # . # . # ; |
208 | # . # . # . # . # . # . # . # # ; |
209 | # # . # . # . # . # . # . # . # ; |
210 | # . # . # . # . # . # . # . # # ; |
211 | # # . # . # . # . # . # . # . # ; |
212 | # . # . # . # . # . # . # . # # ; |
213 | # # . # . # . # . # . # . # . # ; |
214 | . # # . # . # . # . # . # . # . ; |
215 | . . # # # # # # # # # # # # . . ] |
216 | |
217 | draw sprite [ p at x 5 y 4 ] |
218 | |
219 | draw sprite [ w at x 5 y 5 ] |
220 | |
221 | draw sprite [ w at x 4 y 6 ] |
222 | draw sprite [ w at x 5 y 6 ] |
223 | draw sprite [ w at x 6 y 6 ] |
224 | |
225 | draw sprite [ w at x 3 y 7 ] |
226 | draw sprite [ w at x 4 y 7 ] |
227 | draw sprite [ w at x 5 y 7 ] |
228 | draw sprite [ w at x 6 y 7 ] |
229 | draw sprite [ w at x 7 y 7 ] |
230 | |
231 | draw sprite [ w at x 2 y 8 ] |
232 | draw sprite [ w at x 3 y 8 ] |
233 | draw sprite [ w at x 4 y 8 ] |
234 | draw sprite [ w at x 5 y 8 ] |
235 | draw sprite [ w at x 6 y 8 ] |
236 | draw sprite [ w at x 7 y 8 ] |
237 | draw sprite [ w at x 8 y 8 ] |
238 | |
239 | draw sprite [ w at x 1 y 9 ] |
240 | draw sprite [ w at x 2 y 9 ] |
241 | draw sprite [ w at x 3 y 9 ] |
242 | draw sprite [ w at x 4 y 9 ] |
243 | draw sprite [ w at x 5 y 9 ] |
244 | draw sprite [ w at x 6 y 9 ] |
245 | draw sprite [ w at x 7 y 9 ] |
246 | draw sprite [ w at x 8 y 9 ] |
247 | draw sprite [ w at x 9 y 9 ] |
248 | |
249 | draw sprite [ w at x 0 y 10 ] |
250 | draw sprite [ w at x 1 y 10 ] |
251 | draw sprite [ w at x 2 y 10 ] |
252 | draw sprite [ w at x 3 y 10 ] |
253 | draw sprite [ w at x 4 y 10 ] |
254 | draw sprite [ w at x 5 y 10 ] |
255 | draw sprite [ w at x 6 y 10 ] |
256 | draw sprite [ w at x 7 y 10 ] |
257 | draw sprite [ w at x 8 y 10 ] |
258 | draw sprite [ w at x 9 y 10 ] |
259 | draw sprite [ w at x 10 y 10 ] |
260 | ]] |
261 | |
262 | run() |
263 | |
264 | function love.draw() |
265 | |
266 | love.graphics.draw(screen, 0, 0, 0, 4, 4) |
267 | end |
string-rewriter.lua
· 2.1 KiB · Lua
Ham
Playground
local read, write = 1, 1
local active_buffer, back_buffer, rule_book = {}, {}, {}
local function parse(str)
local symbols = {}
for symbol in str:gmatch("%S+") do
table.insert(symbols, symbol)
end
return symbols
end
local function queue_up(string)
for _, symbol in ipairs(parse(string)) do
table.insert(active_buffer, symbol)
end
end
local function add_rule(wants)
return function(gives)
table.insert(rule_book, {parse(wants), parse(gives)})
end
end
local function match(wants)
for i = 1, #wants do
if wants[i] ~= active_buffer[i + read - 1] then return false end
end
return true
end
local function consume(n)
read = read + n
end
local function produce(gives)
for _, symbol in ipairs(gives) do
back_buffer[write] = symbol
write = write + 1
end
end
local function advance()
back_buffer[write], active_buffer[read] = active_buffer[read], nil
write, read = write + 1, read + 1
end
local function run_cycle()
local rule_matched = false
repeat
local rule_fired = false
for _, rule in ipairs(rule_book) do
local wants, gives = rule[1], rule[2]
if match(wants) then
consume(#wants)
produce(gives)
rule_fired, rule_matched = true, true
break
end
end
if not rule_fired then advance() end
until not active_buffer[read]
return rule_matched
end
local function exchange_buffers()
active_buffer, back_buffer = back_buffer, {}
read, write = 1, 1
end
local cycles, MAX_CYCLES = 0, 10000
local function run()
while run_cycle() and cycles < MAX_CYCLES do
print(table.concat(back_buffer, " "))
exchange_buffers()
cycles = cycles + 1
end
end
add_rule "D D" "M"
add_rule "C C C C C" "D"
add_rule "L L" "C"
add_rule "X X X X X" "L"
add_rule "V V" "X"
add_rule "I I I I I" "V"
add_rule "I I I I" "I V"
add_rule "V I V" "I X"
add_rule "X X X X" "X L"
add_rule "L X L" "X C"
add_rule "C C C C" "C D"
add_rule "D C D" "C M"
queue_up(("I"):rep(1950, " "))
run()
1 | local read, write = 1, 1 |
2 | local active_buffer, back_buffer, rule_book = {}, {}, {} |
3 | local function parse(str) |
4 | local symbols = {} |
5 | for symbol in str:gmatch("%S+") do |
6 | table.insert(symbols, symbol) |
7 | end |
8 | return symbols |
9 | end |
10 | |
11 | local function queue_up(string) |
12 | for _, symbol in ipairs(parse(string)) do |
13 | table.insert(active_buffer, symbol) |
14 | end |
15 | end |
16 | local function add_rule(wants) |
17 | return function(gives) |
18 | table.insert(rule_book, {parse(wants), parse(gives)}) |
19 | end |
20 | end |
21 | |
22 | local function match(wants) |
23 | for i = 1, #wants do |
24 | if wants[i] ~= active_buffer[i + read - 1] then return false end |
25 | end |
26 | return true |
27 | end |
28 | |
29 | local function consume(n) |
30 | read = read + n |
31 | end |
32 | |
33 | local function produce(gives) |
34 | for _, symbol in ipairs(gives) do |
35 | back_buffer[write] = symbol |
36 | write = write + 1 |
37 | end |
38 | end |
39 | |
40 | local function advance() |
41 | back_buffer[write], active_buffer[read] = active_buffer[read], nil |
42 | write, read = write + 1, read + 1 |
43 | end |
44 | |
45 | local function run_cycle() |
46 | local rule_matched = false |
47 | repeat |
48 | local rule_fired = false |
49 | for _, rule in ipairs(rule_book) do |
50 | local wants, gives = rule[1], rule[2] |
51 | if match(wants) then |
52 | consume(#wants) |
53 | produce(gives) |
54 | rule_fired, rule_matched = true, true |
55 | break |
56 | end |
57 | end |
58 | if not rule_fired then advance() end |
59 | until not active_buffer[read] |
60 | return rule_matched |
61 | end |
62 | |
63 | |
64 | local function exchange_buffers() |
65 | active_buffer, back_buffer = back_buffer, {} |
66 | read, write = 1, 1 |
67 | end |
68 | |
69 | local cycles, MAX_CYCLES = 0, 10000 |
70 | local function run() |
71 | while run_cycle() and cycles < MAX_CYCLES do |
72 | print(table.concat(back_buffer, " ")) |
73 | exchange_buffers() |
74 | cycles = cycles + 1 |
75 | end |
76 | end |
77 | |
78 | add_rule "D D" "M" |
79 | add_rule "C C C C C" "D" |
80 | add_rule "L L" "C" |
81 | add_rule "X X X X X" "L" |
82 | add_rule "V V" "X" |
83 | add_rule "I I I I I" "V" |
84 | |
85 | add_rule "I I I I" "I V" |
86 | add_rule "V I V" "I X" |
87 | add_rule "X X X X" "X L" |
88 | add_rule "L X L" "X C" |
89 | add_rule "C C C C" "C D" |
90 | add_rule "D C D" "C M" |
91 | |
92 | queue_up(("I"):rep(1950, " ")) |
93 | |
94 | run() |