snapshot: migrate all sample apps to new format

This commit is contained in:
Kartik K. Agaram 2021-12-11 10:18:41 -08:00
parent d5038fe514
commit c0c9d31688
8 changed files with 1027 additions and 1215 deletions

View File

@ -1,253 +1,200 @@
teliva_program = { # .tlv file generated by https://github.com/akkartik/teliva
{ # You may edit it if you are careful; however, you may see cryptic errors if you
__teliva_timestamp = [==[ # violate Teliva's assumptions.
original]==], #
norm = [==[ # .tlv files are representations of Teliva programs. Teliva programs consist of
function norm() # sequences of definitions. Each definition is a table of key/value pairs. Keys
window:attrset(curses.A_NORMAL) # and values are both strings.
end]==], #
}, # Lines in .tlv files always follow exactly one of the following forms:
{ # - comment lines at the top of the file starting with '#' at column 0
__teliva_timestamp = [==[ # - beginnings of definitions starting with '- ' at column 0, followed by a
original]==], # key/value pair
bold = [==[ # - key/value pairs consisting of ' ' at column 0, containing either a
function bold() # spaceless value on the same line, or a multi-line value
window:attron(curses.A_BOLD) # - multiline values indented by more than 2 spaces, starting with a '>'
end]==], #
}, # If these constraints are violated, Teliva may unceremoniously crash. Please
{ # report bugs at http://akkartik.name/contact
__teliva_timestamp = [==[ - __teliva_timestamp: original
original]==], norm:
rv = [==[ >function norm()
function rv() > window:attrset(curses.A_NORMAL)
window:attron(curses.A_REVERSE) >end
end]==], - __teliva_timestamp: original
}, bold:
{ >function bold()
__teliva_timestamp = [==[ > window:attron(curses.A_BOLD)
original]==], >end
color = [==[ - __teliva_timestamp: original
function color(i) rv:
window:attron(curses.color_pair(i)) >function rv()
end]==], > window:attron(curses.A_REVERSE)
}, >end
{ - __teliva_timestamp: original
__teliva_timestamp = [==[ color:
original]==], >function color(i)
abbreviations = [==[ > window:attron(curses.color_pair(i))
clear = curses.clear >end
refresh = curses.refresh - __teliva_timestamp: original
getch = curses.getch abbreviations:
addch = curses.addch >clear = curses.clear
mvaddch = curses.mvaddch >refresh = curses.refresh
pr = curses.addstr >getch = curses.getch
mpr = curses.mvaddstr >addch = curses.addch
str = tostring >mvaddch = curses.mvaddch
num = tonumber >pr = curses.addstr
]==], >mpr = curses.mvaddstr
}, >str = tostring
{ >num = tonumber
__teliva_timestamp = [==[ - __teliva_timestamp: original
original]==], str_helpers:
str_helpers = [==[ >-- some string helpers from http://lua-users.org/wiki/StringIndexing
-- some string helpers from http://lua-users.org/wiki/StringIndexing >
>-- index characters using []
-- index characters using [] >getmetatable('').__index = function(str,i)
getmetatable('').__index = function(str,i) > if type(i) == 'number' then
if type(i) == 'number' then > return string.sub(str,i,i)
return string.sub(str,i,i) > else
else > return string[i]
return string[i] > end
end >end
end >
>-- ranges using (), selected bytes using {}
-- ranges using (), selected bytes using {} >getmetatable('').__call = function(str,i,j)
getmetatable('').__call = function(str,i,j) > if type(i)~='table' then
if type(i)~='table' then > return string.sub(str,i,j)
return string.sub(str,i,j) > else
else > local t={}
local t={} > for k,v in ipairs(i) do
for k,v in ipairs(i) do > t[k]=string.sub(str,v,v)
t[k]=string.sub(str,v,v) > end
end > return table.concat(t)
return table.concat(t) > end
end >end
end >
>-- iterate over an ordered sequence
-- iterate over an ordered sequence >function q(x)
function q(x) > if type(x) == 'string' then
if type(x) == 'string' then > return x:gmatch('.')
return x:gmatch('.') > else
else > return ipairs(x)
return ipairs(x) > end
end >end
end >
>-- TODO: backport utf-8 support from Lua 5.3
-- TODO: backport utf-8 support from Lua 5.3 - __teliva_timestamp: original
]==], prn:
}, >-- functional form of 'print'
{ >-- use this in map/reduce/filter
__teliva_timestamp = [==[ >function prn(...)
original]==], > print(unpack(arg))
prn = [==[ > return arg[1]
-- functional form of 'print' >end
-- use this in map/reduce/filter - __teliva_timestamp: original
function prn(...) add:
print(unpack(arg)) >add = table.insert
return arg[1] - __teliva_timestamp: original
end]==], map:
}, >-- only for arrays
{ >function map(l, f)
__teliva_timestamp = [==[ > result = {}
original]==], > for _, x in q(l) do
add = [==[ > add(result, f(x))
add = table.insert]==], > end
}, > return result
{ >end
__teliva_timestamp = [==[ - __teliva_timestamp: original
original]==], reduce:
map = [==[ >-- only for arrays
-- only for arrays >function reduce(l, f, init)
function map(l, f) > result = init
result = {} > for _, x in q(l) do
for _, x in q(l) do > result = f(result, x)
add(result, f(x)) > end
end > return result
return result >end
end - __teliva_timestamp: original
]==], filter:
}, >-- only for arrays
{ >function filter(l, f)
__teliva_timestamp = [==[ > result = {}
original]==], > for _, x in q(l) do
reduce = [==[ > if f(x) then
-- only for arrays > add(result, x)
function reduce(l, f, init) > end
result = init > end
for _, x in q(l) do > return result
result = f(result, x) >end
end - __teliva_timestamp: original
return result find_index:
end >function find_index(arr, x)
]==], > for n, y in q(arr) do
}, > if x == y then
{ > return n
__teliva_timestamp = [==[ > end
original]==], > end
filter = [==[ >end
-- only for arrays - __teliva_timestamp: original
function filter(l, f) trim:
result = {} >function trim(s)
for _, x in q(l) do > return s:gsub('^%s*', ''):gsub('%s*$', '')
if f(x) then >end
add(result, x) - __teliva_timestamp: original
end split:
end >function split(s, d)
return result > result = {}
end > for match in (s..d):gmatch("(.-)"..d) do
]==], > add(result, match);
}, > end
{ > return result
__teliva_timestamp = [==[ >end
original]==], - __teliva_timestamp: original
find_index = [==[ window:
function find_index(arr, x) >window = curses.stdscr()
for n, y in q(arr) do - __teliva_timestamp: original
if x == y then render:
return n >function render(window)
end > clear()
end > -- draw stuff to screen here
end > for line in io.lines("input") do
]==], > pr(line)
}, > pr("\n")
{ > end
__teliva_timestamp = [==[ > refresh()
original]==], >end
trim = [==[ - __teliva_timestamp: original
function trim(s) menu:
return s:gsub('^%s*', ''):gsub('%s*$', '') >menu = {}
end - __teliva_timestamp: original
]==], update:
}, >function update(window)
{ > local key = curses.getch()
__teliva_timestamp = [==[ > -- process key here
original]==], >end
split = [==[ - __teliva_timestamp: original
function split(s, d) init_colors:
result = {} >function init_colors()
for match in (s..d):gmatch("(.-)"..d) do > for i=0,7 do
add(result, match); > curses.init_pair(i, i, -1)
end > end
return result > curses.init_pair(8, 7, 0)
end > curses.init_pair(9, 7, 1)
]==], > curses.init_pair(10, 7, 2)
}, > curses.init_pair(11, 7, 3)
{ > curses.init_pair(12, 7, 4)
__teliva_timestamp = [==[ > curses.init_pair(13, 7, 5)
original]==], > curses.init_pair(14, 7, 6)
window = [==[ > curses.init_pair(15, -1, 15)
window = curses.stdscr()]==], > curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
}, >end
{ - main:
__teliva_timestamp = [==[ >function main()
original]==], > init_colors()
render = [==[ >
function render(window) > while true do
clear() > render(window)
-- draw stuff to screen here > update(window)
for line in io.lines("input") do > end
pr(line) >end
pr("\n") __teliva_timestamp: original
end
refresh()
end]==],
},
{
__teliva_timestamp = [==[
original]==],
menu = [==[
menu = {}]==],
},
{
__teliva_timestamp = [==[
original]==],
update = [==[
function update(window)
local key = curses.getch()
-- process key here
end]==],
},
{
__teliva_timestamp = [==[
original]==],
init_colors = [==[
function init_colors()
for i=0,7 do
curses.init_pair(i, i, -1)
end
curses.init_pair(8, 7, 0)
curses.init_pair(9, 7, 1)
curses.init_pair(10, 7, 2)
curses.init_pair(11, 7, 3)
curses.init_pair(12, 7, 4)
curses.init_pair(13, 7, 5)
curses.init_pair(14, 7, 6)
curses.init_pair(15, -1, 15)
curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
end]==],
},
{
main = [==[
function main()
init_colors()
while true do
render(window)
update(window)
end
end
]==],
__teliva_timestamp = [==[
original]==],
},
}

View File

@ -1,298 +1,263 @@
teliva_program = { # .tlv file generated by https://github.com/akkartik/teliva
{ # You may edit it if you are careful; however, you may see cryptic errors if you
__teliva_timestamp = [==[ # violate Teliva's assumptions.
original]==], #
window = [==[ # .tlv files are representations of Teliva programs. Teliva programs consist of
window = curses.stdscr() # sequences of definitions. Each definition is a table of key/value pairs. Keys
-- animation-based app # and values are both strings.
window:nodelay(true) #
lines, cols = window:getmaxyx()]==], # Lines in .tlv files always follow exactly one of the following forms:
}, # - comment lines at the top of the file starting with '#' at column 0
{ # - beginnings of definitions starting with '- ' at column 0, followed by a
__teliva_timestamp = [==[ # key/value pair
original]==], # - key/value pairs consisting of ' ' at column 0, containing either a
current_game = [==[ # spaceless value on the same line, or a multi-line value
current_game = {}]==], # - multiline values indented by more than 2 spaces, starting with a '>'
}, #
{ # If these constraints are violated, Teliva may unceremoniously crash. Please
__teliva_timestamp = [==[ # report bugs at http://akkartik.name/contact
original]==], - __teliva_timestamp: original
piece_glyph = [==[ window:
piece_glyph = { >window = curses.stdscr()
-- for legibility, white pieces also use unicode glyphs for black pieces >-- animation-based app
-- we rely on colors to distinguish them >window:nodelay(true)
K = 0x265a, >lines, cols = window:getmaxyx()
Q = 0x265b, - __teliva_timestamp: original
R = 0x265c, current_game:
B = 0x265d, >current_game = {}
N = 0x265e, - __teliva_timestamp: original
P = 0x265f, piece_glyph:
k = 0x265a, >piece_glyph = {
q = 0x265b, > -- for legibility, white pieces also use unicode glyphs for black pieces
r = 0x265c, > -- we rely on colors to distinguish them
b = 0x265d, > K = 0x265a,
n = 0x265e, > Q = 0x265b,
p = 0x265f, > R = 0x265c,
}]==], > B = 0x265d,
}, > N = 0x265e,
{ > P = 0x265f,
__teliva_timestamp = [==[ > k = 0x265a,
original]==], > q = 0x265b,
top_player = [==[ > r = 0x265c,
function top_player(current_game) > b = 0x265d,
if current_game.players[1].color == "black" then > n = 0x265e,
return current_game.players[1] > p = 0x265f,
end >}
return current_game.players[2] - __teliva_timestamp: original
end]==], top_player:
}, >function top_player(current_game)
{ > if current_game.players[1].color == "black" then
__teliva_timestamp = [==[ > return current_game.players[1]
original]==], > end
bottom_player = [==[ > return current_game.players[2]
function bottom_player(current_game) >end
if current_game.players[1].color == "white" then - __teliva_timestamp: original
return current_game.players[1] bottom_player:
end >function bottom_player(current_game)
return current_game.players[2] > if current_game.players[1].color == "white" then
end]==], > return current_game.players[1]
}, > end
{ > return current_game.players[2]
__teliva_timestamp = [==[ >end
original]==], - __teliva_timestamp: original
render_player = [==[ render_player:
function render_player(y, x, player) >function render_player(y, x, player)
curses.mvaddstr(y, x, player.user.name) > curses.mvaddstr(y, x, player.user.name)
curses.addstr(" · ") > curses.addstr(" · ")
curses.addstr(tostring(player.rating)) > curses.addstr(tostring(player.rating))
end]==], >end
}, - __teliva_timestamp: original
{ render_square:
__teliva_timestamp = [==[ >function render_square(current_game, rank, file, highlighted_squares)
original]==], > -- decide whether to highlight
render_square = [==[ > local hl = 0
function render_square(current_game, rank, file, highlighted_squares) > if (rank == highlighted_squares.from.rank and file == highlighted_squares.from.file)
-- decide whether to highlight > or (rank == highlighted_squares.to.rank and file == highlighted_squares.to.file) then
local hl = 0 > hl = 4
if (rank == highlighted_squares.from.rank and file == highlighted_squares.from.file) > end
or (rank == highlighted_squares.to.rank and file == highlighted_squares.to.file) then > if (rank+file)%2 == 1 then
hl = 4 > -- light square
end > curses.attrset(curses.color_pair(1+hl))
if (rank+file)%2 == 1 then > else
-- light square > -- dark square
curses.attrset(curses.color_pair(1+hl)) > curses.attrset(curses.color_pair(3+hl))
else > end
-- dark square > curses.mvaddstr((8 - rank + 1)*3, file*5, " ")
curses.attrset(curses.color_pair(3+hl)) > curses.mvaddstr((8 - rank + 1)*3+1, file*5, " ")
end > curses.mvaddstr((8 - rank + 1)*3+2, file*5, " ")
curses.mvaddstr((8 - rank + 1)*3, file*5, " ") > curses.attrset(curses.A_NORMAL)
curses.mvaddstr((8 - rank + 1)*3+1, file*5, " ") >end
curses.mvaddstr((8 - rank + 1)*3+2, file*5, " ") - __teliva_timestamp: original
curses.attrset(curses.A_NORMAL) render_fen_rank:
end]==], >function render_fen_rank(rank, fen_rank, highlighted_squares)
}, > local file = 1
{ > for x in fen_rank:gmatch(".") do
__teliva_timestamp = [==[ > if x:match("%d") then
original]==], > file = file + tonumber(x)
render_fen_rank = [==[ > else
function render_fen_rank(rank, fen_rank, highlighted_squares) > -- decide whether to highlight
local file = 1 > local hl = 0
for x in fen_rank:gmatch(".") do > if (rank == highlighted_squares.from.rank and file == highlighted_squares.from.file)
if x:match("%d") then > or (rank == highlighted_squares.to.rank and file == highlighted_squares.to.file) then
file = file + tonumber(x) > hl = 4
else > end
-- decide whether to highlight > if (rank+file)%2 == 1 then
local hl = 0 > if x < 'Z' then
if (rank == highlighted_squares.from.rank and file == highlighted_squares.from.file) > -- white piece on light square
or (rank == highlighted_squares.to.rank and file == highlighted_squares.to.file) then > curses.attrset(curses.color_pair(1+hl))
hl = 4 > else
end > -- black piece on light square
if (rank+file)%2 == 1 then > curses.attrset(curses.color_pair(2+hl))
if x < 'Z' then > end
-- white piece on light square > else
curses.attrset(curses.color_pair(1+hl)) > if x < 'Z' then
else > -- white piece on dark square
-- black piece on light square > curses.attrset(curses.color_pair(3+hl))
curses.attrset(curses.color_pair(2+hl)) > else
end > -- black piece on dark square
else > curses.attrset(curses.color_pair(4+hl))
if x < 'Z' then > end
-- white piece on dark square > end
curses.attrset(curses.color_pair(3+hl)) > curses.mvaddstr((8 - rank + 1)*3+1, file*5+2, utf8(piece_glyph[x]))
else > curses.attrset(curses.A_NORMAL)
-- black piece on dark square > file = file + 1
curses.attrset(curses.color_pair(4+hl)) > end
end > end
end >end
curses.mvaddstr((8 - rank + 1)*3+1, file*5+2, utf8(piece_glyph[x])) - __teliva_timestamp: original
curses.attrset(curses.A_NORMAL) render_time:
file = file + 1 >function render_time(y, x, seconds)
end > if seconds == nil then return end
end > curses.mvaddstr(y, x, tostring(math.floor(seconds/60)))
end]==], > curses.addstr(string.format(":%02d", seconds%60))
}, >end
{ - __teliva_timestamp: original
__teliva_timestamp = [==[ render_board:
original]==], >function render_board(current_game)
render_time = [==[ >--? curses.mvaddstr(1, 50, dump(current_game.fen))
function render_time(y, x, seconds) >--? curses.mvaddstr(6, 50, dump(current_game.previously_moved_squares))
if seconds == nil then return end > render_player(2, 5, top_player(current_game))
curses.mvaddstr(y, x, tostring(math.floor(seconds/60))) > render_time(2, 35, current_game.bc)
curses.addstr(string.format(":%02d", seconds%60)) > for rank=8,1,-1 do
end]==], > for file=1,8 do
}, > render_square(current_game, rank, file, current_game.previously_moved_squares)
{ > end
__teliva_timestamp = [==[ > render_fen_rank(rank, current_game.fen_rank[8-rank+1], current_game.previously_moved_squares)
original]==], > end
render_board = [==[ > render_player(27, 5, bottom_player(current_game))
function render_board(current_game) > render_time(27, 35, current_game.wc)
--? curses.mvaddstr(1, 50, dump(current_game.fen)) >end
--? curses.mvaddstr(6, 50, dump(current_game.previously_moved_squares)) - __teliva_timestamp: original
render_player(2, 5, top_player(current_game)) parse_lm:
render_time(2, 35, current_game.bc) >function parse_lm(move)
for rank=8,1,-1 do >--? curses.mvaddstr(4, 50, move)
for file=1,8 do > local file1 = string.byte(move:sub(1, 1)) - 96 -- 'a'-1
render_square(current_game, rank, file, current_game.previously_moved_squares) > local rank1 = string.byte(move:sub(2, 2)) - 48 -- '0'
end > local file2 = string.byte(move:sub(3, 3)) - 96 -- 'a'-1
render_fen_rank(rank, current_game.fen_rank[8-rank+1], current_game.previously_moved_squares) > local rank2 = string.byte(move:sub(4, 4)) - 48 -- '0'
end >--? curses.mvaddstr(5, 50, dump({{rank1, file1}, {rank2, file2}}))
render_player(27, 5, bottom_player(current_game)) > return {from={rank=rank1, file=file1}, to={rank=rank2, file=file2}}
render_time(27, 35, current_game.wc) >end
end]==], - __teliva_timestamp: original
}, render:
{ >function render(chunk)
__teliva_timestamp = [==[ > local o = json.decode(chunk)
original]==], > if o.t == "featured" then
parse_lm = [==[ > current_game = o.d
function parse_lm(move) >--? current_game.lm = "__"
--? curses.mvaddstr(4, 50, move) > current_game.previously_moved_squares = {from={rank=0, file=0}, to={rank=0, file=0}} -- no highlight
local file1 = string.byte(move:sub(1, 1)) - 96 -- 'a'-1 > else
local rank1 = string.byte(move:sub(2, 2)) - 48 -- '0' > current_game.fen = o.d.fen
local file2 = string.byte(move:sub(3, 3)) - 96 -- 'a'-1 > current_game.wc = o.d.wc
local rank2 = string.byte(move:sub(4, 4)) - 48 -- '0' > current_game.bc = o.d.bc
--? curses.mvaddstr(5, 50, dump({{rank1, file1}, {rank2, file2}})) >--? current_game.lm = o.d.lm
return {from={rank=rank1, file=file1}, to={rank=rank2, file=file2}} > current_game.previously_moved_squares = parse_lm(o.d.lm)
end]==], >--? window:nodelay(false)
}, >--? curses.mvaddstr(3, 50, "paused")
{ > end
__teliva_timestamp = [==[ > current_game.fen_rank = split(current_game.fen, "%w+")
original]==], > render_board(current_game)
render = [==[ > curses.refresh()
function render(chunk) >end
local o = json.decode(chunk) - __teliva_timestamp: original
if o.t == "featured" then init_colors:
current_game = o.d >function init_colors()
--? current_game.lm = "__" > -- colors
current_game.previously_moved_squares = {from={rank=0, file=0}, to={rank=0, file=0}} -- no highlight > local light_piece = 1
else > local dark_piece = 0
current_game.fen = o.d.fen > local light_square = 252
current_game.wc = o.d.wc > local dark_square = 242
current_game.bc = o.d.bc > local light_last_moved_square = 229
--? current_game.lm = o.d.lm > local dark_last_moved_square = 226
current_game.previously_moved_squares = parse_lm(o.d.lm) > -- initialize colors
--? window:nodelay(false) > curses.init_pair(1, light_piece, light_square)
--? curses.mvaddstr(3, 50, "paused") > curses.init_pair(2, dark_piece, light_square)
end > curses.init_pair(3, light_piece, dark_square)
current_game.fen_rank = split(current_game.fen, "%w+") > curses.init_pair(4, dark_piece, dark_square)
render_board(current_game) > curses.init_pair(5, light_piece, light_last_moved_square)
curses.refresh() > curses.init_pair(6, dark_piece, light_last_moved_square)
end]==], > curses.init_pair(7, light_piece, dark_last_moved_square)
}, > curses.init_pair(8, dark_piece, dark_last_moved_square)
{ > curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
__teliva_timestamp = [==[ >end
original]==], - __teliva_timestamp: original
init_colors = [==[ main:
function init_colors() >function main()
-- colors > init_colors()
local light_piece = 1 > local request = {
local dark_piece = 0 > url = "https://lichess.org/api/tv/feed",
local light_square = 252 > sink = function(chunk, err)
local dark_square = 242 > if chunk then
local light_last_moved_square = 229 > curses.clear()
local dark_last_moved_square = 226 > render(chunk)
-- initialize colors > curses.getch()
curses.init_pair(1, light_piece, light_square) > end
curses.init_pair(2, dark_piece, light_square) > return 1
curses.init_pair(3, light_piece, dark_square) > end,
curses.init_pair(4, dark_piece, dark_square) > }
curses.init_pair(5, light_piece, light_last_moved_square) > http.request(request)
curses.init_pair(6, dark_piece, light_last_moved_square) >end
curses.init_pair(7, light_piece, dark_last_moved_square) - __teliva_timestamp: original
curses.init_pair(8, dark_piece, dark_last_moved_square) utf8:
curses.init_pair(255, 15, 1) -- reserved for Teliva error messages >-- https://stackoverflow.com/questions/7983574/how-to-write-a-unicode-symbol-in-lua
end]==], >function utf8(decimal)
}, > local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} }
{ > if decimal<128 then return string.char(decimal) end
__teliva_timestamp = [==[ > local charbytes = {}
original]==], > for bytes,vals in ipairs(bytemarkers) do
main = [==[ > if decimal<=vals[1] then
function main() > for b=bytes+1,2,-1 do
init_colors() > local mod = decimal%64
local request = { > decimal = (decimal-mod)/64
url = "https://lichess.org/api/tv/feed", > charbytes[b] = string.char(128+mod)
sink = function(chunk, err) > end
if chunk then > charbytes[1] = string.char(vals[2]+decimal)
curses.clear() > break
render(chunk) > end
curses.getch() > end
end > return table.concat(charbytes)
return 1 >end
end, - __teliva_timestamp: original
} split:
http.request(request) >function split(s, pat)
end]==], > result = {}
}, > for x in s:gmatch(pat) do
{ > table.insert(result, x)
__teliva_timestamp = [==[ > end
original]==], > return result
utf8 = [==[ >end
-- https://stackoverflow.com/questions/7983574/how-to-write-a-unicode-symbol-in-lua - __teliva_timestamp: original
function utf8(decimal) dump:
local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} } >-- https://stackoverflow.com/questions/9168058/how-to-dump-a-table-to-console
if decimal<128 then return string.char(decimal) end >function dump(o)
local charbytes = {} > if type(o) == 'table' then
for bytes,vals in ipairs(bytemarkers) do > local s = '{ '
if decimal<=vals[1] then > for k,v in pairs(o) do
for b=bytes+1,2,-1 do > if type(k) ~= 'number' then k = '"'..k..'"' end
local mod = decimal%64 > s = s .. '['..k..'] = ' .. dump(v) .. ','
decimal = (decimal-mod)/64 > end
charbytes[b] = string.char(128+mod) > return s .. '} '
end > else
charbytes[1] = string.char(vals[2]+decimal) > return tostring(o)
break > end
end >end
end
return table.concat(charbytes)
end]==],
},
{
__teliva_timestamp = [==[
original]==],
split = [==[
function split(s, pat)
result = {}
for x in s:gmatch(pat) do
table.insert(result, x)
end
return result
end]==],
},
{
__teliva_timestamp = [==[
original]==],
dump = [==[
-- https://stackoverflow.com/questions/9168058/how-to-dump-a-table-to-console
function dump(o)
if type(o) == 'table' then
local s = '{ '
for k,v in pairs(o) do
if type(k) ~= 'number' then k = '"'..k..'"' end
s = s .. '['..k..'] = ' .. dump(v) .. ','
end
return s .. '} '
else
return tostring(o)
end
end]==],
},
}

View File

@ -1,62 +1,61 @@
teliva_program = { # .tlv file generated by https://github.com/akkartik/teliva
{ # You may edit it if you are careful; however, you may see cryptic errors if you
__teliva_timestamp = [==[ # violate Teliva's assumptions.
original]==], #
window = [==[ # .tlv files are representations of Teliva programs. Teliva programs consist of
window = curses.stdscr()]==], # sequences of definitions. Each definition is a table of key/value pairs. Keys
}, # and values are both strings.
{ #
__teliva_timestamp = [==[ # Lines in .tlv files always follow exactly one of the following forms:
original]==], # - comment lines at the top of the file starting with '#' at column 0
n = [==[ # - beginnings of definitions starting with '- ' at column 0, followed by a
n = 0]==], # key/value pair
}, # - key/value pairs consisting of ' ' at column 0, containing either a
{ # spaceless value on the same line, or a multi-line value
__teliva_timestamp = [==[ # - multiline values indented by more than 2 spaces, starting with a '>'
original]==], #
render = [==[ # If these constraints are violated, Teliva may unceremoniously crash. Please
function render(window) # report bugs at http://akkartik.name/contact
window:clear() - __teliva_timestamp: original
window:attron(curses.A_BOLD) window:
window:attron(curses.color_pair(6)) >window = curses.stdscr()
window:mvaddstr(10, 10, " ") - __teliva_timestamp: original
window:mvaddstr(10, 11, n) n:
window:attroff(curses.color_pair(6)) >n = 0
window:attroff(curses.A_BOLD) - __teliva_timestamp: original
curses.refresh() render:
end]==], >function render(window)
}, > window:clear()
{ > window:attron(curses.A_BOLD)
__teliva_timestamp = [==[ > window:attron(curses.color_pair(6))
original]==], > window:mvaddstr(10, 10, " ")
menu = [==[ > window:mvaddstr(10, 11, n)
menu = {Enter="increment"}]==], > window:attroff(curses.color_pair(6))
}, > window:attroff(curses.A_BOLD)
{ > curses.refresh()
__teliva_timestamp = [==[ >end
original]==], __teliva_note: foo
update = [==[ - __teliva_timestamp: original
function update(window) menu:
local key = curses.getch() >menu = {Enter="increment"}
if key == 10 then - __teliva_timestamp: original
n = n+1 update:
end >function update(window)
end]==], > local key = curses.getch()
}, > if key == 10 then
{ > n = n+1
__teliva_timestamp = [==[ > end
original]==], >end
main = [==[ - __teliva_timestamp: original
function main() main:
for i=1,7 do >function main()
curses.init_pair(i, 0, i) > for i=1,7 do
end > curses.init_pair(i, 0, i)
curses.init_pair(255, 15, 1) -- reserved for Teliva error messages > end
> curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
while true do >
render(window) > while true do
update(window) > render(window)
end > update(window)
end]==], > end
}, >end
}

267
hanoi.tlv
View File

@ -1,144 +1,123 @@
teliva_program = { # .tlv file generated by https://github.com/akkartik/teliva
{ # You may edit it if you are careful; however, you may see cryptic errors if you
__teliva_timestamp = [==[ # violate Teliva's assumptions.
original]==], #
render = [==[ # .tlv files are representations of Teliva programs. Teliva programs consist of
function render(window) # sequences of definitions. Each definition is a table of key/value pairs. Keys
window:clear() # and values are both strings.
local lines, cols = window:getmaxyx() #
local line = math.floor(lines/2) # Lines in .tlv files always follow exactly one of the following forms:
local col = math.floor(cols/4) # - comment lines at the top of the file starting with '#' at column 0
for i,t in ipairs(tower) do # - beginnings of definitions starting with '- ' at column 0, followed by a
render_tower(window, line, i*col, i, t) # key/value pair
end # - key/value pairs consisting of ' ' at column 0, containing either a
curses.refresh() # spaceless value on the same line, or a multi-line value
end]==], # - multiline values indented by more than 2 spaces, starting with a '>'
}, #
{ # If these constraints are violated, Teliva may unceremoniously crash. Please
__teliva_timestamp = [==[ # report bugs at http://akkartik.name/contact
original]==], - __teliva_timestamp: original
lines = [==[ render:
function lines(window) >function render(window)
local lines, cols = window:getmaxyx() > window:clear()
return lines > local lines, cols = window:getmaxyx()
end]==], > local line = math.floor(lines/2)
}, > local col = math.floor(cols/4)
{ > for i,t in ipairs(tower) do
__teliva_timestamp = [==[ > render_tower(window, line, i*col, i, t)
original]==], > end
pop = [==[ > curses.refresh()
function pop(array) >end
return table.remove(array) - __teliva_timestamp: original
end]==], lines:
}, >function lines(window)
{ > local lines, cols = window:getmaxyx()
__teliva_timestamp = [==[ > return lines
original]==], >end
window = [==[ - __teliva_timestamp: original
window = curses.stdscr()]==], pop:
}, >function pop(array)
{ > return table.remove(array)
__teliva_timestamp = [==[ >end
original]==], - __teliva_timestamp: original
render_tower = [==[ window:
function render_tower(window, line, col, tower_index, tower) >window = curses.stdscr()
window:attron(curses.A_BOLD) - __teliva_timestamp: original
window:mvaddch(line+2, col, string.char(96+tower_index)) render_tower:
window:attroff(curses.A_BOLD) >function render_tower(window, line, col, tower_index, tower)
window:attron(curses.color_pair(15)) > window:attron(curses.A_BOLD)
window:mvaddstr(line+1, col-6, " ") > window:mvaddch(line+2, col, string.char(96+tower_index))
window:attroff(curses.color_pair(15)) > window:attroff(curses.A_BOLD)
for i, n in ipairs(tower) do > window:attron(curses.color_pair(15))
render_disk(window, line, col, n) > window:mvaddstr(line+1, col-6, " ")
line = line - 1 > window:attroff(curses.color_pair(15))
end > for i, n in ipairs(tower) do
for i=1,5-len(tower)+1 do > render_disk(window, line, col, n)
window:attron(curses.color_pair(15)) > line = line - 1
window:mvaddstr(line, col, " ") > end
window:attroff(curses.color_pair(15)) > for i=1,5-len(tower)+1 do
line = line - 1 > window:attron(curses.color_pair(15))
end > window:mvaddstr(line, col, " ")
end]==], > window:attroff(curses.color_pair(15))
}, > line = line - 1
{ > end
__teliva_timestamp = [==[ >end
original]==], - __teliva_timestamp: original
tower = [==[ tower:
tower = {{6, 5, 4, 3, 2}, {}, {}}]==], >tower = {{6, 5, 4, 3, 2}, {}, {}}
}, - __teliva_timestamp: original
{ render_disk:
__teliva_timestamp = [==[ >function render_disk(window, line, col, size)
original]==], > col = col-size+1
render_disk = [==[ > for i=1,size do
function render_disk(window, line, col, size) > window:attron(curses.color_pair(size))
col = col-size+1 > window:mvaddstr(line, col, " ")
for i=1,size do > window:attroff(curses.color_pair(size))
window:attron(curses.color_pair(size)) > col = col+2
window:mvaddstr(line, col, " ") > end
window:attroff(curses.color_pair(size)) >end
col = col+2 - __teliva_timestamp: original
end main:
end]==], >function main()
}, > curses.assume_default_colors(250, 139)
{ > for i=1,7 do
__teliva_timestamp = [==[ > curses.init_pair(i, 0, i)
original]==], > end
main = [==[ > curses.init_pair(15, 0, 250) -- tower frames
function main() > curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
curses.assume_default_colors(250, 139) >
for i=1,7 do > while true do
curses.init_pair(i, 0, i) > render(window)
end > update(window)
curses.init_pair(15, 0, 250) -- tower frames > end
curses.init_pair(255, 15, 1) -- reserved for Teliva error messages >end
- __teliva_timestamp: original
while true do len:
render(window) >function len(array)
update(window) > local result = 0
end > for k in pairs(array) do
end > result = result+1
]==], > end
}, > return result
{ >end
__teliva_timestamp = [==[ - __teliva_timestamp: original
original]==], update:
len = [==[ >function update(window)
function len(array) > window:mvaddstr(lines(window)-2, 5, "tower to remove top disk from? ")
local result = 0 > local from = curses.getch() - 96
for k in pairs(array) do > window:mvaddstr(lines(window)-1, 5, "tower to stack it on? ")
result = result+1 > local to = curses.getch() - 96
end > make_move(from, to)
return result >end
end]==], - __teliva_timestamp: original
}, make_move:
{ >function make_move(from, to)
__teliva_timestamp = [==[ > local disk = pop(tower[from])
original]==], > table.insert(tower[to], disk)
update = [==[ >end
function update(window) - __teliva_timestamp: original
window:mvaddstr(lines(window)-2, 5, "tower to remove top disk from? ") cols:
local from = curses.getch() - 96 >function cols(window)
window:mvaddstr(lines(window)-1, 5, "tower to stack it on? ") > local lines, cols = window:getmaxyx()
local to = curses.getch() - 96 > return cols
make_move(from, to) >end
end]==],
},
{
__teliva_timestamp = [==[
original]==],
make_move = [==[
function make_move(from, to)
local disk = pop(tower[from])
table.insert(tower[to], disk)
end]==],
},
{
__teliva_timestamp = [==[
original]==],
cols = [==[
function cols(window)
local lines, cols = window:getmaxyx()
return cols
end]==],
},
}

650
life.tlv
View File

@ -1,342 +1,308 @@
teliva_program = { # .tlv file generated by https://github.com/akkartik/teliva
{ # You may edit it if you are careful; however, you may see cryptic errors if you
__teliva_timestamp = [==[ # violate Teliva's assumptions.
original]==], #
grid = [==[ # .tlv files are representations of Teliva programs. Teliva programs consist of
-- main data structure # sequences of definitions. Each definition is a table of key/value pairs. Keys
grid = {} # and values are both strings.
for i=1,lines*4 do #
grid[i] = {} # Lines in .tlv files always follow exactly one of the following forms:
for j=1,cols*2 do # - comment lines at the top of the file starting with '#' at column 0
grid[i][j] = 0 # - beginnings of definitions starting with '- ' at column 0, followed by a
end # key/value pair
end # - key/value pairs consisting of ' ' at column 0, containing either a
]==], # spaceless value on the same line, or a multi-line value
}, # - multiline values indented by more than 2 spaces, starting with a '>'
{ #
__teliva_timestamp = [==[ # If these constraints are violated, Teliva may unceremoniously crash. Please
original]==], # report bugs at http://akkartik.name/contact
window = [==[ - __teliva_timestamp: original
window = curses.stdscr() grid:
-- animation-based app >-- main data structure
window:nodelay(true) >grid = {}
lines, cols = window:getmaxyx()]==], >for i=1,lines*4 do
}, > grid[i] = {}
{ > for j=1,cols*2 do
__teliva_timestamp = [==[ > grid[i][j] = 0
original]==], > end
grid_char = [==[ >end
-- grab a 4x2 chunk of grid - __teliva_timestamp: original
function grid_char(line, col) window:
result = {} >window = curses.stdscr()
for l, row in ipairs({unpack(grid, (line-1)*4+1, line*4)}) do >-- animation-based app
result[l] = {unpack(row, (col-1)*2+1, col*2)} >window:nodelay(true)
end >lines, cols = window:getmaxyx()
return result - __teliva_timestamp: original
end]==], grid_char:
}, >-- grab a 4x2 chunk of grid
{ >function grid_char(line, col)
__teliva_timestamp = [==[ > result = {}
original]==], > for l, row in ipairs({unpack(grid, (line-1)*4+1, line*4)}) do
print_grid_char = [==[ > result[l] = {unpack(row, (col-1)*2+1, col*2)}
function print_grid_char(window, x) > end
result = {} > return result
for l, row in ipairs(x) do >end
for c, val in ipairs(row) do - __teliva_timestamp: original
window:mvaddstr(l, c, val) print_grid_char:
end >function print_grid_char(window, x)
end > result = {}
return result > for l, row in ipairs(x) do
end]==], > for c, val in ipairs(row) do
}, > window:mvaddstr(l, c, val)
{ > end
__teliva_timestamp = [==[ > end
original]==], > return result
glyph = [==[ >end
-- look up the braille pattern corresponding to a 4x2 chunk of grid - __teliva_timestamp: original
-- https://en.wikipedia.org/wiki/Braille_Patterns glyph:
-- not obviously programmatic because Unicode added 4x2 after 3x2 >-- look up the braille pattern corresponding to a 4x2 chunk of grid
glyph = { >-- https://en.wikipedia.org/wiki/Braille_Patterns
0x2800, 0x2801, 0x2802, 0x2803, 0x2804, 0x2805, 0x2806, 0x2807, 0x2840, 0x2841, 0x2842, 0x2843, 0x2844, 0x2845, 0x2846, 0x2847, >-- not obviously programmatic because Unicode added 4x2 after 3x2
0x2808, 0x2809, 0x280a, 0x280b, 0x280c, 0x280d, 0x280e, 0x280f, 0x2848, 0x2849, 0x284a, 0x284b, 0x284c, 0x284d, 0x284e, 0x284f, >glyph = {
0x2810, 0x2811, 0x2812, 0x2813, 0x2814, 0x2815, 0x2816, 0x2817, 0x2850, 0x2851, 0x2852, 0x2853, 0x2854, 0x2855, 0x2856, 0x2857, > 0x2800, 0x2801, 0x2802, 0x2803, 0x2804, 0x2805, 0x2806, 0x2807, 0x2840, 0x2841, 0x2842, 0x2843, 0x2844, 0x2845, 0x2846, 0x2847,
0x2818, 0x2819, 0x281a, 0x281b, 0x281c, 0x281d, 0x281e, 0x281f, 0x2858, 0x2859, 0x285a, 0x285b, 0x285c, 0x285d, 0x285e, 0x285f, > 0x2808, 0x2809, 0x280a, 0x280b, 0x280c, 0x280d, 0x280e, 0x280f, 0x2848, 0x2849, 0x284a, 0x284b, 0x284c, 0x284d, 0x284e, 0x284f,
0x2820, 0x2821, 0x2822, 0x2823, 0x2824, 0x2825, 0x2826, 0x2827, 0x2860, 0x2861, 0x2862, 0x2863, 0x2864, 0x2865, 0x2866, 0x2867, > 0x2810, 0x2811, 0x2812, 0x2813, 0x2814, 0x2815, 0x2816, 0x2817, 0x2850, 0x2851, 0x2852, 0x2853, 0x2854, 0x2855, 0x2856, 0x2857,
0x2828, 0x2829, 0x282a, 0x282b, 0x282c, 0x282d, 0x282e, 0x282f, 0x2868, 0x2869, 0x286a, 0x286b, 0x286c, 0x286d, 0x286e, 0x286f, > 0x2818, 0x2819, 0x281a, 0x281b, 0x281c, 0x281d, 0x281e, 0x281f, 0x2858, 0x2859, 0x285a, 0x285b, 0x285c, 0x285d, 0x285e, 0x285f,
0x2830, 0x2831, 0x2832, 0x2833, 0x2834, 0x2835, 0x2836, 0x2837, 0x2870, 0x2871, 0x2872, 0x2873, 0x2874, 0x2875, 0x2876, 0x2877, > 0x2820, 0x2821, 0x2822, 0x2823, 0x2824, 0x2825, 0x2826, 0x2827, 0x2860, 0x2861, 0x2862, 0x2863, 0x2864, 0x2865, 0x2866, 0x2867,
0x2838, 0x2839, 0x283a, 0x283b, 0x283c, 0x283d, 0x283e, 0x283f, 0x2878, 0x2879, 0x287a, 0x287b, 0x287c, 0x287d, 0x287e, 0x287f, > 0x2828, 0x2829, 0x282a, 0x282b, 0x282c, 0x282d, 0x282e, 0x282f, 0x2868, 0x2869, 0x286a, 0x286b, 0x286c, 0x286d, 0x286e, 0x286f,
> 0x2830, 0x2831, 0x2832, 0x2833, 0x2834, 0x2835, 0x2836, 0x2837, 0x2870, 0x2871, 0x2872, 0x2873, 0x2874, 0x2875, 0x2876, 0x2877,
0x2880, 0x2881, 0x2882, 0x2883, 0x2884, 0x2885, 0x2886, 0x2887, 0x28c0, 0x28c1, 0x28c2, 0x28c3, 0x28c4, 0x28c5, 0x28c6, 0x28c7, > 0x2838, 0x2839, 0x283a, 0x283b, 0x283c, 0x283d, 0x283e, 0x283f, 0x2878, 0x2879, 0x287a, 0x287b, 0x287c, 0x287d, 0x287e, 0x287f,
0x2888, 0x2889, 0x288a, 0x288b, 0x288c, 0x288d, 0x288e, 0x288f, 0x28c8, 0x28c9, 0x28ca, 0x28cb, 0x28cc, 0x28cd, 0x28ce, 0x28cf, >
0x2890, 0x2891, 0x2892, 0x2893, 0x2894, 0x2895, 0x2896, 0x2897, 0x28d0, 0x28d1, 0x28d2, 0x28d3, 0x28d4, 0x28d5, 0x28d6, 0x28d7, > 0x2880, 0x2881, 0x2882, 0x2883, 0x2884, 0x2885, 0x2886, 0x2887, 0x28c0, 0x28c1, 0x28c2, 0x28c3, 0x28c4, 0x28c5, 0x28c6, 0x28c7,
0x2898, 0x2899, 0x289a, 0x289b, 0x289c, 0x289d, 0x289e, 0x289f, 0x28d8, 0x28d9, 0x28da, 0x28db, 0x28dc, 0x28dd, 0x28de, 0x28df, > 0x2888, 0x2889, 0x288a, 0x288b, 0x288c, 0x288d, 0x288e, 0x288f, 0x28c8, 0x28c9, 0x28ca, 0x28cb, 0x28cc, 0x28cd, 0x28ce, 0x28cf,
0x28a0, 0x28a1, 0x28a2, 0x28a3, 0x28a4, 0x28a5, 0x28a6, 0x28a7, 0x28e0, 0x28e1, 0x28e2, 0x28e3, 0x28e4, 0x28e5, 0x28e6, 0x28e7, > 0x2890, 0x2891, 0x2892, 0x2893, 0x2894, 0x2895, 0x2896, 0x2897, 0x28d0, 0x28d1, 0x28d2, 0x28d3, 0x28d4, 0x28d5, 0x28d6, 0x28d7,
0x28a8, 0x28a9, 0x28aa, 0x28ab, 0x28ac, 0x28ad, 0x28ae, 0x28af, 0x28e8, 0x28e9, 0x28ea, 0x28eb, 0x28ec, 0x28ed, 0x28ee, 0x28ef, > 0x2898, 0x2899, 0x289a, 0x289b, 0x289c, 0x289d, 0x289e, 0x289f, 0x28d8, 0x28d9, 0x28da, 0x28db, 0x28dc, 0x28dd, 0x28de, 0x28df,
0x28b0, 0x28b1, 0x28b2, 0x28b3, 0x28b4, 0x28b5, 0x28b6, 0x28b7, 0x28f0, 0x28f1, 0x28f2, 0x28f3, 0x28f4, 0x28f5, 0x28f6, 0x28f7, > 0x28a0, 0x28a1, 0x28a2, 0x28a3, 0x28a4, 0x28a5, 0x28a6, 0x28a7, 0x28e0, 0x28e1, 0x28e2, 0x28e3, 0x28e4, 0x28e5, 0x28e6, 0x28e7,
0x28b8, 0x28b9, 0x28ba, 0x28bb, 0x28bc, 0x28bd, 0x28be, 0x28bf, 0x28f8, 0x28f9, 0x28fa, 0x28fb, 0x28fc, 0x28fd, 0x28fe, 0x28ff, > 0x28a8, 0x28a9, 0x28aa, 0x28ab, 0x28ac, 0x28ad, 0x28ae, 0x28af, 0x28e8, 0x28e9, 0x28ea, 0x28eb, 0x28ec, 0x28ed, 0x28ee, 0x28ef,
}]==], > 0x28b0, 0x28b1, 0x28b2, 0x28b3, 0x28b4, 0x28b5, 0x28b6, 0x28b7, 0x28f0, 0x28f1, 0x28f2, 0x28f3, 0x28f4, 0x28f5, 0x28f6, 0x28f7,
}, > 0x28b8, 0x28b9, 0x28ba, 0x28bb, 0x28bc, 0x28bd, 0x28be, 0x28bf, 0x28f8, 0x28f9, 0x28fa, 0x28fb, 0x28fc, 0x28fd, 0x28fe, 0x28ff,
{ >}
__teliva_timestamp = [==[ - __teliva_timestamp: original
original]==], utf8:
utf8 = [==[ >-- https://stackoverflow.com/questions/7983574/how-to-write-a-unicode-symbol-in-lua
-- https://stackoverflow.com/questions/7983574/how-to-write-a-unicode-symbol-in-lua >function utf8(decimal)
function utf8(decimal) > local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} }
local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} } > if decimal<128 then return string.char(decimal) end
if decimal<128 then return string.char(decimal) end > local charbytes = {}
local charbytes = {} > for bytes,vals in ipairs(bytemarkers) do
for bytes,vals in ipairs(bytemarkers) do > if decimal<=vals[1] then
if decimal<=vals[1] then > for b=bytes+1,2,-1 do
for b=bytes+1,2,-1 do > local mod = decimal%64
local mod = decimal%64 > decimal = (decimal-mod)/64
decimal = (decimal-mod)/64 > charbytes[b] = string.char(128+mod)
charbytes[b] = string.char(128+mod) > end
end > charbytes[1] = string.char(vals[2]+decimal)
charbytes[1] = string.char(vals[2]+decimal) > break
break > end
end > end
end > return table.concat(charbytes)
return table.concat(charbytes) >end
end]==], - __teliva_timestamp: original
}, grid_char_to_glyph_index:
{ >-- convert a chunk of grid into a number
__teliva_timestamp = [==[ >function grid_char_to_glyph_index(g)
original]==], > return g[1][1] + g[2][1]*2 + g[3][1]*4 + g[4][1]*8 +
grid_char_to_glyph_index = [==[ > g[1][2]*16 + g[2][2]*32 + g[3][2]*64 + g[4][2]*128 +
-- convert a chunk of grid into a number > 1 -- 1-indexing
function grid_char_to_glyph_index(g) >end
return g[1][1] + g[2][1]*2 + g[3][1]*4 + g[4][1]*8 + - __teliva_timestamp: original
g[1][2]*16 + g[2][2]*32 + g[3][2]*64 + g[4][2]*128 + render:
1 -- 1-indexing >function render(window)
end]==], > window:clear()
}, > curses.attron(curses.color_pair(1))
{ > for line=1,lines do
__teliva_timestamp = [==[ > for col=1,cols do
original]==], > window:addstr(utf8(glyph[grid_char_to_glyph_index(grid_char(line, col))]))
render = [==[ > end
function render(window) > end
window:clear() > curses.attroff(curses.color_pair(1))
curses.attron(curses.color_pair(1)) > curses.refresh()
for line=1,lines do >end
for col=1,cols do - __teliva_timestamp: original
window:addstr(utf8(glyph[grid_char_to_glyph_index(grid_char(line, col))])) state:
end >function state(line, col)
end > if line < 1 or line > table.getn(grid) or col < 1 or col > table.getn(grid[1]) then
curses.attroff(curses.color_pair(1)) > return 0
curses.refresh() > end
end > return grid[line][col]
]==], >end
}, - __teliva_timestamp: original
{ num_live_neighbors:
__teliva_timestamp = [==[ >function num_live_neighbors(line, col)
original]==], > return state(line-1, col-1) + state(line-1, col) + state(line-1, col+1) +
state = [==[ > state(line, col-1) + state(line, col+1) +
function state(line, col) > state(line+1, col-1) + state(line+1, col) + state(line+1, col+1)
if line < 1 or line > table.getn(grid) or col < 1 or col > table.getn(grid[1]) then >end
return 0 - __teliva_timestamp: original
end step:
return grid[line][col] >function step()
end]==], > local new_grid = {}
}, > for line=1,table.getn(grid) do
{ > new_grid[line] = {}
__teliva_timestamp = [==[ > for col=1,table.getn(grid[1]) do
original]==], > local n = num_live_neighbors(line, col)
num_live_neighbors = [==[ > if n == 3 then
function num_live_neighbors(line, col) > new_grid[line][col] = 1
return state(line-1, col-1) + state(line-1, col) + state(line-1, col+1) + > elseif n == 2 then
state(line, col-1) + state(line, col+1) + > new_grid[line][col] = grid[line][col]
state(line+1, col-1) + state(line+1, col) + state(line+1, col+1) > else
end]==], > new_grid[line][col] = 0
}, > end
{ > end
__teliva_timestamp = [==[ > end
original]==], > grid = new_grid
step = [==[ >end
function step() - __teliva_timestamp: original
local new_grid = {} sleep:
for line=1,table.getn(grid) do >function sleep(a)
new_grid[line] = {} > local sec = tonumber(os.clock() + a);
for col=1,table.getn(grid[1]) do > while (os.clock() < sec) do
local n = num_live_neighbors(line, col) > end
if n == 3 then >end
new_grid[line][col] = 1 - __teliva_timestamp: original
elseif n == 2 then file_exists:
new_grid[line][col] = grid[line][col] >function file_exists(filename)
else > local f = io.open(filename, "r")
new_grid[line][col] = 0 > if f ~= nil then
end > io.close(f)
end > return true
end > else
grid = new_grid > return false
end]==], > end
}, >end
{ - __teliva_timestamp: original
__teliva_timestamp = [==[ load_file:
original]==], >function load_file(window, filename)
sleep = [==[ > io.input(filename)
function sleep(a) > local line_index = lines
local sec = tonumber(os.clock() + a); > for line in io.lines() do
while (os.clock() < sec) do > if line:sub(1,1) ~= '!' then -- comment; plaintext files can't have whitespace before comments
end > local col_index = cols
end]==], > for c in line:gmatch(".") do
}, > if c == '\r' then break end -- DOS line ending
{ > if c == '.' then
__teliva_timestamp = [==[ > grid[line_index][col_index] = 0
original]==], > else
file_exists = [==[ > grid[line_index][col_index] = 1
function file_exists(filename) > end
local f = io.open(filename, "r") > col_index = col_index+1
if f ~= nil then > end
io.close(f) > line_index = line_index+1
return true > end
else > end
return false >end
end - __teliva_timestamp: original
end]==], update:
}, >menu = {arrow="pan"}
{ >
__teliva_timestamp = [==[ >function update(window, c)
original]==], > if c == curses.KEY_LEFT then
load_file = [==[ > for i=1,lines*4 do
function load_file(window, filename) > for j=2,cols*2 do
io.input(filename) > grid[i][j-1] = grid[i][j]
local line_index = lines > end
for line in io.lines() do > grid[i][cols*2] = 0
if line:sub(1,1) ~= '!' then -- comment; plaintext files can't have whitespace before comments > end
local col_index = cols > elseif c == curses.KEY_DOWN then
for c in line:gmatch(".") do > for i=lines*4-1,1,-1 do
if c == '\r' then break end -- DOS line ending > for j=1,cols*2 do
if c == '.' then > grid[i+1][j] = grid[i][j]
grid[line_index][col_index] = 0 > end
else > end
grid[line_index][col_index] = 1 > for j=1,cols*2 do
end > grid[1][j] = 0
col_index = col_index+1 > end
end > elseif c == curses.KEY_UP then
line_index = line_index+1 > for i=2,lines*4 do
end > for j=1,cols*2 do
end > grid[i-1][j] = grid[i][j]
end]==], > end
}, > end
{ > for j=1,cols*2 do
__teliva_timestamp = [==[ > grid[lines*4][j] = 0
original]==], > end
update = [==[ > elseif c == curses.KEY_RIGHT then
menu = {arrow="pan"} > for i=1,lines*4 do
> for j=cols*2-1,1,-1 do
function update(window, c) > grid[i][j+1] = grid[i][j]
if c == curses.KEY_LEFT then > end
for i=1,lines*4 do > grid[i][1] = 0
for j=2,cols*2 do > end
grid[i][j-1] = grid[i][j] > end
end >end
grid[i][cols*2] = 0 - __teliva_timestamp: original
end main:
elseif c == curses.KEY_DOWN then >function main()
for i=lines*4-1,1,-1 do > curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
for j=1,cols*2 do > curses.init_pair(1, 22, 189)
grid[i+1][j] = grid[i][j] >
end > -- initialize grid based on commandline args
end > if (#arg == 0) then
for j=1,cols*2 do > -- by default, start from a deterministically random state
grid[1][j] = 0 > for i=1,lines*4 do
end > for j=1,cols*2 do
elseif c == curses.KEY_UP then > grid[i][j] = math.random(0, 1)
for i=2,lines*4 do > end
for j=1,cols*2 do > end
grid[i-1][j] = grid[i][j] > elseif arg[1] == "random" then
end > -- start from a non-deterministically random start state
end > math.randomseed(os.time())
for j=1,cols*2 do > for i=1,lines*4 do
grid[lines*4][j] = 0 > for j=1,cols*2 do
end > grid[i][j] = math.random(0, 1)
elseif c == curses.KEY_RIGHT then > end
for i=1,lines*4 do > end
for j=cols*2-1,1,-1 do > -- shortcuts for some common patterns
grid[i][j+1] = grid[i][j] > elseif arg[1] == "pentomino" then
end > -- https://www.conwaylife.com/wiki/Pentomino
grid[i][1] = 0 > grid[83][172] = 1
end > grid[83][173] = 1
end > grid[84][173] = 1
end]==], > grid[84][174] = 1
}, > grid[85][173] = 1
{ > elseif arg[1] == "glider" then
__teliva_timestamp = [==[ > -- https://www.conwaylife.com/wiki/Glider
original]==], > grid[5][4] = 1
main = [==[ > grid[6][5] = 1
function main() > grid[7][3] = 1
curses.init_pair(255, 15, 1) -- reserved for Teliva error messages > grid[7][4] = 1
curses.init_pair(1, 22, 189) > grid[7][5] = 1
> elseif arg[1] == "blinker" then
-- initialize grid based on commandline args > -- https://www.conwaylife.com/wiki/Blinker
if (#arg == 0) then > grid[7][3] = 1
-- by default, start from a deterministically random state > grid[7][4] = 1
for i=1,lines*4 do > grid[7][5] = 1
for j=1,cols*2 do > elseif arg[1] == "block" then
grid[i][j] = math.random(0, 1) > -- https://www.conwaylife.com/wiki/Block
end > grid[5][4] = 1
end > grid[5][5] = 1
elseif arg[1] == "random" then > grid[6][4] = 1
-- start from a non-deterministically random start state > grid[6][5] = 1
math.randomseed(os.time()) > elseif arg[1] == "loaf" then
for i=1,lines*4 do > -- https://www.conwaylife.com/wiki/Loaf
for j=1,cols*2 do > grid[5][4] = 1
grid[i][j] = math.random(0, 1) > grid[5][5] = 1
end > grid[6][6] = 1
end > grid[7][6] = 1
-- shortcuts for some common patterns > grid[8][5] = 1
elseif arg[1] == "pentomino" then > grid[7][4] = 1
-- https://www.conwaylife.com/wiki/Pentomino > grid[6][3] = 1
grid[83][172] = 1 > elseif file_exists(arg[1]) then
grid[83][173] = 1 > -- Load a file in the standard "plaintext" format: https://www.conwaylife.com/wiki/Plaintext
grid[84][173] = 1 > --
grid[84][174] = 1 > -- Each pattern page at https://www.conwaylife.com/wiki provides its
grid[85][173] = 1 > -- plaintext representation in a block called "Pattern Files" on the right.
elseif arg[1] == "glider" then > --
-- https://www.conwaylife.com/wiki/Glider > -- For example, check out the list of Important Patterns at
grid[5][4] = 1 > -- https://www.conwaylife.com/wiki/Category:Patterns_with_Catagolue_frequency_class_0
grid[6][5] = 1 > load_file(window, arg[1])
grid[7][3] = 1 > end
grid[7][4] = 1 >
grid[7][5] = 1 > -- main loop
elseif arg[1] == "blinker" then > while true do
-- https://www.conwaylife.com/wiki/Blinker > render(window)
grid[7][3] = 1 > c = curses.getch()
grid[7][4] = 1 > update(window, c)
grid[7][5] = 1 > step()
elseif arg[1] == "block" then > end
-- https://www.conwaylife.com/wiki/Block >end
grid[5][4] = 1
grid[5][5] = 1
grid[6][4] = 1
grid[6][5] = 1
elseif arg[1] == "loaf" then
-- https://www.conwaylife.com/wiki/Loaf
grid[5][4] = 1
grid[5][5] = 1
grid[6][6] = 1
grid[7][6] = 1
grid[8][5] = 1
grid[7][4] = 1
grid[6][3] = 1
elseif file_exists(arg[1]) then
-- Load a file in the standard "plaintext" format: https://www.conwaylife.com/wiki/Plaintext
--
-- Each pattern page at https://www.conwaylife.com/wiki provides its
-- plaintext representation in a block called "Pattern Files" on the right.
--
-- For example, check out the list of Important Patterns at
-- https://www.conwaylife.com/wiki/Category:Patterns_with_Catagolue_frequency_class_0
load_file(window, arg[1])
end
-- main loop
while true do
render(window)
c = curses.getch()
update(window, c)
step()
end
end]==],
},
}

View File

@ -89,7 +89,9 @@ static void teliva_load_definition(lua_State* L, FILE* in) {
strcpy(line, "-\n"); strcpy(line, "-\n");
} }
else { else {
assert(fgets(line, 1024, in)); memset(line, '\0', 1024);
//? printf("%d\n", feof(in));
fgets(line, 1024, in);
//? printf("new line: %s", line); //? printf("new line: %s", line);
} }
} }

View File

@ -1,43 +0,0 @@
- __teliva_timestamp: foo1
window:
>window = curses.stdscr()
- __teliva_timestamp: foo2
n:
>n = 0
- __teliva_timestamp: foo3
render:
>function render(window)
> window:clear()
> window:attron(curses.A_BOLD)
> window:attron(curses.color_pair(6))
> window:mvaddstr(10, 10, " ")
> window:mvaddstr(10, 11, n)
> window:attroff(curses.color_pair(6))
> window:attroff(curses.A_BOLD)
> curses.refresh()
>end
__teliva_note: foo
- __teliva_timestamp: foo4
menu:
>menu = {Enter="increment"}
- __teliva_timestamp: foo5
update:
>function update(window)
> local key = curses.getch()
> if key == 10 then
> n = n+1
> end
>end
- __teliva_timestamp: foo6
main:
>function main()
> for i=1,7 do
> curses.init_pair(i, 0, i)
> end
> curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
>
> while true do
> render(window)
> update(window)
> end
>end

View File

@ -1,72 +1,69 @@
teliva_program = { # .tlv file generated by https://github.com/akkartik/teliva
{ # You may edit it if you are careful; however, you may see cryptic errors if you
__teliva_timestamp = [==[ # violate Teliva's assumptions.
original]==], #
window = [==[ # .tlv files are representations of Teliva programs. Teliva programs consist of
window = curses.stdscr()]==], # sequences of definitions. Each definition is a table of key/value pairs. Keys
}, # and values are both strings.
{ #
__teliva_timestamp = [==[ # Lines in .tlv files always follow exactly one of the following forms:
original]==], # - comment lines at the top of the file starting with '#' at column 0
render = [==[ # - beginnings of definitions starting with '- ' at column 0, followed by a
function render(window) # key/value pair
window:clear() # - key/value pairs consisting of ' ' at column 0, containing either a
-- draw stuff to screen here # spaceless value on the same line, or a multi-line value
window:attron(curses.A_BOLD) # - multiline values indented by more than 2 spaces, starting with a '>'
window:mvaddstr(1, 5, "example app") #
window:attrset(curses.A_NORMAL) # If these constraints are violated, Teliva may unceremoniously crash. Please
for i=0,15 do # report bugs at http://akkartik.name/contact
window:attrset(curses.color_pair(i)) - __teliva_timestamp: original
window:mvaddstr(3+i, 5, "========================") window:
end >window = curses.stdscr()
curses.refresh() - __teliva_timestamp: original
end]==], render:
}, >function render(window)
{ > window:clear()
__teliva_timestamp = [==[ > -- draw stuff to screen here
original]==], > window:attron(curses.A_BOLD)
menu = [==[ > window:mvaddstr(1, 5, "example app")
menu = {}]==], > window:attrset(curses.A_NORMAL)
}, > for i=0,15 do
{ > window:attrset(curses.color_pair(i))
__teliva_timestamp = [==[ > window:mvaddstr(3+i, 5, "========================")
original]==], > end
update = [==[ > curses.refresh()
function update(window) >end
local key = curses.getch() - __teliva_timestamp: original
-- process key here menu:
end]==], >menu = {}
}, - __teliva_timestamp: original
{ update:
init_colors = [==[ >function update(window)
function init_colors() > local key = curses.getch()
for i=0,7 do > -- process key here
curses.init_pair(i, i, -1) >end
end - init_colors:
curses.init_pair(8, 7, 0) >function init_colors()
curses.init_pair(9, 7, 1) > for i=0,7 do
curses.init_pair(10, 7, 2) > curses.init_pair(i, i, -1)
curses.init_pair(11, 7, 3) > end
curses.init_pair(12, 7, 4) > curses.init_pair(8, 7, 0)
curses.init_pair(13, 7, 5) > curses.init_pair(9, 7, 1)
curses.init_pair(14, 7, 6) > curses.init_pair(10, 7, 2)
curses.init_pair(15, -1, 15) > curses.init_pair(11, 7, 3)
end]==], > curses.init_pair(12, 7, 4)
__teliva_timestamp = [==[ > curses.init_pair(13, 7, 5)
original]==], > curses.init_pair(14, 7, 6)
}, > curses.init_pair(15, -1, 15)
{ >end
main = [==[ __teliva_timestamp: original
function main() - main:
init_colors() >function main()
> init_colors()
while true do >
render(window) > while true do
update(window) > render(window)
end > update(window)
end > end
]==], >end
__teliva_timestamp = [==[ __teliva_timestamp: original
original]==],
},
}