string-rewriter.lua
· 2.1 KiB · Lua
原始檔案
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() |