programextensions/web/demos/life.xtl
A live page: Conway's Life kept by an X_eTaL program and drawn as SVG, one generation per request. The program is the server's request loop. Run: just demo web life, then open http://127.0.0.1:8470/ (New board, Glider; Quit ends the program)
ᵘl̲ife : (Num a, Truthy a) => a -> a
Life (as in X_eTaL's demos/life.xtl): every cell plus its neighbors by rotating along both axes and summing; alive next at 3, or 4 if alive
ᵘl̲ife ← { ('+ r̲/₁₂ -1 0 1 o̲-₁₂ ⍵) { (⍺ = 3) + ⍵ × ⍺ = 4 } ⍵ }
ᵘs̲eed : Truthy a => Int -> a
an n by n board, about one cell in four alive; or one glider
ᵘs̲eed ← { n → (n c̲at n) r̲eshape 1 = r̲oll! (n × n) r̲eshape 4 }
ᵘg̲lider : Num a => Int -> a
(n * n - 3 is n times n - 3: the rows below the glider)
ᵘg̲lider ← { n → (n c̲at n) r̲eshape (n t̲ake 0 1 0) c̲at (n t̲ake 0 0 1) c̲at (n t̲ake 1 1 1) c̲at (n × n − 3) r̲eshape 0 }
ᵘs̲ize : Char -> Int
the size a request asks for (?n=), 8 to 200, else 48
ᵘs̲ize ← { s → 0 = t̲ally s ? 48 8 m̲ax 200 m̲in f̲loor f̲irst n̲umbers s }
ᵘj̲oin : Box Char -> Char
the board as SVG: one unit square per live cell ("M col row h1v1h-1z") boxed strings joined into one (from "", so no live cells is "")
ᵘj̲oin ← { s → d̲isclose '{ e̲nclose (d̲isclose ⍺) c̲at d̲isclose ⍵ } r̲/ (e̲nclose "") c̲at s }
ᵘs̲vg : Truthy a => a -> Char
ᵘs̲vg ← { b → n ← t̲ally b w ← f̲ormat n d ← ᵘj̲oin '{ "M" c̲at (f̲ormat ⍵ m̲od n) c̲at " " c̲at (f̲ormat ⍵ d̲iv n) c̲at "h1v1h-1z" } m̲ap (w̲here r̲avel b) − 1 "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 " c̲at w c̲at " " c̲at w c̲at "' shape-rendering='crispEdges'><rect width='" c̲at w c̲at "' height='" c̲at w c̲at "' fill='#14161a'/><path fill='#e8483b' d='" c̲at d c̲at "'/></svg>" }
page : Char
the page: the board, refreshed several times a second
page ← "<!doctype html><html><head><meta charset='utf-8'><title>Life -- X_eTaL on the web</title><style>body{background:#0d0e10;color:#ddd;font-family:system-ui,sans-serif;text-align:center}img{width:min(90vw,600px);image-rendering:pixelated;border:1px solid #333}button{margin:.5em;padding:.4em 1em}</style></head><body><h1>Life, computed in X_eTaL</h1><p>Each frame is one request: the X_eTaL program steps the board and replies with SVG.</p><img id='b' src='/life.svg' alt='the board'><div><button onclick=nw()>New board</button><button onclick=gl()>Glider</button><button onclick=qt()>Quit</button></div><script>let on=true;function nw(){fetch('/new')}function gl(){fetch('/glider')}function qt(){on=false;fetch('/quit')}setInterval(()=>{if(on){document.getElementById('b').src='/life.svg?'+Date.now()}},150)</script></body></html>"
ᵘa̲nswer : (Num a, Truthy a) => a -> a
one request: the board after answering it (an empty board: quit); x r_ight y is y, so a reply is sent and the board passed on
ᵘa̲nswer ← { b → 0 = t̲ally b ? b r ← ʷᵇn̲ext! 60 r m̲atch "none" ? b r m̲atch "GET /" ? (200 ʷᵇr̲eply! page) r̲ight b r m̲atch "GET /life.svg" ? (200 ʷᵇr̲eply! ᵘs̲vg b) r̲ight ᵘl̲ife b r m̲atch "GET /new" ? (200 ʷᵇr̲eply! "a new board") r̲ight ᵘs̲eed ᵘs̲ize ʷᵇp̲aram "n" r m̲atch "GET /glider" ? (200 ʷᵇr̲eply! "a glider") r̲ight ᵘg̲lider ᵘs̲ize ʷᵇp̲aram "n" r m̲atch "GET /quit" ? (200 ʷᵇr̲eply! "bye") r̲ight 0 0 r̲eshape 0 (404 ʷᵇr̲eply! "no such page: " c̲at ʷᵇp̲ath @) r̲ight b }