string-rewriter.lua
· 2.1 KiB · Lua
Bruto
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() |