sourceextensions/web/demos/life.xtl

1⍝# A live page: Conway's Life kept by an X_eTaL program and drawn as SVG, 2⍝# one generation per request. The program is the server's request loop. 3⍝# Run: just demo web life, then open http://127.0.0.1:8470/ 4⍝# (New board, Glider; Quit ends the program) 5 6ʷᵇ⁼u̲se< "Web" 7 8⍝# Life (as in X_eTaL's demos/life.xtl): every cell plus its neighbors 9⍝# by rotating along both axes and summing; alive next at 3, or 4 if alive 10ᵘl̲ife ← { ('+ r̲/₁₂ -1 0 1 o̲-₁₂ ⍵) { (⍺ = 3) + ⍵ × ⍺ = 4 } ⍵ } 11 12⍝# an n by n board, about one cell in four alive; or one glider 13ᵘs̲eed ← { n → (n c̲at n) r̲eshape 1 = r̲oll! (n × n) r̲eshape 4 } 14⍝# (n * n - 3 is n times n - 3: the rows below the glider) 15ᵘ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 } 16 17⍝# the size a request asks for (?n=), 8 to 200, else 48 18ᵘs̲ize ← { s → 19 0 = t̲ally s ? 48 20 8 m̲ax 200 m̲in f̲loor f̲irst n̲umbers s 21} 22 23⍝# the board as SVG: one unit square per live cell ("M col row h1v1h-1z") 24⍝# boxed strings joined into one (from "", so no live cells is "") 25ᵘj̲oin ← { s → d̲isclose '{ e̲nclose (d̲isclose ⍺) c̲at d̲isclose ⍵ } r̲/ (e̲nclose "") c̲at s } 26ᵘs̲vg ← { b → 27 n ← t̲ally b 28 w ← f̲ormat n 29 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 30 "<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>" 31} 32 33⍝# the page: the board, refreshed several times a second 34page ← "<!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>" 35 36⍝# one request: the board after answering it (an empty board: quit); 37⍝# x r_ight y is y, so a reply is sent and the board passed on 38ᵘa̲nswer ← { b → 39 0 = t̲ally b ? b 40 r ← ʷᵇn̲ext! 60 41 r m̲atch "none" ? b 42 r m̲atch "GET /" ? (200 ʷᵇr̲eply! page) r̲ight b 43 r m̲atch "GET /life.svg" ? (200 ʷᵇr̲eply! ᵘs̲vg b) r̲ight ᵘl̲ife b 44 r m̲atch "GET /new" ? (200 ʷᵇr̲eply! "a new board") r̲ight ᵘs̲eed ᵘs̲ize ʷᵇp̲aram "n" 45 r m̲atch "GET /glider" ? (200 ʷᵇr̲eply! "a glider") r̲ight ᵘg̲lider ᵘs̲ize ʷᵇp̲aram "n" 46 r m̲atch "GET /quit" ? (200 ʷᵇr̲eply! "bye") r̲ight 0 0 r̲eshape 0 47 (404 ʷᵇr̲eply! "no such page: " c̲at ʷᵇp̲ath @) r̲ight b 48} 49 50port ← ʷᵇs̲erve! 8470 51"serving http://127.0.0.1:" c̲at f̲ormat port 52last ← 100000 'ᵘa̲nswer p̲ower ᵘs̲eed 48 53port ← ʷᵇs̲top! @ 54"bye"