Warning: this is an htmlized version! The original is across this link, and the conversion rules are here.
-- luarects.lua: a preprocessor tho let us use literal rectangles in Lua code.
-- This file:
-- http://angg.twu.net/dednat6/luarects.lua
-- http://angg.twu.net/dednat6/luarects.lua.html
--  (find-angg        "dednat6/luarects.lua")
--
-- Example:
--
--   for x,y,str in 2/  ..      \:gen() do print(x,y,str) end
--                   |    ..    |
--                   |  ..  12  |
--                   |..  11  02|
--                   |  ..  01  |
--                   \    ..    /

-- «.AsciiRect»			(to "AsciiRect")
-- «.AsciiRect-tests»		(to "AsciiRect-tests")
-- «.LuaWithRects»		(to "LuaWithRects")
-- «.luarecteval»		(to "luarecteval")
-- «.LuaWithRects-tests»	(to "LuaWithRects-tests")
-- «.ZHAFromPoints»		(to "ZHAFromPoints")
-- «.ZHAFromPoints-tests»	(to "ZHAFromPoints-tests")

trim  = function (s) return s and (s:match"^(.-)[ \t]*$") end trim1 = function (s) s = s and trim(s); if s ~= "" then return s end end linestomatrixbody = function (lines) if type(lines) == "string" then lines = splitlines(lines) end local celltotex = function (str) if str == "." then return "" end return unabbrev((str:gsub("!", "\\"))) end local linetotex = function (i) return mapconcat(celltotex, split(lines[i]), " & ") end local tex = linetotex(1).." \\\\ \\hline\n" for i=2,#ar.lines do tex = tex..linetotex(i).." \\\\\n" end return tex end -- _ _ _ ____ _ -- / \ ___ ___(_|_) _ \ ___ ___| |_ -- / _ \ / __|/ __| | | |_) / _ \/ __| __| -- / ___ \\__ \ (__| | | _ < __/ (__| |_ -- /_/ \_\___/\___|_|_|_| \_\___|\___|\__| -- -- «AsciiRect» (to ".AsciiRect") -- Note: this class is for rectangles from which we want to READ their -- cells. Compare with rect.lua, -- (find-dn6 "rect.lua") -- which is for write-only-ish rectangles glueable in several ways, -- and with AsciiPicture: -- (find-dn6 "picture.lua" "AsciiPicture") -- -- Example of use: -- for x,y,c in AsciiRect.new(1, " a |b c | d e| f "):gen() do ... end AsciiRect = Class { type = "AsciiRect", new = function (w, lines, x0) if type(lines) == "string" then lines = splitlines((lines:gsub("|", "\n"))) end return AsciiRect {w=w, lines=lines, x0=x0 or 0} end, __tostring = function (ar) return format("w=%d x0=%d\n%s", ar.w, ar.x0, table.concat(ar.lines, "\n")) end, __index = { linetoy = function (ar, l) return #ar.lines - l end, ytoline = function (ar, y) return #ar.lines - y end, coltopos = function (ar, c) return ar.w*c + 1 end, postocol = function (ar, p) return (p - 1)/ar.w end, coltox = function (ar, c) return c - ar.x0 end, xtocol = function (ar, x) return x + ar.x0 end, -- read_linepos = function (ar, l, p) return (ar.lines[l] or ""):sub(p, p+ar.w-1) end, read_ycol = function (ar, y, c) return ar:read_linepos(ar:ytoline(y), ar:coltopos(c)) end, read_xy = function (ar, x, y) return ar:read_ycol(y, ar:xtocol(x)) end, read_linepos1 = function (ar, l, p) return trim1(ar:read_linepos(l, p)) end, read_ycol1 = function (ar, y, c) return trim1(ar:read_ycol(y, c)) end, read_xy1 = function (ar, x, y) return trim1(ar:read_xy(x, y)) end, hasxy = function (ar, x, y) return trim1(ar:read_xy(x, y)) end, -- setx0 = function (ar) local lastline = ar.lines[#ar.lines] ar.x0 = #(lastline:match"^ *") / ar.w return ar end, -- maxline = function (ar) return #ar.lines[l] end, maxcol = function (ar, l) return (#ar.lines[l] / ar.w)-1 end, minx = function (ar) return -ar.x0 end, maxx = function (ar, y) return ar:maxcol(ar:ytoline(y)) - ar.x0 end, maxy = function (ar) return #ar.lines - 1 end, -- gen = function (ar) return cow(function () for line=1,#ar.lines do for col=0,(#ar.lines[line] / ar.w)-1 do local str = ar:read_linepos(line, ar:coltopos(col)) if not str:match"^ *$" then
coy(ar:coltox(col), ar:linetoy(line), str)
end
end
end
end)
end,
--
-- Generate all points and all arrows (the black moves) of the zrect.
-- Similar to: (find-dn6 "newrect.lua" "ZHA" "points =")
--        and: (find-dn6 "newrect.lua" "ZHA" "arrows =")
points = function (ar) -- TODO
return cow(function ()
for y=ar:maxy(),0,-1 do
for x=ar:minx(y),ar:maxx(y) do
if str then coy(v(x, y), str) end
end
end
end)
end,
arrows = function (ar, usewhitemoves)
local tar = texarrow_smart(usewhitemoves)
return cow(function ()
for y=ar:maxy(),1,-1 do
for x=ar:minx(y),ar:maxx(y) do
if ar:hasxy(x, y) then
if ar:hasxy(x-1, y-1) then coy(v(x, y), -1, -1, tar.sw) end
if ar:hasxy(x,   y-1) then coy(v(x, y),  0, -1, tar.s ) end
if ar:hasxy(x+1, y-1) then coy(v(x, y),  1, -1, tar.se) end
-- coy returns: v(x,y), dx, dy, tex
end
end
end
end)
end,
--
toexpr = function (ar)
local f = function (s) return format("%q", s) end
local body = mapconcat(f, ar.lines, ", ")
return format("AsciiRect.new(%d, {%s})", ar.w, body)
end,
--
-- Uses the ZHAFromPoints class defined below
spec = function (ar)
local z = ZHAFromPoints.new()
for x,y,str in ar:gen() do z:putxy(x, y) end
return z:spec()
end,
-- See: (find-dn6 "newrect.lua" "MixedPicture-tests")
zhatomixedpicture0 = function (ar, opts)
return mpnew(opts, ar:spec())
end,
zhatomixedpicture = function (ar, opts)
local mp = mpnew(opts, ar:spec())
for x,y,str in ar:setx0():gen() do mp:put(v(x, y), str) end
return mp
end,
tomixedpicture = function (ar, opts)
return MixedPicture.new(opts, nil, nil, ar)
end,
--
tomp  = function (ar, opts)
return MixedPicture.new(opts, nil,       nil, ar)
end,
tozmp = function (ar, opts)
-- return MixedPicture.new(opts, ar:spec(), nil, ar)
return MixedPicture.new(opts, ZHA.fromspec(ar:spec()), nil, ar:setx0())
end,
--
tomatrix = function (ar, def)
local tex = linestomatrixbody(ar.lines)
tex = "\\begin{matrix}\n"..tex.."\\end{matrix}"
tex = "\\def\\"..def.."{\n"..tex.."}"
output(tex)
end,
},
}

-- «AsciiRect-tests» (to ".AsciiRect-tests")
--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "luarects.lua"
ar = AsciiRect.new(1, " a  |b c | d e|  f ")
= ar
for x,y,str in ar:gen() do printf("(%d,%d):%s\n", x, y, str) end
= ar:setx0()
for x,y,str in ar:gen() do printf("(%d,%d):%s\n", x, y, str) end
PPV(ar)

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "luarects.lua"
dofile "picture.lua"
ar = AsciiRect.new(1, " a  |b c | d e|  f ")
for v,str in ar:points() do printf("%s:%s\n", v:xy(), str) end
for v,dx,dy,tex in ar:arrows() do printf("%s,%d,%d,%s\n", v:xy(), dx, dy, tex) end
= ar:setx0()
for x,y,str in ar:gen() do printf("(%d,%d):%s\n", x, y, str) end
PPV(ar)

* (ex "asciirect")

--]]

--  _              __        ___ _   _     ____           _
-- | |   _   _  __ \ \      / (_) |_| |__ |  _ \ ___  ___| |_ ___
-- | |  | | | |/ _ \ \ /\ / /| | __| '_ \| |_) / _ \/ __| __/ __|
-- | |__| |_| | (_| |\ V  V / | | |_| | | |  _ <  __/ (__| |_\__ \
-- |_____\__,_|\__,_| \_/\_/  |_|\__|_| |_|_| \_\___|\___|\__|___/
--
-- «LuaWithRects» (to ".LuaWithRects")

LuaWithRects = Class {
type = "LuaWithRects",
new  = function (lines)
if type(lines) == "string" then lines = splitlines(lines) end
return LuaWithRects {lines=lines, defs="", ars={}}
end,
__tostring = function (lwr) return lwr:tostring() end,
__index = {
body = function (lwr) return table.concat(lwr.lines, "\n") end,
tostring = function (lwr) return lwr.defs..lwr:body() end,
--
read = function (lwr, nline, pos1, pos2)
return lwr.lines[nline]:sub(pos1, pos2-1)
end,
readasciirect = function (lwr, w, nline1, nline2, pos1, pos2)
local ar = AsciiRect.new(w, {})
for y=nline1,nline2 do table.insert(ar.lines, lwr:read(y, pos1, pos2)) end
return ar
end,
--
replace = function (lwr, nline, pos1, pos2, newstr, spc)
local line = lwr.lines[nline]
local a, b, c = line:sub(1, pos1-1), line:sub(pos1, pos2-1), line:sub(pos2)
newstr = newstr .. (spc or " "):rep(pos2-pos1)
newstr = newstr:sub(1, (pos2-pos1))
lwr.lines[nline] = a..newstr..c
return lwr
end,
replacerect = function (lwr, nline1, nline2, pos1, pos2, newstr, spc)
lwr:replace(nline1, pos1, pos2, newstr, spc)
for y=nline1+1,nline2 do lwr:replace(y, pos1, pos2, "", spc) end
return lwr
end,
--
matchasciirect = function (lwr, nline1)
local pos1, w, pos2 = lwr.lines[nline1]:match "()(%d)/[^\\]+\\()"
if pos1 then
local yc = function (y) return lwr.lines[y]:sub(pos1+1, pos1+1) end
local nline2 = nline1 + 1
while yc(nline2) == "|" do nline2 = nline2 + 1 end
if yc(nline2) == "\\" then
return w+0, nline1, nline2, pos1, pos2
else
error("Rectangle starting at line "..nline1..", "..
"column "..pos1.." does not close")
end
end
end,
extractasciirect = function (lwr, w, nline1, nline2, pos1, pos2, newstr)
local ar = lwr:readasciirect(w, nline1, nline2, pos1+2, pos2-1)
lwr:replacerect(nline1, nline2, pos1, pos2, newstr)
return ar
end,
ntoname = function (lwr, n) return "aR"..n end,
extractasciirects = function (lwr)
for nline = 1,#lwr.lines do
while true do
local w, y1, y2, pos1, pos2 = lwr:matchasciirect(nline)
if not w then break end
local name = lwr:ntoname(#lwr.ars)
local ar = lwr:readasciirect(w, y1, y2, pos1+2, pos2-1)
lwr:extractasciirect(w, y1, y2, pos1, pos2, name)
table.insert(lwr.ars, {name, ar})
lwr.defs = lwr.defs .. format("local %s = %s\n", name, ar:toexpr())
end
end
return lwr
end,
},
}

-- «luarecteval» (to ".luarecteval")
luarectexpand = function (bigstr)
return LuaWithRects.new(bigstr):extractasciirects():tostring()
end
luarecteval = function (bigstr, verbose)
local code = luarectexpand(bigstr)
if verbose then print(code) end
return eval(code)
end
luarectexpr = function (bigstr) return luarecteval("return\n"..bigstr) end

-- «LuaWithRects-tests» (to ".LuaWithRects-tests")
--[==[
-- High-level tests:
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "luarects.lua"
bigstr = [[
A = 1/ a \;  B = 2/abcd\;
|b c|        \efgh/   C = 1/o o \
| d |                      | o o|
\  e/                      \o o /
]]
lwr = LuaWithRects.new(bigstr)
= lwr
= lwr:extractasciirects()
= lwr:body()
= lwr.defs
= mytabletostring(lwr.ars)
= lwr.ars[1][2]

* (ex "luawithrects-1")

* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "luarects.lua"
bigstr = [[
for x,y,str in 2/  ..      \:setx0():gen() do print(x,y,str) end
|    ..    |
|  ..  12  |
|..  11  02|
|  ..  01  |
\    ..    /
]]
luarecteval(bigstr)

=    LuaWithRects.new(bigstr)
=    LuaWithRects.new(bigstr):extractasciirects()
=    LuaWithRects.new(bigstr):extractasciirects():tostring()
eval(LuaWithRects.new(bigstr):extractasciirects():tostring())
luarecteval(bigstr)

* (ex "luawithrects-2")

-- Low-level tests:
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "luarects.lua"
bigstr = [[
1/ a \
|b c|
| d |
\  e/
]]
lwr = LuaWithRects.new(bigstr)
= lwr
= lwr:readasciirect(9, 2, 4, 3, 6)
= lwr:readasciirect(9, 1, 4, 3, 6)
= lwr:replace         (2,    3, 6, "!", ".")
= lwr:replacerect     (1, 4, 3, 6, "!", ".")

lwr = LuaWithRects.new(bigstr)
= lwr:matchasciirect(1)
= lwr:readasciirect(9, 1, 4, 3, 6)
w, y1, y2, pos1, pos2 = lwr:matchasciirect(1)
ar = lwr:extractasciirect(w, y1, y2, pos1, pos2, "foo")
= ar
= lwr

* (ex "luawithrects-3")

--]==]

--  ______   _    _    _____                    ____       _       _
-- |__  / | | |  / \  |  ___| __ ___  _ __ ___ |  _ \ ___ (_)_ __ | |_ ___
--   / /| |_| | / _ \ | |_ | '__/ _ \| '_  _ \| |_) / _ \| | '_ \| __/ __|
--  / /_|  _  |/ ___ \|  _|| | | (_) | | | | | |  __/ (_) | | | | | |_\__ \
-- /____|_| |_/_/   \_\_|  |_|  \___/|_| |_| |_|_|   \___/|_|_| |_|\__|___/
--
-- «ZHAFromPoints» (to ".ZHAFromPoints")
-- The core was copied to: (find-dn6 "zhas.lua" "spec-tools")
-- To be moved to: (find-dn6 "zhaspecs.lua" "spec-tools")

ZHAFromPoints = Class {
type = "ZHAFromPoints",
new  = function () return ZHAFromPoints {L={}, R={}, W={}} end,
__index = {
putxy = function (zfp, x, y)
zfp.L[y], zfp.R[y] = minmax(zfp.L[y], x, zfp.R[y])
return zfp
end,
spec = function (zfp)
local s = "1"
local L, R, W = zfp.L, zfp.R, {}
for y=0,#L do W[y] = (R[y] - L[y])/2 + 1 end
for y=1,#L do
if W[y] == W[y-1]
then s = s..((L[y]<L[y-1]) and "L" or "R")
else s = s..W[y]
end
end
return s
end,
},
}

-- «ZHAFromPoints-tests» (to ".ZHAFromPoints-tests")
--[==[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "luarects.lua"

luarecteval [[
r = 2/  32      \
|    22    |
|  21  12  |
|20  11  02|
|  10  01  |
\    00    /
]]
= r
= r:spec()    --> 12321L

luarecteval [[
ra, rb, rc =
2/                48        \, 2/            48        \, 2/            48    \
|              47  38      |   |          47  38      |   |          47  38  |
|            46  37  28    |   |        46  37  28    |   |        46  37    |
|          45  36  27  18  |   |      45  36  27  18  |   |          36      |
|        44  35  26  17  08|   |    44  35  26  17  08|   |        35  26    |
|      43  34  25  16  07  |   |  43  34  25  16  07  |   |      34  25  16  |
|    42  33  24  15  06    |   |    33  24  15  06    |   |    33  24  15  06|
|  41  32  23  14  05      |   |      23  14  05      |   |      23  14  05  |
|40  31  22  13  04        |   |    22  13  04        |   |    22  13  04    |
|  30  21  12  03          |   |  21  12  03          |   |  21  12  03      |
|    20  11  02            |   |20  11  02            |   |20  11  02        |
|      10  01              |   |  10  01              |   |  10  01          |
\        00                /   \    00                /   \    00            /
print(ra:spec(), rb:spec(), rc:spec())
--> 12345RRRR4321	123RRR45R4321	123RRR43212R1
]]

* (ex "zhafrompoints")

--]==]

--[[
* (eepitch-lua51)
* (eepitch-kill)
* (eepitch-lua51)
dofile "luarects.lua"

--]]

-- Local Variables:
-- coding: raw-text-unix
-- End: