snapshot: migrate all sample apps to new format
This commit is contained in:
parent
d5038fe514
commit
c0c9d31688
453
advent.tlv
453
advent.tlv
|
@ -1,253 +1,200 @@
|
|||
teliva_program = {
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
norm = [==[
|
||||
function norm()
|
||||
window:attrset(curses.A_NORMAL)
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
bold = [==[
|
||||
function bold()
|
||||
window:attron(curses.A_BOLD)
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
rv = [==[
|
||||
function rv()
|
||||
window:attron(curses.A_REVERSE)
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
color = [==[
|
||||
function color(i)
|
||||
window:attron(curses.color_pair(i))
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
abbreviations = [==[
|
||||
clear = curses.clear
|
||||
refresh = curses.refresh
|
||||
getch = curses.getch
|
||||
addch = curses.addch
|
||||
mvaddch = curses.mvaddch
|
||||
pr = curses.addstr
|
||||
mpr = curses.mvaddstr
|
||||
str = tostring
|
||||
num = tonumber
|
||||
]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
str_helpers = [==[
|
||||
-- some string helpers from http://lua-users.org/wiki/StringIndexing
|
||||
|
||||
-- index characters using []
|
||||
getmetatable('').__index = function(str,i)
|
||||
if type(i) == 'number' then
|
||||
return string.sub(str,i,i)
|
||||
else
|
||||
return string[i]
|
||||
end
|
||||
end
|
||||
|
||||
-- ranges using (), selected bytes using {}
|
||||
getmetatable('').__call = function(str,i,j)
|
||||
if type(i)~='table' then
|
||||
return string.sub(str,i,j)
|
||||
else
|
||||
local t={}
|
||||
for k,v in ipairs(i) do
|
||||
t[k]=string.sub(str,v,v)
|
||||
end
|
||||
return table.concat(t)
|
||||
end
|
||||
end
|
||||
|
||||
-- iterate over an ordered sequence
|
||||
function q(x)
|
||||
if type(x) == 'string' then
|
||||
return x:gmatch('.')
|
||||
else
|
||||
return ipairs(x)
|
||||
end
|
||||
end
|
||||
|
||||
-- TODO: backport utf-8 support from Lua 5.3
|
||||
]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
prn = [==[
|
||||
-- functional form of 'print'
|
||||
-- use this in map/reduce/filter
|
||||
function prn(...)
|
||||
print(unpack(arg))
|
||||
return arg[1]
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
add = [==[
|
||||
add = table.insert]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
map = [==[
|
||||
-- only for arrays
|
||||
function map(l, f)
|
||||
result = {}
|
||||
for _, x in q(l) do
|
||||
add(result, f(x))
|
||||
end
|
||||
return result
|
||||
end
|
||||
]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
reduce = [==[
|
||||
-- only for arrays
|
||||
function reduce(l, f, init)
|
||||
result = init
|
||||
for _, x in q(l) do
|
||||
result = f(result, x)
|
||||
end
|
||||
return result
|
||||
end
|
||||
]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
filter = [==[
|
||||
-- only for arrays
|
||||
function filter(l, f)
|
||||
result = {}
|
||||
for _, x in q(l) do
|
||||
if f(x) then
|
||||
add(result, x)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
find_index = [==[
|
||||
function find_index(arr, x)
|
||||
for n, y in q(arr) do
|
||||
if x == y then
|
||||
return n
|
||||
end
|
||||
end
|
||||
end
|
||||
]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
trim = [==[
|
||||
function trim(s)
|
||||
return s:gsub('^%s*', ''):gsub('%s*$', '')
|
||||
end
|
||||
]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
split = [==[
|
||||
function split(s, d)
|
||||
result = {}
|
||||
for match in (s..d):gmatch("(.-)"..d) do
|
||||
add(result, match);
|
||||
end
|
||||
return result
|
||||
end
|
||||
]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
window = [==[
|
||||
window = curses.stdscr()]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
render = [==[
|
||||
function render(window)
|
||||
clear()
|
||||
-- draw stuff to screen here
|
||||
for line in io.lines("input") do
|
||||
pr(line)
|
||||
pr("\n")
|
||||
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]==],
|
||||
},
|
||||
}
|
||||
# .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
|
||||
# violate Teliva's assumptions.
|
||||
#
|
||||
# .tlv files are representations of Teliva programs. Teliva programs consist of
|
||||
# sequences of definitions. Each definition is a table of key/value pairs. Keys
|
||||
# and values are both strings.
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
# - multiline values indented by more than 2 spaces, starting with a '>'
|
||||
#
|
||||
# If these constraints are violated, Teliva may unceremoniously crash. Please
|
||||
# report bugs at http://akkartik.name/contact
|
||||
- __teliva_timestamp: original
|
||||
norm:
|
||||
>function norm()
|
||||
> window:attrset(curses.A_NORMAL)
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
bold:
|
||||
>function bold()
|
||||
> window:attron(curses.A_BOLD)
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
rv:
|
||||
>function rv()
|
||||
> window:attron(curses.A_REVERSE)
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
color:
|
||||
>function color(i)
|
||||
> window:attron(curses.color_pair(i))
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
abbreviations:
|
||||
>clear = curses.clear
|
||||
>refresh = curses.refresh
|
||||
>getch = curses.getch
|
||||
>addch = curses.addch
|
||||
>mvaddch = curses.mvaddch
|
||||
>pr = curses.addstr
|
||||
>mpr = curses.mvaddstr
|
||||
>str = tostring
|
||||
>num = tonumber
|
||||
- __teliva_timestamp: original
|
||||
str_helpers:
|
||||
>-- some string helpers from http://lua-users.org/wiki/StringIndexing
|
||||
>
|
||||
>-- index characters using []
|
||||
>getmetatable('').__index = function(str,i)
|
||||
> if type(i) == 'number' then
|
||||
> return string.sub(str,i,i)
|
||||
> else
|
||||
> return string[i]
|
||||
> end
|
||||
>end
|
||||
>
|
||||
>-- ranges using (), selected bytes using {}
|
||||
>getmetatable('').__call = function(str,i,j)
|
||||
> if type(i)~='table' then
|
||||
> return string.sub(str,i,j)
|
||||
> else
|
||||
> local t={}
|
||||
> for k,v in ipairs(i) do
|
||||
> t[k]=string.sub(str,v,v)
|
||||
> end
|
||||
> return table.concat(t)
|
||||
> end
|
||||
>end
|
||||
>
|
||||
>-- iterate over an ordered sequence
|
||||
>function q(x)
|
||||
> if type(x) == 'string' then
|
||||
> return x:gmatch('.')
|
||||
> else
|
||||
> return ipairs(x)
|
||||
> end
|
||||
>end
|
||||
>
|
||||
>-- TODO: backport utf-8 support from Lua 5.3
|
||||
- __teliva_timestamp: original
|
||||
prn:
|
||||
>-- functional form of 'print'
|
||||
>-- use this in map/reduce/filter
|
||||
>function prn(...)
|
||||
> print(unpack(arg))
|
||||
> return arg[1]
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
add:
|
||||
>add = table.insert
|
||||
- __teliva_timestamp: original
|
||||
map:
|
||||
>-- only for arrays
|
||||
>function map(l, f)
|
||||
> result = {}
|
||||
> for _, x in q(l) do
|
||||
> add(result, f(x))
|
||||
> end
|
||||
> return result
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
reduce:
|
||||
>-- only for arrays
|
||||
>function reduce(l, f, init)
|
||||
> result = init
|
||||
> for _, x in q(l) do
|
||||
> result = f(result, x)
|
||||
> end
|
||||
> return result
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
filter:
|
||||
>-- only for arrays
|
||||
>function filter(l, f)
|
||||
> result = {}
|
||||
> for _, x in q(l) do
|
||||
> if f(x) then
|
||||
> add(result, x)
|
||||
> end
|
||||
> end
|
||||
> return result
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
find_index:
|
||||
>function find_index(arr, x)
|
||||
> for n, y in q(arr) do
|
||||
> if x == y then
|
||||
> return n
|
||||
> end
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
trim:
|
||||
>function trim(s)
|
||||
> return s:gsub('^%s*', ''):gsub('%s*$', '')
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
split:
|
||||
>function split(s, d)
|
||||
> result = {}
|
||||
> for match in (s..d):gmatch("(.-)"..d) do
|
||||
> add(result, match);
|
||||
> end
|
||||
> return result
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
window:
|
||||
>window = curses.stdscr()
|
||||
- __teliva_timestamp: original
|
||||
render:
|
||||
>function render(window)
|
||||
> clear()
|
||||
> -- draw stuff to screen here
|
||||
> for line in io.lines("input") do
|
||||
> pr(line)
|
||||
> pr("\n")
|
||||
> 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
|
||||
|
|
561
chesstv.tlv
561
chesstv.tlv
|
@ -1,298 +1,263 @@
|
|||
teliva_program = {
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
window = [==[
|
||||
window = curses.stdscr()
|
||||
-- animation-based app
|
||||
window:nodelay(true)
|
||||
lines, cols = window:getmaxyx()]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
current_game = [==[
|
||||
current_game = {}]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
piece_glyph = [==[
|
||||
piece_glyph = {
|
||||
-- for legibility, white pieces also use unicode glyphs for black pieces
|
||||
-- we rely on colors to distinguish them
|
||||
K = 0x265a,
|
||||
Q = 0x265b,
|
||||
R = 0x265c,
|
||||
B = 0x265d,
|
||||
N = 0x265e,
|
||||
P = 0x265f,
|
||||
k = 0x265a,
|
||||
q = 0x265b,
|
||||
r = 0x265c,
|
||||
b = 0x265d,
|
||||
n = 0x265e,
|
||||
p = 0x265f,
|
||||
}]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
top_player = [==[
|
||||
function top_player(current_game)
|
||||
if current_game.players[1].color == "black" then
|
||||
return current_game.players[1]
|
||||
end
|
||||
return current_game.players[2]
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
bottom_player = [==[
|
||||
function bottom_player(current_game)
|
||||
if current_game.players[1].color == "white" then
|
||||
return current_game.players[1]
|
||||
end
|
||||
return current_game.players[2]
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
render_player = [==[
|
||||
function render_player(y, x, player)
|
||||
curses.mvaddstr(y, x, player.user.name)
|
||||
curses.addstr(" · ")
|
||||
curses.addstr(tostring(player.rating))
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
render_square = [==[
|
||||
function render_square(current_game, rank, file, highlighted_squares)
|
||||
-- decide whether to highlight
|
||||
local hl = 0
|
||||
if (rank == highlighted_squares.from.rank and file == highlighted_squares.from.file)
|
||||
or (rank == highlighted_squares.to.rank and file == highlighted_squares.to.file) then
|
||||
hl = 4
|
||||
end
|
||||
if (rank+file)%2 == 1 then
|
||||
-- light square
|
||||
curses.attrset(curses.color_pair(1+hl))
|
||||
else
|
||||
-- dark square
|
||||
curses.attrset(curses.color_pair(3+hl))
|
||||
end
|
||||
curses.mvaddstr((8 - rank + 1)*3, file*5, " ")
|
||||
curses.mvaddstr((8 - rank + 1)*3+1, file*5, " ")
|
||||
curses.mvaddstr((8 - rank + 1)*3+2, file*5, " ")
|
||||
curses.attrset(curses.A_NORMAL)
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
render_fen_rank = [==[
|
||||
function render_fen_rank(rank, fen_rank, highlighted_squares)
|
||||
local file = 1
|
||||
for x in fen_rank:gmatch(".") do
|
||||
if x:match("%d") then
|
||||
file = file + tonumber(x)
|
||||
else
|
||||
-- decide whether to highlight
|
||||
local hl = 0
|
||||
if (rank == highlighted_squares.from.rank and file == highlighted_squares.from.file)
|
||||
or (rank == highlighted_squares.to.rank and file == highlighted_squares.to.file) then
|
||||
hl = 4
|
||||
end
|
||||
if (rank+file)%2 == 1 then
|
||||
if x < 'Z' then
|
||||
-- white piece on light square
|
||||
curses.attrset(curses.color_pair(1+hl))
|
||||
else
|
||||
-- black piece on light square
|
||||
curses.attrset(curses.color_pair(2+hl))
|
||||
end
|
||||
else
|
||||
if x < 'Z' then
|
||||
-- white piece on dark square
|
||||
curses.attrset(curses.color_pair(3+hl))
|
||||
else
|
||||
-- black piece on dark square
|
||||
curses.attrset(curses.color_pair(4+hl))
|
||||
end
|
||||
end
|
||||
curses.mvaddstr((8 - rank + 1)*3+1, file*5+2, utf8(piece_glyph[x]))
|
||||
curses.attrset(curses.A_NORMAL)
|
||||
file = file + 1
|
||||
end
|
||||
end
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
render_time = [==[
|
||||
function render_time(y, x, seconds)
|
||||
if seconds == nil then return end
|
||||
curses.mvaddstr(y, x, tostring(math.floor(seconds/60)))
|
||||
curses.addstr(string.format(":%02d", seconds%60))
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
render_board = [==[
|
||||
function render_board(current_game)
|
||||
--? curses.mvaddstr(1, 50, dump(current_game.fen))
|
||||
--? curses.mvaddstr(6, 50, dump(current_game.previously_moved_squares))
|
||||
render_player(2, 5, top_player(current_game))
|
||||
render_time(2, 35, current_game.bc)
|
||||
for rank=8,1,-1 do
|
||||
for file=1,8 do
|
||||
render_square(current_game, rank, file, current_game.previously_moved_squares)
|
||||
end
|
||||
render_fen_rank(rank, current_game.fen_rank[8-rank+1], current_game.previously_moved_squares)
|
||||
end
|
||||
render_player(27, 5, bottom_player(current_game))
|
||||
render_time(27, 35, current_game.wc)
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
parse_lm = [==[
|
||||
function parse_lm(move)
|
||||
--? curses.mvaddstr(4, 50, move)
|
||||
local file1 = string.byte(move:sub(1, 1)) - 96 -- 'a'-1
|
||||
local rank1 = string.byte(move:sub(2, 2)) - 48 -- '0'
|
||||
local file2 = string.byte(move:sub(3, 3)) - 96 -- 'a'-1
|
||||
local rank2 = string.byte(move:sub(4, 4)) - 48 -- '0'
|
||||
--? curses.mvaddstr(5, 50, dump({{rank1, file1}, {rank2, file2}}))
|
||||
return {from={rank=rank1, file=file1}, to={rank=rank2, file=file2}}
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
render = [==[
|
||||
function render(chunk)
|
||||
local o = json.decode(chunk)
|
||||
if o.t == "featured" then
|
||||
current_game = o.d
|
||||
--? current_game.lm = "__"
|
||||
current_game.previously_moved_squares = {from={rank=0, file=0}, to={rank=0, file=0}} -- no highlight
|
||||
else
|
||||
current_game.fen = o.d.fen
|
||||
current_game.wc = o.d.wc
|
||||
current_game.bc = o.d.bc
|
||||
--? current_game.lm = o.d.lm
|
||||
current_game.previously_moved_squares = parse_lm(o.d.lm)
|
||||
--? window:nodelay(false)
|
||||
--? curses.mvaddstr(3, 50, "paused")
|
||||
end
|
||||
current_game.fen_rank = split(current_game.fen, "%w+")
|
||||
render_board(current_game)
|
||||
curses.refresh()
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
init_colors = [==[
|
||||
function init_colors()
|
||||
-- colors
|
||||
local light_piece = 1
|
||||
local dark_piece = 0
|
||||
local light_square = 252
|
||||
local dark_square = 242
|
||||
local light_last_moved_square = 229
|
||||
local dark_last_moved_square = 226
|
||||
-- initialize colors
|
||||
curses.init_pair(1, light_piece, light_square)
|
||||
curses.init_pair(2, dark_piece, light_square)
|
||||
curses.init_pair(3, light_piece, dark_square)
|
||||
curses.init_pair(4, dark_piece, dark_square)
|
||||
curses.init_pair(5, light_piece, light_last_moved_square)
|
||||
curses.init_pair(6, dark_piece, light_last_moved_square)
|
||||
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
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
main = [==[
|
||||
function main()
|
||||
init_colors()
|
||||
local request = {
|
||||
url = "https://lichess.org/api/tv/feed",
|
||||
sink = function(chunk, err)
|
||||
if chunk then
|
||||
curses.clear()
|
||||
render(chunk)
|
||||
curses.getch()
|
||||
end
|
||||
return 1
|
||||
end,
|
||||
}
|
||||
http.request(request)
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
utf8 = [==[
|
||||
-- https://stackoverflow.com/questions/7983574/how-to-write-a-unicode-symbol-in-lua
|
||||
function utf8(decimal)
|
||||
local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} }
|
||||
if decimal<128 then return string.char(decimal) end
|
||||
local charbytes = {}
|
||||
for bytes,vals in ipairs(bytemarkers) do
|
||||
if decimal<=vals[1] then
|
||||
for b=bytes+1,2,-1 do
|
||||
local mod = decimal%64
|
||||
decimal = (decimal-mod)/64
|
||||
charbytes[b] = string.char(128+mod)
|
||||
end
|
||||
charbytes[1] = string.char(vals[2]+decimal)
|
||||
break
|
||||
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]==],
|
||||
},
|
||||
}
|
||||
# .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
|
||||
# violate Teliva's assumptions.
|
||||
#
|
||||
# .tlv files are representations of Teliva programs. Teliva programs consist of
|
||||
# sequences of definitions. Each definition is a table of key/value pairs. Keys
|
||||
# and values are both strings.
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
# - multiline values indented by more than 2 spaces, starting with a '>'
|
||||
#
|
||||
# If these constraints are violated, Teliva may unceremoniously crash. Please
|
||||
# report bugs at http://akkartik.name/contact
|
||||
- __teliva_timestamp: original
|
||||
window:
|
||||
>window = curses.stdscr()
|
||||
>-- animation-based app
|
||||
>window:nodelay(true)
|
||||
>lines, cols = window:getmaxyx()
|
||||
- __teliva_timestamp: original
|
||||
current_game:
|
||||
>current_game = {}
|
||||
- __teliva_timestamp: original
|
||||
piece_glyph:
|
||||
>piece_glyph = {
|
||||
> -- for legibility, white pieces also use unicode glyphs for black pieces
|
||||
> -- we rely on colors to distinguish them
|
||||
> K = 0x265a,
|
||||
> Q = 0x265b,
|
||||
> R = 0x265c,
|
||||
> B = 0x265d,
|
||||
> N = 0x265e,
|
||||
> P = 0x265f,
|
||||
> k = 0x265a,
|
||||
> q = 0x265b,
|
||||
> r = 0x265c,
|
||||
> b = 0x265d,
|
||||
> n = 0x265e,
|
||||
> p = 0x265f,
|
||||
>}
|
||||
- __teliva_timestamp: original
|
||||
top_player:
|
||||
>function top_player(current_game)
|
||||
> if current_game.players[1].color == "black" then
|
||||
> return current_game.players[1]
|
||||
> end
|
||||
> return current_game.players[2]
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
bottom_player:
|
||||
>function bottom_player(current_game)
|
||||
> if current_game.players[1].color == "white" then
|
||||
> return current_game.players[1]
|
||||
> end
|
||||
> return current_game.players[2]
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
render_player:
|
||||
>function render_player(y, x, player)
|
||||
> curses.mvaddstr(y, x, player.user.name)
|
||||
> curses.addstr(" · ")
|
||||
> curses.addstr(tostring(player.rating))
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
render_square:
|
||||
>function render_square(current_game, rank, file, highlighted_squares)
|
||||
> -- decide whether to highlight
|
||||
> local hl = 0
|
||||
> if (rank == highlighted_squares.from.rank and file == highlighted_squares.from.file)
|
||||
> or (rank == highlighted_squares.to.rank and file == highlighted_squares.to.file) then
|
||||
> hl = 4
|
||||
> end
|
||||
> if (rank+file)%2 == 1 then
|
||||
> -- light square
|
||||
> curses.attrset(curses.color_pair(1+hl))
|
||||
> else
|
||||
> -- dark square
|
||||
> curses.attrset(curses.color_pair(3+hl))
|
||||
> end
|
||||
> curses.mvaddstr((8 - rank + 1)*3, file*5, " ")
|
||||
> curses.mvaddstr((8 - rank + 1)*3+1, file*5, " ")
|
||||
> curses.mvaddstr((8 - rank + 1)*3+2, file*5, " ")
|
||||
> curses.attrset(curses.A_NORMAL)
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
render_fen_rank:
|
||||
>function render_fen_rank(rank, fen_rank, highlighted_squares)
|
||||
> local file = 1
|
||||
> for x in fen_rank:gmatch(".") do
|
||||
> if x:match("%d") then
|
||||
> file = file + tonumber(x)
|
||||
> else
|
||||
> -- decide whether to highlight
|
||||
> local hl = 0
|
||||
> if (rank == highlighted_squares.from.rank and file == highlighted_squares.from.file)
|
||||
> or (rank == highlighted_squares.to.rank and file == highlighted_squares.to.file) then
|
||||
> hl = 4
|
||||
> end
|
||||
> if (rank+file)%2 == 1 then
|
||||
> if x < 'Z' then
|
||||
> -- white piece on light square
|
||||
> curses.attrset(curses.color_pair(1+hl))
|
||||
> else
|
||||
> -- black piece on light square
|
||||
> curses.attrset(curses.color_pair(2+hl))
|
||||
> end
|
||||
> else
|
||||
> if x < 'Z' then
|
||||
> -- white piece on dark square
|
||||
> curses.attrset(curses.color_pair(3+hl))
|
||||
> else
|
||||
> -- black piece on dark square
|
||||
> curses.attrset(curses.color_pair(4+hl))
|
||||
> end
|
||||
> end
|
||||
> curses.mvaddstr((8 - rank + 1)*3+1, file*5+2, utf8(piece_glyph[x]))
|
||||
> curses.attrset(curses.A_NORMAL)
|
||||
> file = file + 1
|
||||
> end
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
render_time:
|
||||
>function render_time(y, x, seconds)
|
||||
> if seconds == nil then return end
|
||||
> curses.mvaddstr(y, x, tostring(math.floor(seconds/60)))
|
||||
> curses.addstr(string.format(":%02d", seconds%60))
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
render_board:
|
||||
>function render_board(current_game)
|
||||
>--? curses.mvaddstr(1, 50, dump(current_game.fen))
|
||||
>--? curses.mvaddstr(6, 50, dump(current_game.previously_moved_squares))
|
||||
> render_player(2, 5, top_player(current_game))
|
||||
> render_time(2, 35, current_game.bc)
|
||||
> for rank=8,1,-1 do
|
||||
> for file=1,8 do
|
||||
> render_square(current_game, rank, file, current_game.previously_moved_squares)
|
||||
> end
|
||||
> render_fen_rank(rank, current_game.fen_rank[8-rank+1], current_game.previously_moved_squares)
|
||||
> end
|
||||
> render_player(27, 5, bottom_player(current_game))
|
||||
> render_time(27, 35, current_game.wc)
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
parse_lm:
|
||||
>function parse_lm(move)
|
||||
>--? curses.mvaddstr(4, 50, move)
|
||||
> local file1 = string.byte(move:sub(1, 1)) - 96 -- 'a'-1
|
||||
> local rank1 = string.byte(move:sub(2, 2)) - 48 -- '0'
|
||||
> local file2 = string.byte(move:sub(3, 3)) - 96 -- 'a'-1
|
||||
> local rank2 = string.byte(move:sub(4, 4)) - 48 -- '0'
|
||||
>--? curses.mvaddstr(5, 50, dump({{rank1, file1}, {rank2, file2}}))
|
||||
> return {from={rank=rank1, file=file1}, to={rank=rank2, file=file2}}
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
render:
|
||||
>function render(chunk)
|
||||
> local o = json.decode(chunk)
|
||||
> if o.t == "featured" then
|
||||
> current_game = o.d
|
||||
>--? current_game.lm = "__"
|
||||
> current_game.previously_moved_squares = {from={rank=0, file=0}, to={rank=0, file=0}} -- no highlight
|
||||
> else
|
||||
> current_game.fen = o.d.fen
|
||||
> current_game.wc = o.d.wc
|
||||
> current_game.bc = o.d.bc
|
||||
>--? current_game.lm = o.d.lm
|
||||
> current_game.previously_moved_squares = parse_lm(o.d.lm)
|
||||
>--? window:nodelay(false)
|
||||
>--? curses.mvaddstr(3, 50, "paused")
|
||||
> end
|
||||
> current_game.fen_rank = split(current_game.fen, "%w+")
|
||||
> render_board(current_game)
|
||||
> curses.refresh()
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
init_colors:
|
||||
>function init_colors()
|
||||
> -- colors
|
||||
> local light_piece = 1
|
||||
> local dark_piece = 0
|
||||
> local light_square = 252
|
||||
> local dark_square = 242
|
||||
> local light_last_moved_square = 229
|
||||
> local dark_last_moved_square = 226
|
||||
> -- initialize colors
|
||||
> curses.init_pair(1, light_piece, light_square)
|
||||
> curses.init_pair(2, dark_piece, light_square)
|
||||
> curses.init_pair(3, light_piece, dark_square)
|
||||
> curses.init_pair(4, dark_piece, dark_square)
|
||||
> curses.init_pair(5, light_piece, light_last_moved_square)
|
||||
> curses.init_pair(6, dark_piece, light_last_moved_square)
|
||||
> 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
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
main:
|
||||
>function main()
|
||||
> init_colors()
|
||||
> local request = {
|
||||
> url = "https://lichess.org/api/tv/feed",
|
||||
> sink = function(chunk, err)
|
||||
> if chunk then
|
||||
> curses.clear()
|
||||
> render(chunk)
|
||||
> curses.getch()
|
||||
> end
|
||||
> return 1
|
||||
> end,
|
||||
> }
|
||||
> http.request(request)
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
utf8:
|
||||
>-- https://stackoverflow.com/questions/7983574/how-to-write-a-unicode-symbol-in-lua
|
||||
>function utf8(decimal)
|
||||
> local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} }
|
||||
> if decimal<128 then return string.char(decimal) end
|
||||
> local charbytes = {}
|
||||
> for bytes,vals in ipairs(bytemarkers) do
|
||||
> if decimal<=vals[1] then
|
||||
> for b=bytes+1,2,-1 do
|
||||
> local mod = decimal%64
|
||||
> decimal = (decimal-mod)/64
|
||||
> charbytes[b] = string.char(128+mod)
|
||||
> end
|
||||
> charbytes[1] = string.char(vals[2]+decimal)
|
||||
> break
|
||||
> 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
|
||||
|
|
123
counter.tlv
123
counter.tlv
|
@ -1,62 +1,61 @@
|
|||
teliva_program = {
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
window = [==[
|
||||
window = curses.stdscr()]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
n = [==[
|
||||
n = 0]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
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_timestamp = [==[
|
||||
original]==],
|
||||
menu = [==[
|
||||
menu = {Enter="increment"}]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
update = [==[
|
||||
function update(window)
|
||||
local key = curses.getch()
|
||||
if key == 10 then
|
||||
n = n+1
|
||||
end
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
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]==],
|
||||
},
|
||||
}
|
||||
# .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
|
||||
# violate Teliva's assumptions.
|
||||
#
|
||||
# .tlv files are representations of Teliva programs. Teliva programs consist of
|
||||
# sequences of definitions. Each definition is a table of key/value pairs. Keys
|
||||
# and values are both strings.
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
# - multiline values indented by more than 2 spaces, starting with a '>'
|
||||
#
|
||||
# If these constraints are violated, Teliva may unceremoniously crash. Please
|
||||
# report bugs at http://akkartik.name/contact
|
||||
- __teliva_timestamp: original
|
||||
window:
|
||||
>window = curses.stdscr()
|
||||
- __teliva_timestamp: original
|
||||
n:
|
||||
>n = 0
|
||||
- __teliva_timestamp: original
|
||||
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: original
|
||||
menu:
|
||||
>menu = {Enter="increment"}
|
||||
- __teliva_timestamp: original
|
||||
update:
|
||||
>function update(window)
|
||||
> local key = curses.getch()
|
||||
> if key == 10 then
|
||||
> n = n+1
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
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
|
||||
|
|
267
hanoi.tlv
267
hanoi.tlv
|
@ -1,144 +1,123 @@
|
|||
teliva_program = {
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
render = [==[
|
||||
function render(window)
|
||||
window:clear()
|
||||
local lines, cols = window:getmaxyx()
|
||||
local line = math.floor(lines/2)
|
||||
local col = math.floor(cols/4)
|
||||
for i,t in ipairs(tower) do
|
||||
render_tower(window, line, i*col, i, t)
|
||||
end
|
||||
curses.refresh()
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
lines = [==[
|
||||
function lines(window)
|
||||
local lines, cols = window:getmaxyx()
|
||||
return lines
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
pop = [==[
|
||||
function pop(array)
|
||||
return table.remove(array)
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
window = [==[
|
||||
window = curses.stdscr()]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
render_tower = [==[
|
||||
function render_tower(window, line, col, tower_index, tower)
|
||||
window:attron(curses.A_BOLD)
|
||||
window:mvaddch(line+2, col, string.char(96+tower_index))
|
||||
window:attroff(curses.A_BOLD)
|
||||
window:attron(curses.color_pair(15))
|
||||
window:mvaddstr(line+1, col-6, " ")
|
||||
window:attroff(curses.color_pair(15))
|
||||
for i, n in ipairs(tower) do
|
||||
render_disk(window, line, col, n)
|
||||
line = line - 1
|
||||
end
|
||||
for i=1,5-len(tower)+1 do
|
||||
window:attron(curses.color_pair(15))
|
||||
window:mvaddstr(line, col, " ")
|
||||
window:attroff(curses.color_pair(15))
|
||||
line = line - 1
|
||||
end
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
tower = [==[
|
||||
tower = {{6, 5, 4, 3, 2}, {}, {}}]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
render_disk = [==[
|
||||
function render_disk(window, line, col, size)
|
||||
col = col-size+1
|
||||
for i=1,size do
|
||||
window:attron(curses.color_pair(size))
|
||||
window:mvaddstr(line, col, " ")
|
||||
window:attroff(curses.color_pair(size))
|
||||
col = col+2
|
||||
end
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
main = [==[
|
||||
function main()
|
||||
curses.assume_default_colors(250, 139)
|
||||
for i=1,7 do
|
||||
curses.init_pair(i, 0, i)
|
||||
end
|
||||
curses.init_pair(15, 0, 250) -- tower frames
|
||||
curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
|
||||
|
||||
while true do
|
||||
render(window)
|
||||
update(window)
|
||||
end
|
||||
end
|
||||
]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
len = [==[
|
||||
function len(array)
|
||||
local result = 0
|
||||
for k in pairs(array) do
|
||||
result = result+1
|
||||
end
|
||||
return result
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
update = [==[
|
||||
function update(window)
|
||||
window:mvaddstr(lines(window)-2, 5, "tower to remove top disk from? ")
|
||||
local from = curses.getch() - 96
|
||||
window:mvaddstr(lines(window)-1, 5, "tower to stack it on? ")
|
||||
local to = curses.getch() - 96
|
||||
make_move(from, to)
|
||||
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]==],
|
||||
},
|
||||
}
|
||||
# .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
|
||||
# violate Teliva's assumptions.
|
||||
#
|
||||
# .tlv files are representations of Teliva programs. Teliva programs consist of
|
||||
# sequences of definitions. Each definition is a table of key/value pairs. Keys
|
||||
# and values are both strings.
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
# - multiline values indented by more than 2 spaces, starting with a '>'
|
||||
#
|
||||
# If these constraints are violated, Teliva may unceremoniously crash. Please
|
||||
# report bugs at http://akkartik.name/contact
|
||||
- __teliva_timestamp: original
|
||||
render:
|
||||
>function render(window)
|
||||
> window:clear()
|
||||
> local lines, cols = window:getmaxyx()
|
||||
> local line = math.floor(lines/2)
|
||||
> local col = math.floor(cols/4)
|
||||
> for i,t in ipairs(tower) do
|
||||
> render_tower(window, line, i*col, i, t)
|
||||
> end
|
||||
> curses.refresh()
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
lines:
|
||||
>function lines(window)
|
||||
> local lines, cols = window:getmaxyx()
|
||||
> return lines
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
pop:
|
||||
>function pop(array)
|
||||
> return table.remove(array)
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
window:
|
||||
>window = curses.stdscr()
|
||||
- __teliva_timestamp: original
|
||||
render_tower:
|
||||
>function render_tower(window, line, col, tower_index, tower)
|
||||
> window:attron(curses.A_BOLD)
|
||||
> window:mvaddch(line+2, col, string.char(96+tower_index))
|
||||
> window:attroff(curses.A_BOLD)
|
||||
> window:attron(curses.color_pair(15))
|
||||
> window:mvaddstr(line+1, col-6, " ")
|
||||
> window:attroff(curses.color_pair(15))
|
||||
> for i, n in ipairs(tower) do
|
||||
> render_disk(window, line, col, n)
|
||||
> line = line - 1
|
||||
> end
|
||||
> for i=1,5-len(tower)+1 do
|
||||
> window:attron(curses.color_pair(15))
|
||||
> window:mvaddstr(line, col, " ")
|
||||
> window:attroff(curses.color_pair(15))
|
||||
> line = line - 1
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
tower:
|
||||
>tower = {{6, 5, 4, 3, 2}, {}, {}}
|
||||
- __teliva_timestamp: original
|
||||
render_disk:
|
||||
>function render_disk(window, line, col, size)
|
||||
> col = col-size+1
|
||||
> for i=1,size do
|
||||
> window:attron(curses.color_pair(size))
|
||||
> window:mvaddstr(line, col, " ")
|
||||
> window:attroff(curses.color_pair(size))
|
||||
> col = col+2
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
main:
|
||||
>function main()
|
||||
> curses.assume_default_colors(250, 139)
|
||||
> for i=1,7 do
|
||||
> curses.init_pair(i, 0, i)
|
||||
> end
|
||||
> curses.init_pair(15, 0, 250) -- tower frames
|
||||
> curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
|
||||
>
|
||||
> while true do
|
||||
> render(window)
|
||||
> update(window)
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
len:
|
||||
>function len(array)
|
||||
> local result = 0
|
||||
> for k in pairs(array) do
|
||||
> result = result+1
|
||||
> end
|
||||
> return result
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
update:
|
||||
>function update(window)
|
||||
> window:mvaddstr(lines(window)-2, 5, "tower to remove top disk from? ")
|
||||
> local from = curses.getch() - 96
|
||||
> window:mvaddstr(lines(window)-1, 5, "tower to stack it on? ")
|
||||
> local to = curses.getch() - 96
|
||||
> make_move(from, to)
|
||||
>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
650
life.tlv
|
@ -1,342 +1,308 @@
|
|||
teliva_program = {
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
grid = [==[
|
||||
-- main data structure
|
||||
grid = {}
|
||||
for i=1,lines*4 do
|
||||
grid[i] = {}
|
||||
for j=1,cols*2 do
|
||||
grid[i][j] = 0
|
||||
end
|
||||
end
|
||||
]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
window = [==[
|
||||
window = curses.stdscr()
|
||||
-- animation-based app
|
||||
window:nodelay(true)
|
||||
lines, cols = window:getmaxyx()]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
grid_char = [==[
|
||||
-- grab a 4x2 chunk of grid
|
||||
function grid_char(line, col)
|
||||
result = {}
|
||||
for l, row in ipairs({unpack(grid, (line-1)*4+1, line*4)}) do
|
||||
result[l] = {unpack(row, (col-1)*2+1, col*2)}
|
||||
end
|
||||
return result
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
print_grid_char = [==[
|
||||
function print_grid_char(window, x)
|
||||
result = {}
|
||||
for l, row in ipairs(x) do
|
||||
for c, val in ipairs(row) do
|
||||
window:mvaddstr(l, c, val)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
glyph = [==[
|
||||
-- look up the braille pattern corresponding to a 4x2 chunk of grid
|
||||
-- https://en.wikipedia.org/wiki/Braille_Patterns
|
||||
-- not obviously programmatic because Unicode added 4x2 after 3x2
|
||||
glyph = {
|
||||
0x2800, 0x2801, 0x2802, 0x2803, 0x2804, 0x2805, 0x2806, 0x2807, 0x2840, 0x2841, 0x2842, 0x2843, 0x2844, 0x2845, 0x2846, 0x2847,
|
||||
0x2808, 0x2809, 0x280a, 0x280b, 0x280c, 0x280d, 0x280e, 0x280f, 0x2848, 0x2849, 0x284a, 0x284b, 0x284c, 0x284d, 0x284e, 0x284f,
|
||||
0x2810, 0x2811, 0x2812, 0x2813, 0x2814, 0x2815, 0x2816, 0x2817, 0x2850, 0x2851, 0x2852, 0x2853, 0x2854, 0x2855, 0x2856, 0x2857,
|
||||
0x2818, 0x2819, 0x281a, 0x281b, 0x281c, 0x281d, 0x281e, 0x281f, 0x2858, 0x2859, 0x285a, 0x285b, 0x285c, 0x285d, 0x285e, 0x285f,
|
||||
0x2820, 0x2821, 0x2822, 0x2823, 0x2824, 0x2825, 0x2826, 0x2827, 0x2860, 0x2861, 0x2862, 0x2863, 0x2864, 0x2865, 0x2866, 0x2867,
|
||||
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,
|
||||
0x2838, 0x2839, 0x283a, 0x283b, 0x283c, 0x283d, 0x283e, 0x283f, 0x2878, 0x2879, 0x287a, 0x287b, 0x287c, 0x287d, 0x287e, 0x287f,
|
||||
|
||||
0x2880, 0x2881, 0x2882, 0x2883, 0x2884, 0x2885, 0x2886, 0x2887, 0x28c0, 0x28c1, 0x28c2, 0x28c3, 0x28c4, 0x28c5, 0x28c6, 0x28c7,
|
||||
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,
|
||||
0x2898, 0x2899, 0x289a, 0x289b, 0x289c, 0x289d, 0x289e, 0x289f, 0x28d8, 0x28d9, 0x28da, 0x28db, 0x28dc, 0x28dd, 0x28de, 0x28df,
|
||||
0x28a0, 0x28a1, 0x28a2, 0x28a3, 0x28a4, 0x28a5, 0x28a6, 0x28a7, 0x28e0, 0x28e1, 0x28e2, 0x28e3, 0x28e4, 0x28e5, 0x28e6, 0x28e7,
|
||||
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 = [==[
|
||||
original]==],
|
||||
utf8 = [==[
|
||||
-- https://stackoverflow.com/questions/7983574/how-to-write-a-unicode-symbol-in-lua
|
||||
function utf8(decimal)
|
||||
local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} }
|
||||
if decimal<128 then return string.char(decimal) end
|
||||
local charbytes = {}
|
||||
for bytes,vals in ipairs(bytemarkers) do
|
||||
if decimal<=vals[1] then
|
||||
for b=bytes+1,2,-1 do
|
||||
local mod = decimal%64
|
||||
decimal = (decimal-mod)/64
|
||||
charbytes[b] = string.char(128+mod)
|
||||
end
|
||||
charbytes[1] = string.char(vals[2]+decimal)
|
||||
break
|
||||
end
|
||||
end
|
||||
return table.concat(charbytes)
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
grid_char_to_glyph_index = [==[
|
||||
-- convert a chunk of grid into a number
|
||||
function grid_char_to_glyph_index(g)
|
||||
return g[1][1] + g[2][1]*2 + g[3][1]*4 + g[4][1]*8 +
|
||||
g[1][2]*16 + g[2][2]*32 + g[3][2]*64 + g[4][2]*128 +
|
||||
1 -- 1-indexing
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
render = [==[
|
||||
function render(window)
|
||||
window:clear()
|
||||
curses.attron(curses.color_pair(1))
|
||||
for line=1,lines do
|
||||
for col=1,cols do
|
||||
window:addstr(utf8(glyph[grid_char_to_glyph_index(grid_char(line, col))]))
|
||||
end
|
||||
end
|
||||
curses.attroff(curses.color_pair(1))
|
||||
curses.refresh()
|
||||
end
|
||||
]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
state = [==[
|
||||
function state(line, col)
|
||||
if line < 1 or line > table.getn(grid) or col < 1 or col > table.getn(grid[1]) then
|
||||
return 0
|
||||
end
|
||||
return grid[line][col]
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
num_live_neighbors = [==[
|
||||
function num_live_neighbors(line, col)
|
||||
return state(line-1, col-1) + state(line-1, col) + state(line-1, col+1) +
|
||||
state(line, col-1) + state(line, col+1) +
|
||||
state(line+1, col-1) + state(line+1, col) + state(line+1, col+1)
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
step = [==[
|
||||
function step()
|
||||
local new_grid = {}
|
||||
for line=1,table.getn(grid) do
|
||||
new_grid[line] = {}
|
||||
for col=1,table.getn(grid[1]) do
|
||||
local n = num_live_neighbors(line, col)
|
||||
if n == 3 then
|
||||
new_grid[line][col] = 1
|
||||
elseif n == 2 then
|
||||
new_grid[line][col] = grid[line][col]
|
||||
else
|
||||
new_grid[line][col] = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
grid = new_grid
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
sleep = [==[
|
||||
function sleep(a)
|
||||
local sec = tonumber(os.clock() + a);
|
||||
while (os.clock() < sec) do
|
||||
end
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
file_exists = [==[
|
||||
function file_exists(filename)
|
||||
local f = io.open(filename, "r")
|
||||
if f ~= nil then
|
||||
io.close(f)
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
load_file = [==[
|
||||
function load_file(window, filename)
|
||||
io.input(filename)
|
||||
local line_index = lines
|
||||
for line in io.lines() do
|
||||
if line:sub(1,1) ~= '!' then -- comment; plaintext files can't have whitespace before comments
|
||||
local col_index = cols
|
||||
for c in line:gmatch(".") do
|
||||
if c == '\r' then break end -- DOS line ending
|
||||
if c == '.' then
|
||||
grid[line_index][col_index] = 0
|
||||
else
|
||||
grid[line_index][col_index] = 1
|
||||
end
|
||||
col_index = col_index+1
|
||||
end
|
||||
line_index = line_index+1
|
||||
end
|
||||
end
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
update = [==[
|
||||
menu = {arrow="pan"}
|
||||
|
||||
function update(window, c)
|
||||
if c == curses.KEY_LEFT then
|
||||
for i=1,lines*4 do
|
||||
for j=2,cols*2 do
|
||||
grid[i][j-1] = grid[i][j]
|
||||
end
|
||||
grid[i][cols*2] = 0
|
||||
end
|
||||
elseif c == curses.KEY_DOWN then
|
||||
for i=lines*4-1,1,-1 do
|
||||
for j=1,cols*2 do
|
||||
grid[i+1][j] = grid[i][j]
|
||||
end
|
||||
end
|
||||
for j=1,cols*2 do
|
||||
grid[1][j] = 0
|
||||
end
|
||||
elseif c == curses.KEY_UP then
|
||||
for i=2,lines*4 do
|
||||
for j=1,cols*2 do
|
||||
grid[i-1][j] = grid[i][j]
|
||||
end
|
||||
end
|
||||
for j=1,cols*2 do
|
||||
grid[lines*4][j] = 0
|
||||
end
|
||||
elseif c == curses.KEY_RIGHT then
|
||||
for i=1,lines*4 do
|
||||
for j=cols*2-1,1,-1 do
|
||||
grid[i][j+1] = grid[i][j]
|
||||
end
|
||||
grid[i][1] = 0
|
||||
end
|
||||
end
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
main = [==[
|
||||
function main()
|
||||
curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
|
||||
curses.init_pair(1, 22, 189)
|
||||
|
||||
-- initialize grid based on commandline args
|
||||
if (#arg == 0) then
|
||||
-- by default, start from a deterministically random state
|
||||
for i=1,lines*4 do
|
||||
for j=1,cols*2 do
|
||||
grid[i][j] = math.random(0, 1)
|
||||
end
|
||||
end
|
||||
elseif arg[1] == "random" then
|
||||
-- start from a non-deterministically random start state
|
||||
math.randomseed(os.time())
|
||||
for i=1,lines*4 do
|
||||
for j=1,cols*2 do
|
||||
grid[i][j] = math.random(0, 1)
|
||||
end
|
||||
end
|
||||
-- shortcuts for some common patterns
|
||||
elseif arg[1] == "pentomino" then
|
||||
-- https://www.conwaylife.com/wiki/Pentomino
|
||||
grid[83][172] = 1
|
||||
grid[83][173] = 1
|
||||
grid[84][173] = 1
|
||||
grid[84][174] = 1
|
||||
grid[85][173] = 1
|
||||
elseif arg[1] == "glider" then
|
||||
-- https://www.conwaylife.com/wiki/Glider
|
||||
grid[5][4] = 1
|
||||
grid[6][5] = 1
|
||||
grid[7][3] = 1
|
||||
grid[7][4] = 1
|
||||
grid[7][5] = 1
|
||||
elseif arg[1] == "blinker" then
|
||||
-- https://www.conwaylife.com/wiki/Blinker
|
||||
grid[7][3] = 1
|
||||
grid[7][4] = 1
|
||||
grid[7][5] = 1
|
||||
elseif arg[1] == "block" then
|
||||
-- https://www.conwaylife.com/wiki/Block
|
||||
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]==],
|
||||
},
|
||||
}
|
||||
# .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
|
||||
# violate Teliva's assumptions.
|
||||
#
|
||||
# .tlv files are representations of Teliva programs. Teliva programs consist of
|
||||
# sequences of definitions. Each definition is a table of key/value pairs. Keys
|
||||
# and values are both strings.
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
# - multiline values indented by more than 2 spaces, starting with a '>'
|
||||
#
|
||||
# If these constraints are violated, Teliva may unceremoniously crash. Please
|
||||
# report bugs at http://akkartik.name/contact
|
||||
- __teliva_timestamp: original
|
||||
grid:
|
||||
>-- main data structure
|
||||
>grid = {}
|
||||
>for i=1,lines*4 do
|
||||
> grid[i] = {}
|
||||
> for j=1,cols*2 do
|
||||
> grid[i][j] = 0
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
window:
|
||||
>window = curses.stdscr()
|
||||
>-- animation-based app
|
||||
>window:nodelay(true)
|
||||
>lines, cols = window:getmaxyx()
|
||||
- __teliva_timestamp: original
|
||||
grid_char:
|
||||
>-- grab a 4x2 chunk of grid
|
||||
>function grid_char(line, col)
|
||||
> result = {}
|
||||
> for l, row in ipairs({unpack(grid, (line-1)*4+1, line*4)}) do
|
||||
> result[l] = {unpack(row, (col-1)*2+1, col*2)}
|
||||
> end
|
||||
> return result
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
print_grid_char:
|
||||
>function print_grid_char(window, x)
|
||||
> result = {}
|
||||
> for l, row in ipairs(x) do
|
||||
> for c, val in ipairs(row) do
|
||||
> window:mvaddstr(l, c, val)
|
||||
> end
|
||||
> end
|
||||
> return result
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
glyph:
|
||||
>-- look up the braille pattern corresponding to a 4x2 chunk of grid
|
||||
>-- https://en.wikipedia.org/wiki/Braille_Patterns
|
||||
>-- not obviously programmatic because Unicode added 4x2 after 3x2
|
||||
>glyph = {
|
||||
> 0x2800, 0x2801, 0x2802, 0x2803, 0x2804, 0x2805, 0x2806, 0x2807, 0x2840, 0x2841, 0x2842, 0x2843, 0x2844, 0x2845, 0x2846, 0x2847,
|
||||
> 0x2808, 0x2809, 0x280a, 0x280b, 0x280c, 0x280d, 0x280e, 0x280f, 0x2848, 0x2849, 0x284a, 0x284b, 0x284c, 0x284d, 0x284e, 0x284f,
|
||||
> 0x2810, 0x2811, 0x2812, 0x2813, 0x2814, 0x2815, 0x2816, 0x2817, 0x2850, 0x2851, 0x2852, 0x2853, 0x2854, 0x2855, 0x2856, 0x2857,
|
||||
> 0x2818, 0x2819, 0x281a, 0x281b, 0x281c, 0x281d, 0x281e, 0x281f, 0x2858, 0x2859, 0x285a, 0x285b, 0x285c, 0x285d, 0x285e, 0x285f,
|
||||
> 0x2820, 0x2821, 0x2822, 0x2823, 0x2824, 0x2825, 0x2826, 0x2827, 0x2860, 0x2861, 0x2862, 0x2863, 0x2864, 0x2865, 0x2866, 0x2867,
|
||||
> 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,
|
||||
> 0x2838, 0x2839, 0x283a, 0x283b, 0x283c, 0x283d, 0x283e, 0x283f, 0x2878, 0x2879, 0x287a, 0x287b, 0x287c, 0x287d, 0x287e, 0x287f,
|
||||
>
|
||||
> 0x2880, 0x2881, 0x2882, 0x2883, 0x2884, 0x2885, 0x2886, 0x2887, 0x28c0, 0x28c1, 0x28c2, 0x28c3, 0x28c4, 0x28c5, 0x28c6, 0x28c7,
|
||||
> 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,
|
||||
> 0x2898, 0x2899, 0x289a, 0x289b, 0x289c, 0x289d, 0x289e, 0x289f, 0x28d8, 0x28d9, 0x28da, 0x28db, 0x28dc, 0x28dd, 0x28de, 0x28df,
|
||||
> 0x28a0, 0x28a1, 0x28a2, 0x28a3, 0x28a4, 0x28a5, 0x28a6, 0x28a7, 0x28e0, 0x28e1, 0x28e2, 0x28e3, 0x28e4, 0x28e5, 0x28e6, 0x28e7,
|
||||
> 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: original
|
||||
utf8:
|
||||
>-- https://stackoverflow.com/questions/7983574/how-to-write-a-unicode-symbol-in-lua
|
||||
>function utf8(decimal)
|
||||
> local bytemarkers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} }
|
||||
> if decimal<128 then return string.char(decimal) end
|
||||
> local charbytes = {}
|
||||
> for bytes,vals in ipairs(bytemarkers) do
|
||||
> if decimal<=vals[1] then
|
||||
> for b=bytes+1,2,-1 do
|
||||
> local mod = decimal%64
|
||||
> decimal = (decimal-mod)/64
|
||||
> charbytes[b] = string.char(128+mod)
|
||||
> end
|
||||
> charbytes[1] = string.char(vals[2]+decimal)
|
||||
> break
|
||||
> end
|
||||
> end
|
||||
> return table.concat(charbytes)
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
grid_char_to_glyph_index:
|
||||
>-- convert a chunk of grid into a number
|
||||
>function grid_char_to_glyph_index(g)
|
||||
> return g[1][1] + g[2][1]*2 + g[3][1]*4 + g[4][1]*8 +
|
||||
> g[1][2]*16 + g[2][2]*32 + g[3][2]*64 + g[4][2]*128 +
|
||||
> 1 -- 1-indexing
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
render:
|
||||
>function render(window)
|
||||
> window:clear()
|
||||
> curses.attron(curses.color_pair(1))
|
||||
> for line=1,lines do
|
||||
> for col=1,cols do
|
||||
> window:addstr(utf8(glyph[grid_char_to_glyph_index(grid_char(line, col))]))
|
||||
> end
|
||||
> end
|
||||
> curses.attroff(curses.color_pair(1))
|
||||
> curses.refresh()
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
state:
|
||||
>function state(line, col)
|
||||
> if line < 1 or line > table.getn(grid) or col < 1 or col > table.getn(grid[1]) then
|
||||
> return 0
|
||||
> end
|
||||
> return grid[line][col]
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
num_live_neighbors:
|
||||
>function num_live_neighbors(line, col)
|
||||
> return state(line-1, col-1) + state(line-1, col) + state(line-1, col+1) +
|
||||
> state(line, col-1) + state(line, col+1) +
|
||||
> state(line+1, col-1) + state(line+1, col) + state(line+1, col+1)
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
step:
|
||||
>function step()
|
||||
> local new_grid = {}
|
||||
> for line=1,table.getn(grid) do
|
||||
> new_grid[line] = {}
|
||||
> for col=1,table.getn(grid[1]) do
|
||||
> local n = num_live_neighbors(line, col)
|
||||
> if n == 3 then
|
||||
> new_grid[line][col] = 1
|
||||
> elseif n == 2 then
|
||||
> new_grid[line][col] = grid[line][col]
|
||||
> else
|
||||
> new_grid[line][col] = 0
|
||||
> end
|
||||
> end
|
||||
> end
|
||||
> grid = new_grid
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
sleep:
|
||||
>function sleep(a)
|
||||
> local sec = tonumber(os.clock() + a);
|
||||
> while (os.clock() < sec) do
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
file_exists:
|
||||
>function file_exists(filename)
|
||||
> local f = io.open(filename, "r")
|
||||
> if f ~= nil then
|
||||
> io.close(f)
|
||||
> return true
|
||||
> else
|
||||
> return false
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
load_file:
|
||||
>function load_file(window, filename)
|
||||
> io.input(filename)
|
||||
> local line_index = lines
|
||||
> for line in io.lines() do
|
||||
> if line:sub(1,1) ~= '!' then -- comment; plaintext files can't have whitespace before comments
|
||||
> local col_index = cols
|
||||
> for c in line:gmatch(".") do
|
||||
> if c == '\r' then break end -- DOS line ending
|
||||
> if c == '.' then
|
||||
> grid[line_index][col_index] = 0
|
||||
> else
|
||||
> grid[line_index][col_index] = 1
|
||||
> end
|
||||
> col_index = col_index+1
|
||||
> end
|
||||
> line_index = line_index+1
|
||||
> end
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
update:
|
||||
>menu = {arrow="pan"}
|
||||
>
|
||||
>function update(window, c)
|
||||
> if c == curses.KEY_LEFT then
|
||||
> for i=1,lines*4 do
|
||||
> for j=2,cols*2 do
|
||||
> grid[i][j-1] = grid[i][j]
|
||||
> end
|
||||
> grid[i][cols*2] = 0
|
||||
> end
|
||||
> elseif c == curses.KEY_DOWN then
|
||||
> for i=lines*4-1,1,-1 do
|
||||
> for j=1,cols*2 do
|
||||
> grid[i+1][j] = grid[i][j]
|
||||
> end
|
||||
> end
|
||||
> for j=1,cols*2 do
|
||||
> grid[1][j] = 0
|
||||
> end
|
||||
> elseif c == curses.KEY_UP then
|
||||
> for i=2,lines*4 do
|
||||
> for j=1,cols*2 do
|
||||
> grid[i-1][j] = grid[i][j]
|
||||
> end
|
||||
> end
|
||||
> for j=1,cols*2 do
|
||||
> grid[lines*4][j] = 0
|
||||
> end
|
||||
> elseif c == curses.KEY_RIGHT then
|
||||
> for i=1,lines*4 do
|
||||
> for j=cols*2-1,1,-1 do
|
||||
> grid[i][j+1] = grid[i][j]
|
||||
> end
|
||||
> grid[i][1] = 0
|
||||
> end
|
||||
> end
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
main:
|
||||
>function main()
|
||||
> curses.init_pair(255, 15, 1) -- reserved for Teliva error messages
|
||||
> curses.init_pair(1, 22, 189)
|
||||
>
|
||||
> -- initialize grid based on commandline args
|
||||
> if (#arg == 0) then
|
||||
> -- by default, start from a deterministically random state
|
||||
> for i=1,lines*4 do
|
||||
> for j=1,cols*2 do
|
||||
> grid[i][j] = math.random(0, 1)
|
||||
> end
|
||||
> end
|
||||
> elseif arg[1] == "random" then
|
||||
> -- start from a non-deterministically random start state
|
||||
> math.randomseed(os.time())
|
||||
> for i=1,lines*4 do
|
||||
> for j=1,cols*2 do
|
||||
> grid[i][j] = math.random(0, 1)
|
||||
> end
|
||||
> end
|
||||
> -- shortcuts for some common patterns
|
||||
> elseif arg[1] == "pentomino" then
|
||||
> -- https://www.conwaylife.com/wiki/Pentomino
|
||||
> grid[83][172] = 1
|
||||
> grid[83][173] = 1
|
||||
> grid[84][173] = 1
|
||||
> grid[84][174] = 1
|
||||
> grid[85][173] = 1
|
||||
> elseif arg[1] == "glider" then
|
||||
> -- https://www.conwaylife.com/wiki/Glider
|
||||
> grid[5][4] = 1
|
||||
> grid[6][5] = 1
|
||||
> grid[7][3] = 1
|
||||
> grid[7][4] = 1
|
||||
> grid[7][5] = 1
|
||||
> elseif arg[1] == "blinker" then
|
||||
> -- https://www.conwaylife.com/wiki/Blinker
|
||||
> grid[7][3] = 1
|
||||
> grid[7][4] = 1
|
||||
> grid[7][5] = 1
|
||||
> elseif arg[1] == "block" then
|
||||
> -- https://www.conwaylife.com/wiki/Block
|
||||
> 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
|
||||
|
|
|
@ -89,7 +89,9 @@ static void teliva_load_definition(lua_State* L, FILE* in) {
|
|||
strcpy(line, "-\n");
|
||||
}
|
||||
else {
|
||||
assert(fgets(line, 1024, in));
|
||||
memset(line, '\0', 1024);
|
||||
//? printf("%d\n", feof(in));
|
||||
fgets(line, 1024, in);
|
||||
//? printf("new line: %s", line);
|
||||
}
|
||||
}
|
||||
|
|
43
src/x.tlv
43
src/x.tlv
|
@ -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
|
141
template.tlv
141
template.tlv
|
@ -1,72 +1,69 @@
|
|||
teliva_program = {
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
window = [==[
|
||||
window = curses.stdscr()]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
render = [==[
|
||||
function render(window)
|
||||
window:clear()
|
||||
-- draw stuff to screen here
|
||||
window:attron(curses.A_BOLD)
|
||||
window:mvaddstr(1, 5, "example app")
|
||||
window:attrset(curses.A_NORMAL)
|
||||
for i=0,15 do
|
||||
window:attrset(curses.color_pair(i))
|
||||
window:mvaddstr(3+i, 5, "========================")
|
||||
end
|
||||
curses.refresh()
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
menu = [==[
|
||||
menu = {}]==],
|
||||
},
|
||||
{
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
update = [==[
|
||||
function update(window)
|
||||
local key = curses.getch()
|
||||
-- process key here
|
||||
end]==],
|
||||
},
|
||||
{
|
||||
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)
|
||||
end]==],
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
},
|
||||
{
|
||||
main = [==[
|
||||
function main()
|
||||
init_colors()
|
||||
|
||||
while true do
|
||||
render(window)
|
||||
update(window)
|
||||
end
|
||||
end
|
||||
]==],
|
||||
__teliva_timestamp = [==[
|
||||
original]==],
|
||||
},
|
||||
}
|
||||
# .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
|
||||
# violate Teliva's assumptions.
|
||||
#
|
||||
# .tlv files are representations of Teliva programs. Teliva programs consist of
|
||||
# sequences of definitions. Each definition is a table of key/value pairs. Keys
|
||||
# and values are both strings.
|
||||
#
|
||||
# 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
|
||||
# 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
|
||||
# - multiline values indented by more than 2 spaces, starting with a '>'
|
||||
#
|
||||
# If these constraints are violated, Teliva may unceremoniously crash. Please
|
||||
# report bugs at http://akkartik.name/contact
|
||||
- __teliva_timestamp: original
|
||||
window:
|
||||
>window = curses.stdscr()
|
||||
- __teliva_timestamp: original
|
||||
render:
|
||||
>function render(window)
|
||||
> window:clear()
|
||||
> -- draw stuff to screen here
|
||||
> window:attron(curses.A_BOLD)
|
||||
> window:mvaddstr(1, 5, "example app")
|
||||
> window:attrset(curses.A_NORMAL)
|
||||
> for i=0,15 do
|
||||
> window:attrset(curses.color_pair(i))
|
||||
> window:mvaddstr(3+i, 5, "========================")
|
||||
> end
|
||||
> curses.refresh()
|
||||
>end
|
||||
- __teliva_timestamp: original
|
||||
menu:
|
||||
>menu = {}
|
||||
- __teliva_timestamp: original
|
||||
update:
|
||||
>function update(window)
|
||||
> local key = curses.getch()
|
||||
> -- process key here
|
||||
>end
|
||||
- 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)
|
||||
>end
|
||||
__teliva_timestamp: original
|
||||
- main:
|
||||
>function main()
|
||||
> init_colors()
|
||||
>
|
||||
> while true do
|
||||
> render(window)
|
||||
> update(window)
|
||||
> end
|
||||
>end
|
||||
__teliva_timestamp: original
|
||||
|
|
Loading…
Reference in New Issue