main.lua
· 5.7 KiB · Lua
Ham
Playground
local PathBag = require "path-bag"
local the_eye = require "the-eye"
local pprint = require "pprint"
-- knowledge base
local kb = PathBag.new()
for _, pixel in ipairs(the_eye) do
kb:insert { "image", "eye", pixel[4], pixel[5], pixel[1], pixel[2], pixel[3] }
end
math.randomseed(os.time())
local function uuid()
local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
return string.gsub(template, '[xy]', function (c)
local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb)
return string.format('%x', v)
end)
end
local function io_add(kb)
local node, b = kb:get_and_bind {
"@add", "eval", "$id", "$x", "$y"
}
if not node then return false end
kb:remove_node(node)
kb:insert { "@add", "success", b.id, b.x + b.y }
return true
end
local function io_put_pixel(kb)
local node, b = kb:get_and_bind {
"@put", "pixel", "$r", "$g", "$b", "$x", "$y"
}
if not node then return false end
kb:remove_node(node)
love.graphics.setColor(b.r, b.g, b.b, 1.0)
love.graphics.points(b.x, b.y)
return true
end
local function put_pixel(kb)
local put_pixel, b1 = kb:get_and_bind {
"put", "pixel", "$r", "$g", "$b", "at", "$px_result", "$py_result"
}
if not put_pixel then return false end
local px, b2 = kb:get_and_bind {
"@add", "success", b1.px_result, "$px"
}
if not px then return false end
local py, b3 = kb:get_and_bind {
"@add", "success", b1.py_result, "$py"
}
if not py then return false end
kb:remove_node(put_pixel)
kb:remove_node(px)
kb:remove_node(py)
kb:insert { "@put", "pixel", b1.r, b1.g, b1.b, b2.px, b3.py }
return true
end
local function next_cursor_down_1(kb)
local next_cursor, b1 = kb:get_and_bind {
"next", "cursor", "down", "$down_id"
}
if not next_cursor then return false end
local add_success, b2 = kb:get_and_bind {
"@add", "success", b1.down_id, "$cy"
}
if not add_success then return false end
kb:remove_node(next_cursor)
kb:remove_node(add_success)
kb:insert { "cursor", 0, b2.cy }
return true
end
local function next_cursor_right_1(kb)
local next_cursor, b1 = kb:get_and_bind {
"next", "cursor", "right", "$right_id", "$cy"
}
if not next_cursor then return false end
local add_success, b2 = kb:get_and_bind {
"@add", "success", b1.right_id, "$cx"
}
if not add_success then return false end
kb:remove_node(next_cursor)
kb:remove_node(add_success)
kb:insert { "cursor", b2.cx, b1.cy }
return true
end
local function draw_image_1(kb)
local draw_image, b1 = kb:get_and_bind {
"draw", "image", "$image", "$x", "$y"
}
if not draw_image then return end
local cursor, b2 = kb:get_and_bind {
"cursor", "$cx", "$cy"
}
if not cursor then return end
local image, b3 = kb:get_and_bind {
"image", "$image", b2.cx, b2.cy, "$r", "$g", "$b"
}
if not image then return end
kb:remove_node(cursor)
local px_id = uuid()
local py_id = uuid()
kb:insert { "put", "pixel", b3.r, b3.g, b3.b, "at", px_id, py_id }
kb:insert { "advance", "cursor", b2.cx, b2.cy }
kb:insert { "@add", "eval", px_id, b1.x, b2.cx }
kb:insert { "@add", "eval", py_id, b1.y, b2.cy }
return true
end
local function advance_cursor_1(kb)
local node, b = kb:get_and_bind { "advance", "cursor", 249, 165 }
if not node then return false end
kb:remove_node(node)
return true
end
local function advance_cursor_2(kb)
local node, b = kb:get_and_bind { "advance", "cursor", 249, "$cy" }
if not node then return false end
kb:remove_node(node)
local down_id = uuid()
kb:insert { "next", "cursor", "down", down_id }
kb:insert { "@add", "eval", down_id, 1, b.cy }
return true
end
local function advance_cursor_3(kb)
local node, b = kb:get_and_bind { "advance", "cursor", "$cx", "$cy" }
if not node then return false end
kb:remove_node(node)
local right_id = uuid()
kb:insert { "next", "cursor", "right", right_id, b.cy }
kb:insert { "@add", "eval", right_id, 1, b.cx }
return true
end
local function draw_image_2(kb)
local node, b = kb:get_and_bind { "draw", "image", "$image", "$x", "$y" }
if not node then return false end
kb:remove_node(node)
return true
end
local function tick(kb)
local node, b = kb:get_and_bind { "tick", "$dt" }
if not node then return false end
kb:remove_node(node)
kb:insert { "draw", "image", "eye", 0, 0 }
kb:insert { "cursor", 0, 0 }
return true
end
local rules =
{ io_add
, io_put_pixel
, put_pixel
, next_cursor_down_1
, next_cursor_right_1
, draw_image_1
, advance_cursor_1, advance_cursor_2, advance_cursor_3
, draw_image_2
, tick
}
local screen = love.graphics.newCanvas()
function love.draw()
love.graphics.setColor(1, 1, 1)
love.graphics.draw(screen, 0, 0)
love.graphics.setColor(1, 0, 0)
love.graphics.print(tostring(love.timer.getFPS()) .. " fps", 0, 0)
end
function love.update(dt)
local dt_fact = tostring(dt)
local now = os.time()
love.graphics.setCanvas(screen)
love.graphics.clear(0, 0, 0, 0)
kb:insert { "tick", dt }
local rewrite = true
-- pprint("--- START ---")
-- pprint(kb)
while rewrite do
rewrite = false
for i, rule in ipairs(rules) do
if rule(kb) then
-- print("--- MATCH ---")
-- pprint(kb)
rewrite = true
break
end
end
end
love.graphics.setCanvas()
local later = os.time()
print(later - now)
end
1 | local PathBag = require "path-bag" |
2 | local the_eye = require "the-eye" |
3 | local pprint = require "pprint" |
4 | -- knowledge base |
5 | local kb = PathBag.new() |
6 | |
7 | for _, pixel in ipairs(the_eye) do |
8 | kb:insert { "image", "eye", pixel[4], pixel[5], pixel[1], pixel[2], pixel[3] } |
9 | end |
10 | |
11 | math.randomseed(os.time()) |
12 | local function uuid() |
13 | local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' |
14 | return string.gsub(template, '[xy]', function (c) |
15 | local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb) |
16 | return string.format('%x', v) |
17 | end) |
18 | end |
19 | |
20 | local function io_add(kb) |
21 | local node, b = kb:get_and_bind { |
22 | "@add", "eval", "$id", "$x", "$y" |
23 | } |
24 | if not node then return false end |
25 | |
26 | kb:remove_node(node) |
27 | kb:insert { "@add", "success", b.id, b.x + b.y } |
28 | return true |
29 | end |
30 | |
31 | local function io_put_pixel(kb) |
32 | local node, b = kb:get_and_bind { |
33 | "@put", "pixel", "$r", "$g", "$b", "$x", "$y" |
34 | } |
35 | if not node then return false end |
36 | kb:remove_node(node) |
37 | |
38 | love.graphics.setColor(b.r, b.g, b.b, 1.0) |
39 | love.graphics.points(b.x, b.y) |
40 | return true |
41 | end |
42 | |
43 | local function put_pixel(kb) |
44 | local put_pixel, b1 = kb:get_and_bind { |
45 | "put", "pixel", "$r", "$g", "$b", "at", "$px_result", "$py_result" |
46 | } |
47 | if not put_pixel then return false end |
48 | |
49 | local px, b2 = kb:get_and_bind { |
50 | "@add", "success", b1.px_result, "$px" |
51 | } |
52 | if not px then return false end |
53 | |
54 | |
55 | local py, b3 = kb:get_and_bind { |
56 | "@add", "success", b1.py_result, "$py" |
57 | } |
58 | if not py then return false end |
59 | |
60 | kb:remove_node(put_pixel) |
61 | kb:remove_node(px) |
62 | kb:remove_node(py) |
63 | |
64 | kb:insert { "@put", "pixel", b1.r, b1.g, b1.b, b2.px, b3.py } |
65 | return true |
66 | end |
67 | |
68 | local function next_cursor_down_1(kb) |
69 | local next_cursor, b1 = kb:get_and_bind { |
70 | "next", "cursor", "down", "$down_id" |
71 | } |
72 | if not next_cursor then return false end |
73 | |
74 | local add_success, b2 = kb:get_and_bind { |
75 | "@add", "success", b1.down_id, "$cy" |
76 | } |
77 | if not add_success then return false end |
78 | |
79 | kb:remove_node(next_cursor) |
80 | kb:remove_node(add_success) |
81 | |
82 | kb:insert { "cursor", 0, b2.cy } |
83 | return true |
84 | end |
85 | |
86 | local function next_cursor_right_1(kb) |
87 | local next_cursor, b1 = kb:get_and_bind { |
88 | "next", "cursor", "right", "$right_id", "$cy" |
89 | } |
90 | if not next_cursor then return false end |
91 | |
92 | local add_success, b2 = kb:get_and_bind { |
93 | "@add", "success", b1.right_id, "$cx" |
94 | } |
95 | if not add_success then return false end |
96 | |
97 | kb:remove_node(next_cursor) |
98 | kb:remove_node(add_success) |
99 | |
100 | kb:insert { "cursor", b2.cx, b1.cy } |
101 | return true |
102 | end |
103 | |
104 | local function draw_image_1(kb) |
105 | local draw_image, b1 = kb:get_and_bind { |
106 | "draw", "image", "$image", "$x", "$y" |
107 | } |
108 | if not draw_image then return end |
109 | |
110 | local cursor, b2 = kb:get_and_bind { |
111 | "cursor", "$cx", "$cy" |
112 | } |
113 | if not cursor then return end |
114 | |
115 | local image, b3 = kb:get_and_bind { |
116 | "image", "$image", b2.cx, b2.cy, "$r", "$g", "$b" |
117 | } |
118 | if not image then return end |
119 | |
120 | kb:remove_node(cursor) |
121 | |
122 | local px_id = uuid() |
123 | local py_id = uuid() |
124 | |
125 | kb:insert { "put", "pixel", b3.r, b3.g, b3.b, "at", px_id, py_id } |
126 | kb:insert { "advance", "cursor", b2.cx, b2.cy } |
127 | kb:insert { "@add", "eval", px_id, b1.x, b2.cx } |
128 | kb:insert { "@add", "eval", py_id, b1.y, b2.cy } |
129 | return true |
130 | end |
131 | |
132 | local function advance_cursor_1(kb) |
133 | local node, b = kb:get_and_bind { "advance", "cursor", 249, 165 } |
134 | if not node then return false end |
135 | |
136 | kb:remove_node(node) |
137 | return true |
138 | end |
139 | |
140 | local function advance_cursor_2(kb) |
141 | local node, b = kb:get_and_bind { "advance", "cursor", 249, "$cy" } |
142 | if not node then return false end |
143 | |
144 | kb:remove_node(node) |
145 | |
146 | local down_id = uuid() |
147 | kb:insert { "next", "cursor", "down", down_id } |
148 | kb:insert { "@add", "eval", down_id, 1, b.cy } |
149 | return true |
150 | end |
151 | |
152 | local function advance_cursor_3(kb) |
153 | local node, b = kb:get_and_bind { "advance", "cursor", "$cx", "$cy" } |
154 | if not node then return false end |
155 | |
156 | |
157 | kb:remove_node(node) |
158 | |
159 | local right_id = uuid() |
160 | kb:insert { "next", "cursor", "right", right_id, b.cy } |
161 | kb:insert { "@add", "eval", right_id, 1, b.cx } |
162 | return true |
163 | end |
164 | |
165 | local function draw_image_2(kb) |
166 | local node, b = kb:get_and_bind { "draw", "image", "$image", "$x", "$y" } |
167 | if not node then return false end |
168 | |
169 | kb:remove_node(node) |
170 | |
171 | return true |
172 | end |
173 | |
174 | local function tick(kb) |
175 | local node, b = kb:get_and_bind { "tick", "$dt" } |
176 | if not node then return false end |
177 | |
178 | kb:remove_node(node) |
179 | |
180 | kb:insert { "draw", "image", "eye", 0, 0 } |
181 | kb:insert { "cursor", 0, 0 } |
182 | return true |
183 | end |
184 | |
185 | local rules = |
186 | { io_add |
187 | , io_put_pixel |
188 | , put_pixel |
189 | , next_cursor_down_1 |
190 | , next_cursor_right_1 |
191 | , draw_image_1 |
192 | , advance_cursor_1, advance_cursor_2, advance_cursor_3 |
193 | , draw_image_2 |
194 | , tick |
195 | } |
196 | |
197 | local screen = love.graphics.newCanvas() |
198 | |
199 | |
200 | function love.draw() |
201 | love.graphics.setColor(1, 1, 1) |
202 | love.graphics.draw(screen, 0, 0) |
203 | love.graphics.setColor(1, 0, 0) |
204 | love.graphics.print(tostring(love.timer.getFPS()) .. " fps", 0, 0) |
205 | end |
206 | |
207 | function love.update(dt) |
208 | local dt_fact = tostring(dt) |
209 | local now = os.time() |
210 | love.graphics.setCanvas(screen) |
211 | love.graphics.clear(0, 0, 0, 0) |
212 | kb:insert { "tick", dt } |
213 | local rewrite = true |
214 | -- pprint("--- START ---") |
215 | -- pprint(kb) |
216 | while rewrite do |
217 | rewrite = false |
218 | for i, rule in ipairs(rules) do |
219 | if rule(kb) then |
220 | -- print("--- MATCH ---") |
221 | -- pprint(kb) |
222 | rewrite = true |
223 | break |
224 | end |
225 | end |
226 | end |
227 | love.graphics.setCanvas() |
228 | local later = os.time() |
229 | print(later - now) |
230 | end |
path-bag.lua
· 2.3 KiB · Lua
Ham
Playground
love = love or {}
local pprint = require "pprint"
--[[
If you are familiar with jargon, then a "path bag" is
a muliset that is implemented as a prefix tree.
this is a path
this is another path
this is a final path
this is a path
|
V
this <-> is <-> a <-> path {2}
| |
| + <-> final path {1}
|
+ <-> another <-> path {1}
--]]
local PathBag = {}
PathBag.__mt = {}
function PathBag.new()
local obj = { root = {children = {}, child_count = 0, count = 0} }
return setmetatable(obj, {__index = PathBag.__mt})
end
function PathBag.__mt:insert(path)
local root = self.root
for _, step in ipairs(path) do
if not root.children[step] then
root.children[step] = { value = step, children = {}, child_count = 0, count = 0, parent = root }
root.child_count = root.child_count + 1
end
root = root.children[step]
end
root.count = root.count + 1
end
function PathBag.__mt:get(path)
local root = self.root
for _, step in ipairs(path) do
if step == "*" then
_, root = next(root.children)
if not root then return end
elseif not root.children[step] then
return nil
else
root = root.children[step]
end
end
return root.count ~= 0 and root or nil
end
function PathBag.__mt:remove_node(node)
local leaf = node
while leaf.parent do
leaf.count = leaf.count - 1
if leaf.count <= 0 and leaf.child_count <= 0 then
local path = leaf.value
leaf = leaf.parent
leaf.children[path] = nil
leaf.child_count = leaf.child_count - 1
else
return
end
end
end
function PathBag.__mt:get_and_bind(path)
local bindings, root = {}, self.root
for _, step in ipairs(path) do
if type(step) == "string" and step:find("^%$") then
key, root = next(root.children)
if not root then return end
bindings[step:sub(2)] = key
elseif not root.children[step] then
return nil
else
root = root.children[step]
end
end
if root.count ~= 0 then
return root, bindings
end
end
return PathBag
1 | love = love or {} |
2 | local pprint = require "pprint" |
3 | |
4 | --[[ |
5 | If you are familiar with jargon, then a "path bag" is |
6 | a muliset that is implemented as a prefix tree. |
7 | |
8 | this is a path |
9 | this is another path |
10 | this is a final path |
11 | this is a path |
12 | | |
13 | V |
14 | this <-> is <-> a <-> path {2} |
15 | | | |
16 | | + <-> final path {1} |
17 | | |
18 | + <-> another <-> path {1} |
19 | --]] |
20 | local PathBag = {} |
21 | PathBag.__mt = {} |
22 | |
23 | function PathBag.new() |
24 | local obj = { root = {children = {}, child_count = 0, count = 0} } |
25 | return setmetatable(obj, {__index = PathBag.__mt}) |
26 | end |
27 | |
28 | function PathBag.__mt:insert(path) |
29 | local root = self.root |
30 | for _, step in ipairs(path) do |
31 | if not root.children[step] then |
32 | root.children[step] = { value = step, children = {}, child_count = 0, count = 0, parent = root } |
33 | root.child_count = root.child_count + 1 |
34 | end |
35 | root = root.children[step] |
36 | end |
37 | root.count = root.count + 1 |
38 | end |
39 | |
40 | function PathBag.__mt:get(path) |
41 | local root = self.root |
42 | for _, step in ipairs(path) do |
43 | if step == "*" then |
44 | _, root = next(root.children) |
45 | if not root then return end |
46 | elseif not root.children[step] then |
47 | return nil |
48 | else |
49 | root = root.children[step] |
50 | end |
51 | end |
52 | |
53 | return root.count ~= 0 and root or nil |
54 | end |
55 | |
56 | function PathBag.__mt:remove_node(node) |
57 | local leaf = node |
58 | while leaf.parent do |
59 | leaf.count = leaf.count - 1 |
60 | if leaf.count <= 0 and leaf.child_count <= 0 then |
61 | local path = leaf.value |
62 | leaf = leaf.parent |
63 | leaf.children[path] = nil |
64 | leaf.child_count = leaf.child_count - 1 |
65 | else |
66 | return |
67 | end |
68 | end |
69 | end |
70 | |
71 | function PathBag.__mt:get_and_bind(path) |
72 | local bindings, root = {}, self.root |
73 | for _, step in ipairs(path) do |
74 | if type(step) == "string" and step:find("^%$") then |
75 | key, root = next(root.children) |
76 | if not root then return end |
77 | bindings[step:sub(2)] = key |
78 | elseif not root.children[step] then |
79 | return nil |
80 | else |
81 | root = root.children[step] |
82 | end |
83 | end |
84 | |
85 | if root.count ~= 0 then |
86 | return root, bindings |
87 | end |
88 | end |
89 | |
90 | |
91 | |
92 | return PathBag |