main.lua
· 5.7 KiB · Lua
原始文件
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
原始文件
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 |