@trolleroof/tui 0.2.5 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/.claude-plugin/plugin.json +10 -0
  2. package/.codex-plugin/plugin.json +2 -2
  3. package/README.md +29 -7
  4. package/dist/index.js +284 -18
  5. package/overlay/dist/app.js +74 -0
  6. package/overlay/dist/index.html +1589 -0
  7. package/overlay-release.json +2 -2
  8. package/package.json +27 -4
  9. package/scripts/install-adapters.sh +6 -6
  10. package/scripts/install-adapters.test.sh +2 -2
  11. package/scripts/materialize-agents-plugin.sh +3 -3
  12. package/scripts/npm-pack.test.ts +51 -0
  13. package/scripts/overlay.ts +1 -1
  14. package/src/analytics/events.test.ts +77 -0
  15. package/src/analytics/events.ts +85 -0
  16. package/src/analytics/posthog.test.ts +85 -0
  17. package/src/analytics/posthog.ts +88 -0
  18. package/src/auth-pages.ts +108 -0
  19. package/src/auth.test.ts +255 -0
  20. package/src/auth.ts +511 -0
  21. package/src/core/game.ts +35 -0
  22. package/src/core/key.ts +12 -0
  23. package/src/core/rng.ts +41 -0
  24. package/src/data/bc-export.test.ts +153 -0
  25. package/src/data/bc-export.ts +125 -0
  26. package/src/data/trajectory.ts +103 -0
  27. package/src/games/connect4/connect4.ts +81 -0
  28. package/src/games/connect4/engine.test.ts +77 -0
  29. package/src/games/connect4/engine.ts +89 -0
  30. package/src/games/g2048/engine.test.ts +138 -0
  31. package/src/games/g2048/engine.ts +109 -0
  32. package/src/games/g2048/game2048.ts +104 -0
  33. package/src/games/minesweeper/engine.test.ts +83 -0
  34. package/src/games/minesweeper/engine.ts +112 -0
  35. package/src/games/minesweeper/minesweeper.ts +107 -0
  36. package/src/games/registry.test.ts +16 -0
  37. package/src/games/registry.ts +130 -0
  38. package/src/games/snake/engine.test.ts +89 -0
  39. package/src/games/snake/engine.ts +95 -0
  40. package/src/games/snake/snake.ts +77 -0
  41. package/src/games/sokoban/engine.test.ts +49 -0
  42. package/src/games/sokoban/engine.ts +152 -0
  43. package/src/games/sokoban/sokoban.ts +103 -0
  44. package/src/games/sudoku/engine.test.ts +88 -0
  45. package/src/games/sudoku/engine.ts +99 -0
  46. package/src/games/sudoku/sudoku.ts +100 -0
  47. package/src/games/tetris/engine.test.ts +378 -0
  48. package/src/games/tetris/engine.ts +236 -0
  49. package/src/games/tetris/tetris.ts +220 -0
  50. package/src/index.ts +82 -0
  51. package/src/recording/chunks.ts +93 -0
  52. package/src/recording/config.test.ts +31 -0
  53. package/src/recording/config.ts +37 -0
  54. package/src/recording/contracts.test.ts +71 -0
  55. package/src/recording/gameplay.test.ts +70 -0
  56. package/src/recording/gameplay.ts +18 -0
  57. package/src/recording/http-transport.test.ts +197 -0
  58. package/src/recording/identity.test.ts +26 -0
  59. package/src/recording/identity.ts +38 -0
  60. package/src/recording/ids.ts +27 -0
  61. package/src/recording/permissions.ts +10 -0
  62. package/src/recording/recorder.test.ts +388 -0
  63. package/src/recording/recorder.ts +464 -0
  64. package/src/recording/store.test.ts +231 -0
  65. package/src/recording/store.ts +305 -0
  66. package/src/recording/terminal-grid.test.ts +88 -0
  67. package/src/recording/terminal-grid.ts +248 -0
  68. package/src/recording/trace-recorder.test.ts +287 -0
  69. package/src/recording/trace-recorder.ts +560 -0
  70. package/src/recording/transport.ts +170 -0
  71. package/src/recording/types.test.ts +18 -0
  72. package/src/recording/types.ts +326 -0
  73. package/src/recording/uploader.test.ts +193 -0
  74. package/src/recording/uploader.ts +103 -0
  75. package/src/results/completion.ts +100 -0
  76. package/src/results/http-result-transport.test.ts +75 -0
  77. package/src/results/local-score.test.ts +32 -0
  78. package/src/results/local-score.ts +39 -0
  79. package/src/results/results.test.ts +383 -0
  80. package/src/results/store.ts +149 -0
  81. package/src/results/transport.ts +79 -0
  82. package/src/results/types.ts +20 -0
  83. package/src/results/uploader.ts +84 -0
  84. package/src/sync/config.test.ts +108 -0
  85. package/src/sync/config.ts +115 -0
  86. package/src/sync/coordinator.test.ts +423 -0
  87. package/src/sync/coordinator.ts +277 -0
  88. package/src/sync/game-start-queue.test.ts +93 -0
  89. package/src/sync/game-start-queue.ts +45 -0
  90. package/src/sync/identity-client.test.ts +34 -0
  91. package/src/sync/identity-client.ts +43 -0
@@ -0,0 +1,74 @@
1
+ class B{s;static assertState($){if(!Number.isSafeInteger($)||$<0||$>4294967295)throw RangeError("RNG state must be an unsigned 32-bit integer")}constructor($){this.s=$>>>0}static fromState($){return B.assertState($),new B($)}exportState(){return this.s}next(){this.s=this.s+1831565813>>>0;let $=this.s;return $=Math.imul($^$>>>15,$|1),$^=$+Math.imul($^$>>>7,$|61),(($^$>>>14)>>>0)/4294967296}int($){return Math.floor(this.next()*$)}}var f2=7;function _4(){return Array.from({length:6},()=>Array(7).fill(0))}function b4($){let Q=[];for(let J=0;J<7;J++)if($[0][J]===0)Q.push(J);return Q}function I0($,Q,J){for(let q=5;q>=0;q--)if($[q][Q]===0)return $[q][Q]=J,q;return-1}var P6=[[1,0],[0,1],[1,1],[1,-1]];function t0($){for(let Q=0;Q<6;Q++)for(let J=0;J<7;J++){let q=$[Q][J];if(q===0)continue;for(let[X,H]of P6){let V=1;while(V<4&&$[Q+H*V]?.[J+X*V]===q)V++;if(V===4)return q}}return 0}function T4($){return b4($).length===0}function h4($,Q,J){let q=I0($,Q,J);if(q<0)return!1;let X=t0($)===J;return $[q][Q]=0,X}function I2($,Q){let J=b4($);for(let W of J)if(h4($,W,2))return W;for(let W of J)if(h4($,W,1))return W;let q=J.filter((W)=>{let U=I0($,W,2),Z=b4($).some((N)=>h4($,N,1));return $[U][W]=0,!Z}),X=q.length>0?q:J,H=(W)=>4-Math.abs(3-W),V=Math.max(...X.map(H)),Y=X.filter((W)=>H(W)===V);return Y[Q.int(Y.length)]}class w4{name="connect4";actions=["left","right","drop","bot_move"];keymap={space:"drop",enter:"drop",down:"drop"};rng=new B(0);board=_4();cursor=3;result=0;reset($){this.rng=new B($),this.board=_4(),this.cursor=3,this.result=0}step($){if(this.result!==0)return{reward:0,moved:!1,done:!0,success:this.result===1};if($==="left"||$==="right"){let Q=this.cursor+($==="left"?-1:1);if(Q<0||Q>=f2)return{reward:0,moved:!1,done:!1,success:!1};return this.cursor=Q,{reward:0,moved:!0,done:!1,success:!1}}if($==="bot_move"){let Q=I2(this.board,this.rng);I0(this.board,Q,2);let J={kind:"bot_move",column:Q};if(t0(this.board)===2)return this.result=2,{reward:0,moved:!0,done:!0,success:!1,randomEffects:J};if(T4(this.board))return this.result=3,{reward:50,moved:!0,done:!0,success:!1,randomEffects:J};return{reward:0,moved:!0,done:!1,success:!1,randomEffects:J}}if(I0(this.board,this.cursor,1)<0)return{reward:0,moved:!1,done:!1,success:!1};if(t0(this.board)===1)return this.result=1,{reward:100,moved:!0,done:!0,success:!0};if(T4(this.board))return this.result=3,{reward:50,moved:!0,done:!0,success:!1};return{reward:1,moved:!0,done:!1,success:!1}}state(){return{board:this.board.map(($)=>[...$]),cursor:this.cursor,result:this.result}}score(){return this.result===1?100:this.result===3?50:0}isOver(){return this.result!==0}hasWon(){return this.result===1}}var E=4,k2=2048;function S4(){return Array.from({length:E},()=>Array(E).fill(0))}function x2($){return $.map((Q)=>[...Q])}function E2($){let Q=[];for(let J=0;J<E;J++)for(let q=0;q<E;q++)if($[J][q]===0)Q.push([J,q]);return Q}function $4($,Q,J=0.1){let q=E2($);if(q.length===0)return $;let[X,H]=q[Q.int(q.length)],V=x2($);return V[X][H]=Q.next()<1-J?2:4,V}function h6($){let Q=$.filter((X)=>X!==0),J=[],q=0;for(let X=0;X<Q.length;X++)if(X+1<Q.length&&Q[X]===Q[X+1]){let H=Q[X]*2;J.push(H),q+=H,X++}else J.push(Q[X]);while(J.length<E)J.push(0);return{row:J,gained:q}}function a0($){return $[0].map((Q,J)=>$.map((q)=>q[J]))}function e0($){return $.map((Q)=>[...Q].reverse())}function u2($,Q){let J=x2($);if(Q==="up")J=a0(J);else if(Q==="down")J=e0(a0(J));else if(Q==="right")J=e0(J);let q=0;if(J=J.map((H)=>{let V=h6(H);return q+=V.gained,V.row}),Q==="up")J=a0(J);else if(Q==="down")J=a0(e0(J));else if(Q==="right")J=e0(J);let X=J.some((H,V)=>H.some((Y,W)=>Y!==$[V][W]));return{board:J,gained:q,moved:X}}function f4($){return Math.max(...$.flat())}function y2($){if(E2($).length>0)return!0;for(let Q=0;Q<E;Q++)for(let J=0;J<E;J++){let q=$[Q][J];if(Q+1<E&&$[Q+1][J]===q)return!0;if(J+1<E&&$[Q][J+1]===q)return!0}return!1}class Z0{static VARIATIONS=[{id:"classic",title:"Standard",description:"Standard 2048 rules.",goal:"Reach 2048"},{id:"rush",title:"Rush",description:"Reach 512 before the board fills.",goal:"Reach 512"},{id:"chaos",title:"Chaos",description:"More 4 tiles, faster-changing boards.",goal:"Reach 1024"}];name="2048";actions=["up","down","left","right"];variation;board=S4();points=0;rng=new B(0);won=!1;over=!1;winTile;fourChance=0.1;constructor($="classic"){this.variation=Z0.VARIATIONS.find(({id:Q})=>Q===$)??Z0.VARIATIONS[0],this.winTile=this.variation.id==="rush"?512:this.variation.id==="chaos"?1024:k2,this.fourChance=this.variation.id==="chaos"?0.35:0.1}reset($){this.rng=new B($),this.fourChance=this.variation.id==="chaos"?0.2+new B($).next()*0.3:0.1,this.points=0,this.won=!1,this.over=!1,this.board=$4($4(S4(),this.rng,this.fourChance),this.rng,this.fourChance)}step($){if(this.over)return{reward:0,moved:!1,done:!0,success:this.won};let Q=u2(this.board,$);if(!Q.moved)return{reward:0,moved:!1,done:!1,success:this.won};this.board=$4(Q.board,this.rng,this.fourChance);let J;for(let q=0;q<this.board.length;q++)for(let X=0;X<this.board[q].length;X++)if(Q.board[q][X]===0&&this.board[q][X]!==0)J={kind:"tile_spawned",x:X,y:q,value:this.board[q][X]};if(this.points+=Q.gained,!this.won&&f4(this.board)>=this.winTile)this.won=!0;if(!y2(this.board))this.over=!0;return{reward:Q.gained,moved:!0,done:this.over,success:this.won,...J?{randomEffects:J}:{}}}state(){return{board:this.board.map(($)=>[...$]),score:this.points,highest:f4(this.board)}}score(){return this.points}isOver(){return this.over}hasWon(){return this.won}}var Q4=9,J4=9,q4=10;function k4(){return{cells:Array.from({length:9},()=>Array.from({length:9},()=>({mine:!1,revealed:!1,flagged:!1,adjacent:0}))),minesPlaced:!1,exploded:!1}}function I4($,Q){let J=[];for(let q=-1;q<=1;q++)for(let X=-1;X<=1;X++){if(X===0&&q===0)continue;let H=$+X,V=Q+q;if(H>=0&&V>=0&&H<9&&V<9)J.push([H,V])}return J}function b6($,Q,J,q){let X=new Set([`${Q},${J}`,...I4(Q,J).map(([V,Y])=>`${V},${Y}`)]),H=[];for(let V=0;V<9;V++)for(let Y=0;Y<9;Y++)if(!X.has(`${Y},${V}`))H.push([Y,V]);for(let V=0;V<10;V++){let Y=q.int(H.length),[W,U]=H.splice(Y,1)[0];$.cells[U][W].mine=!0}for(let V=0;V<9;V++)for(let Y=0;Y<9;Y++)$.cells[V][Y].adjacent=I4(Y,V).filter(([W,U])=>$.cells[U][W].mine).length;$.minesPlaced=!0}function p2($,Q,J,q){let X=$.cells[J]?.[Q];if(!X||X.revealed||X.flagged||$.exploded)return 0;if(!$.minesPlaced)b6($,Q,J,q);if(X.mine)return $.exploded=!0,X.revealed=!0,-1;let H=0,V=[[Q,J]];while(V.length>0){let[Y,W]=V.pop(),U=$.cells[W][Y];if(U.revealed||U.flagged||U.mine)continue;if(U.revealed=!0,H++,U.adjacent===0)V.push(...I4(Y,W))}return H}function m2($,Q,J){let q=$.cells[J]?.[Q];if(!q||q.revealed||$.exploded)return!1;return q.flagged=!q.flagged,!0}function X4($){return $.cells.flat().filter((Q)=>Q.revealed&&!Q.mine).length}function g2($){return!$.exploded&&X4($)===71}class x4{name="minesweeper";actions=["up","down","left","right","reveal","flag"];keymap={space:"reveal",enter:"reveal",f:"flag"};rng=new B(0);field=k4();cx=Math.floor(Q4/2);cy=Math.floor(J4/2);cleared=!1;reset($){this.rng=new B($),this.field=k4(),this.cx=Math.floor(Q4/2),this.cy=Math.floor(J4/2),this.cleared=!1}step($){if(this.isOver())return{reward:0,moved:!1,done:!0,success:this.cleared};if($==="up"||$==="down"||$==="left"||$==="right"){let X=this.cx+($==="left"?-1:$==="right"?1:0),H=this.cy+($==="up"?-1:$==="down"?1:0);if(X<0||H<0||X>=Q4||H>=J4)return{reward:0,moved:!1,done:!1,success:!1};return this.cx=X,this.cy=H,{reward:0,moved:!0,done:!1,success:!1}}if($==="flag")return{reward:0,moved:m2(this.field,this.cx,this.cy),done:!1,success:!1};let Q=!this.field.minesPlaced,J=p2(this.field,this.cx,this.cy,this.rng),q=Q?{kind:"mine_layout",positions:this.field.cells.flatMap((X,H)=>X.flatMap((V,Y)=>V.mine?[{x:Y,y:H}]:[]))}:void 0;if(J===0)return{reward:0,moved:!1,done:!1,success:!1};if(J<0)return{reward:0,moved:!0,done:!0,success:!1,randomEffects:q};return this.cleared=g2(this.field),{reward:J,moved:!0,done:this.cleared,success:this.cleared,randomEffects:q}}state(){return{view:this.field.cells.map((Q)=>Q.map((J)=>{if(J.revealed)return J.mine?-3:J.adjacent;if(J.flagged)return-2;return-1})),cursor:{x:this.cx,y:this.cy},revealed:X4(this.field),exploded:this.field.exploded}}checkpointState(){return{...this.state(),mines:this.field.cells.flatMap(($,Q)=>$.flatMap((J,q)=>J.mine?[{x:q,y:Q}]:[]))}}score(){return X4(this.field)}isOver(){return this.field.exploded||this.cleared}hasWon(){return this.cleared}}var v2=25,_6={up:{x:0,y:-1},down:{x:0,y:1},left:{x:-1,y:0},right:{x:1,y:0}};function E4($){return $==="up"?"down":$==="down"?"up":$==="left"?"right":"left"}function u4($){let Q=Math.floor(6.5),J=Math.floor(10),X={width:20,height:13,snake:[{x:J,y:Q},{x:J-1,y:Q},{x:J-2,y:Q}],dir:"right",food:{x:0,y:0},score:0,alive:!0};return X.food=d2(X,$),X}function d2($,Q){let J=new Set($.snake.map((X)=>`${X.x},${X.y}`)),q=[];for(let X=0;X<$.height;X++)for(let H=0;H<$.width;H++)if(!J.has(`${H},${X}`))q.push({x:H,y:X});return q[Q.int(q.length)]??{x:0,y:0}}function c2($,Q){if(!$.alive)return{ate:!1,died:!1};let J=$.snake[0],q=_6[$.dir],X={x:J.x+q.x,y:J.y+q.y},H=X.x<0||X.y<0||X.x>=$.width||X.y>=$.height,V=X.x===$.food.x&&X.y===$.food.y,Y=V?$.snake:$.snake.slice(0,-1),W=Y.some((U)=>U.x===X.x&&U.y===X.y);if(H||W)return $.alive=!1,{ate:!1,died:!0};if($.snake=[X,...Y],V)$.score+=1,$.food=d2($,Q);return{ate:V,died:!1}}function T6($){if($.length<2)return null;let Q=$[0],J=$[1];if(Q.x>J.x)return"right";if(Q.x<J.x)return"left";if(Q.y>J.y)return"down";if(Q.y<J.y)return"up";return null}class y4{name="snake";actions=["up","down","left","right","tick"];rng=new B(0);st=u4(this.rng);won=!1;reset($){this.rng=new B($),this.st=u4(this.rng),this.won=!1}tickMs(){return Math.max(70,150-this.st.score*4)}step($){if(!this.st.alive)return{reward:0,moved:!1,done:!0,success:this.won};if($!=="tick"){let J=T6(this.st.snake),q=J&&$===E4(J);if($===this.st.dir||$===E4(this.st.dir)||q)return{reward:0,moved:!1,done:!1,success:this.won};return this.st.dir=$,{reward:0,moved:!0,done:!1,success:this.won}}let Q=c2(this.st,this.rng);if(Q.ate&&this.st.score>=v2)this.won=!0;return{reward:Q.ate?1:0,moved:!0,done:!this.st.alive,success:this.won,...Q.ate?{randomEffects:{kind:"food_spawned",position:{...this.st.food}}}:{}}}state(){return{...this.st,snake:this.st.snake.map(($)=>({...$})),food:{...this.st.food}}}score(){return this.st.score}isOver(){return!this.st.alive}hasWon(){return this.won}}var l=[["#####","#@$.#","#####"],["######","# #","# $$ #","# .. #","#@ #","######"],["#######","# #","# .$@ #","# .$ #","# # #","#######"],["#######","# . #","# $ #","#@ $ .#","# #","#######"],["########","# . . #","# $ $ #","# @ #","########"]],t=($,Q)=>`${$},${Q}`;function H0($){let Q=new Set,J=new Set,q=new Set,X={x:0,y:0};return $.forEach((H,V)=>{[...H].forEach((Y,W)=>{if(Y==="#")Q.add(t(W,V));if(Y==="."||Y==="*"||Y==="+")J.add(t(W,V));if(Y==="$"||Y==="*")q.add(t(W,V));if(Y==="@"||Y==="+")X={x:W,y:V}})}),{width:Math.max(...$.map((H)=>H.length)),height:$.length,walls:Q,goals:J,boxes:q,player:X}}var w6={up:{x:0,y:-1},down:{x:0,y:1},left:{x:-1,y:0},right:{x:1,y:0}};function o2($,Q){let J=w6[Q],q=$.player.x+J.x,X=$.player.y+J.y;if($.walls.has(t(q,X)))return{moved:!1,pushed:!1};if($.boxes.has(t(q,X))){let H=q+J.x,V=X+J.y;if($.walls.has(t(H,V))||$.boxes.has(t(H,V)))return{moved:!1,pushed:!1};return $.boxes.delete(t(q,X)),$.boxes.add(t(H,V)),$.player={x:q,y:X},{moved:!0,pushed:!0}}return $.player={x:q,y:X},{moved:!0,pushed:!1}}function l2($){return[...$.boxes].every((Q)=>$.goals.has(Q))}function s2($){return{boxes:[...$.boxes],player:{...$.player}}}function i2($,Q){$.boxes=new Set(Q.boxes),$.player={...Q.player}}var p4=100;class m4{name="sokoban";actions=["up","down","left","right","undo"];keymap={z:"undo",u:"undo"};levelIndex=0;level=H0(l[0]);history=[];moves=0;pushes=0;solvedLevels=0;finished=!1;reset($){this.levelIndex=0,this.solvedLevels=0,this.finished=!1,this.loadLevel(0)}loadLevel($){this.levelIndex=$,this.level=H0(l[$]),this.history=[],this.moves=0,this.pushes=0}step($){if(this.finished)return{reward:0,moved:!1,done:!0,success:!0};if($==="undo"){let q=this.history.pop();if(!q)return{reward:0,moved:!1,done:!1,success:!1};return i2(this.level,q),this.moves=Math.max(0,this.moves-1),{reward:0,moved:!0,done:!1,success:!1}}let Q=s2(this.level),J=o2(this.level,$);if(!J.moved)return{reward:0,moved:!1,done:!1,success:!1};if(this.history.push(Q),this.moves++,J.pushed)this.pushes++;if(!l2(this.level))return{reward:0,moved:!0,done:!1,success:!1};if(this.solvedLevels++,this.levelIndex+1>=l.length)return this.finished=!0,{reward:p4,moved:!0,done:!0,success:!0};return this.loadLevel(this.levelIndex+1),{reward:p4,moved:!0,done:!1,success:!1}}state(){return{level:this.levelIndex,player:{...this.level.player},boxes:[...this.level.boxes].sort(),goals:[...this.level.goals].sort(),moves:this.moves,pushes:this.pushes}}score(){return this.solvedLevels*p4}isOver(){return this.finished}hasWon(){return this.finished}}var G=9;function S6(){return Array.from({length:9},()=>Array(9).fill(0))}function r2($,Q,J,q){for(let V=0;V<9;V++){if(V!==J&&$[Q][V]===q)return!1;if(V!==Q&&$[V][J]===q)return!1}let X=Math.floor(Q/3)*3,H=Math.floor(J/3)*3;for(let V=X;V<X+3;V++)for(let Y=H;Y<H+3;Y++)if((V!==Q||Y!==J)&&$[V][Y]===q)return!1;return!0}function f6($){let Q=[1,2,3,4,5,6,7,8,9];for(let J=Q.length-1;J>0;J--){let q=$.int(J+1);[Q[J],Q[q]]=[Q[q],Q[J]]}return Q}function I6($){let Q=S6(),J=(q)=>{if(q===81)return!0;let X=Math.floor(q/9),H=q%9;for(let V of f6($))if(r2(Q,X,H,V)){if(Q[X][H]=V,J(q+1))return!0;Q[X][H]=0}return!1};return J(0),Q}function n2($){let Q=I6($),J=Q.map((X)=>[...X]),q=Array.from({length:81},(X,H)=>H);for(let X=q.length-1;X>0;X--){let H=$.int(X+1);[q[X],q[H]]=[q[H],q[X]]}for(let X of q.slice(0,44))J[Math.floor(X/9)][X%9]=0;return{givens:J,solution:Q}}function k0($){let Q=new Set;for(let J=0;J<9;J++)for(let q=0;q<9;q++){let X=$[J][q];if(X!==0&&!r2($,J,q,X))Q.add(`${J},${q}`)}return Q}function g4($){return $.every((Q)=>Q.every((J)=>J!==0))&&k0($).size===0}class v4{name="sudoku";actions=["up","down","left","right","1","2","3","4","5","6","7","8","9","clear"];keymap={"0":"clear",backspace:"clear",x:"clear",space:"clear"};puzzle={givens:[],solution:[]};grid=[];row=4;col=4;reset($){this.puzzle=n2(new B($)),this.grid=this.puzzle.givens.map((Q)=>[...Q]),this.row=4,this.col=4}step($){if(this.isOver())return{reward:0,moved:!1,done:!0,success:!0};if($==="up"||$==="down"||$==="left"||$==="right"){let X=this.row+($==="up"?-1:$==="down"?1:0),H=this.col+($==="left"?-1:$==="right"?1:0);if(X<0||H<0||X>=G||H>=G)return{reward:0,moved:!1,done:!1,success:!1};return this.row=X,this.col=H,{reward:0,moved:!0,done:!1,success:!1}}if(this.puzzle.givens[this.row][this.col]!==0)return{reward:0,moved:!1,done:!1,success:!1};let Q=$==="clear"?0:Number($);if(this.grid[this.row][this.col]===Q)return{reward:0,moved:!1,done:!1,success:!1};this.grid[this.row][this.col]=Q;let J=g4(this.grid);return{reward:Q!==0&&Q===this.puzzle.solution[this.row][this.col]?1:0,moved:!0,done:J,success:J}}state(){let $=0,Q=0;for(let J=0;J<G;J++)for(let q=0;q<G;q++){if(this.puzzle.givens[J][q]!==0)continue;let X=this.grid[J][q];if(X!==0)Q++;if(X!==0&&X===this.puzzle.solution[J][q])$++}return{grid:this.grid.map((J)=>[...J]),givens:this.puzzle.givens.map((J)=>[...J]),cursor:{row:this.row,col:this.col},correct:$,filled:Q}}checkpointState(){return{...this.state(),solution:this.puzzle.solution.map(($)=>[...$])}}score(){return this.state().correct}isOver(){return g4(this.grid)}hasWon(){return this.isOver()}givenCount(){return this.puzzle.givens.flat().filter(($)=>$!==0).length}}var T=10,$0=20,H4=["I","O","T","S","Z","J","L"],t2={I:["....","XXXX","....","...."],O:["XX","XX"],T:[".X.","XXX","..."],S:[".XX","XX.","..."],Z:["XX.",".XX","..."],J:["X..","XXX","..."],L:["..X","XXX","..."]};function k6($){let Q=[];return $.forEach((J,q)=>{for(let X=0;X<J.length;X++)if(J[X]==="X")Q.push([X,q])}),Q}function x6($){let Q=$.length;return Array.from({length:Q},(J,q)=>Array.from({length:Q},(X,H)=>$[Q-1-H][q]).join(""))}var a2=(()=>{let $={};for(let Q of H4){let J=t2[Q],q=[];for(let X=0;X<4;X++)q.push(k6(J)),J=x6(J);$[Q]=q}return $})(),E6={"0>1":[[0,0],[-1,0],[-1,1],[0,-2],[-1,-2]],"1>0":[[0,0],[1,0],[1,-1],[0,2],[1,2]],"1>2":[[0,0],[1,0],[1,-1],[0,2],[1,2]],"2>1":[[0,0],[-1,0],[-1,1],[0,-2],[-1,-2]],"2>3":[[0,0],[1,0],[1,1],[0,-2],[1,-2]],"3>2":[[0,0],[-1,0],[-1,-1],[0,2],[-1,2]],"3>0":[[0,0],[-1,0],[-1,-1],[0,2],[-1,2]],"0>3":[[0,0],[1,0],[1,1],[0,-2],[1,-2]]},u6={"0>1":[[0,0],[-2,0],[1,0],[-2,-1],[1,2]],"1>0":[[0,0],[2,0],[-1,0],[2,1],[-1,-2]],"1>2":[[0,0],[-1,0],[2,0],[-1,2],[2,-1]],"2>1":[[0,0],[1,0],[-2,0],[1,-2],[-2,1]],"2>3":[[0,0],[2,0],[-1,0],[2,1],[-1,-2]],"3>2":[[0,0],[-2,0],[1,0],[-2,-1],[1,2]],"3>0":[[0,0],[1,0],[-2,0],[1,-2],[-2,1]],"0>3":[[0,0],[-1,0],[2,0],[-1,2],[2,-1]]};function y6($,Q,J){if($==="O")return[[0,0]];return($==="I"?u6:E6)[`${Q}>${J}`]}function d4(){return Array.from({length:$0},()=>Array(T).fill(null))}function p6($){return $.map((Q)=>[...Q])}function a($){return a2[$.type][$.rotation].map(([Q,J])=>[$.x+Q,$.y+J])}function V4($,Q){for(let[J,q]of a(Q)){if(J<0||J>=T||q>=$0)return!0;if(q>=0&&$[q][J]!==null)return!0}return!1}function c4($){let Q=t2[$].length,J=Math.min(...a2[$][0].map(([,q])=>q));return{type:$,rotation:0,x:Math.floor((T-Q)/2),y:-J}}function x0($,Q,J,q){let X={...Q,x:Q.x+J,y:Q.y+q};return V4($,X)?null:X}function e2($,Q,J){let q=((Q.rotation+J)%4+4)%4;for(let[X,H]of y6(Q.type,Q.rotation,q)){let V={...Q,rotation:q,x:Q.x+X,y:Q.y-H};if(!V4($,V))return V}return null}function A0($,Q){let J=0;while(x0($,Q,0,J+1))J++;return J}function $8($,Q){let J=p6($),q=!1;for(let[V,Y]of a(Q)){if(Y<0){q=!0;continue}J[Y][V]=Q.type}let{board:X,count:H}=m6(J);return{board:X,cleared:H,toppedOut:q}}function m6($){let Q=$.filter((X)=>X.some((H)=>H===null)),J=$0-Q.length;return{board:[...Array.from({length:J},()=>Array(T).fill(null)),...Q.map((X)=>[...X])],count:J}}var g6=[0,100,300,500,800];function Q8($,Q){return g6[$]*(Q+1)}function J8($){return Math.floor($/10)}function q8($){return Math.max(60,Math.round(800*Math.pow(0.85,$)))}class Y4{rng;useBag;bag=[];constructor($,Q=!0){this.rng=$;this.useBag=Q}next(){if(!this.useBag)return H4[this.rng.int(H4.length)];if(this.bag.length===0){this.bag=[...H4];for(let $=this.bag.length-1;$>0;$--){let Q=this.rng.int($+1);[this.bag[$],this.bag[Q]]=[this.bag[Q],this.bag[$]]}}return this.bag.pop()}}var v6=3;class s{static VARIATIONS=[{id:"classic",title:"Standard",description:"Standard seven-bag Tetris.",goal:"Survive as long as possible"},{id:"sprint",title:"Sprint",description:"Clear 10 lines to finish.",goal:"Clear 10 lines"},{id:"chaos",title:"Chaos",description:"Pieces are fully random instead of bagged.",goal:"Survive the chaos"}];name="tetris";actions=["left","right","rotate-cw","rotate-ccw","soft-drop","hard-drop","tick"];variation;board=d4();active=null;queue=[];bag=new Y4(new B(0));points=0;lines=0;over=!1;targetLines;gravityScale=1;constructor($="classic"){this.variation=s.VARIATIONS.find(({id:Q})=>Q===$)??s.VARIATIONS[0],this.targetLines=this.variation.id==="sprint"?10:0}reset($){this.bag=new Y4(new B($),this.variation.id!=="chaos"),this.gravityScale=this.variation.id==="chaos"?0.75+new B($).next()*0.5:1,this.board=d4(),this.points=0,this.lines=0,this.over=!1,this.queue=Array.from({length:v6+1},()=>this.bag.next()),this.active=c4(this.queue.shift())}step($){if(this.over||!this.active)return{reward:0,moved:!1,done:!0,success:!1};switch($){case"left":case"right":{let Q=x0(this.board,this.active,$==="left"?-1:1,0);if(!Q)return this.noop();return this.active=Q,{reward:0,moved:!0,done:!1,success:!1}}case"rotate-cw":case"rotate-ccw":{let Q=e2(this.board,this.active,$==="rotate-cw"?1:-1);if(!Q)return this.noop();return this.active=Q,{reward:0,moved:!0,done:!1,success:!1}}case"soft-drop":{let Q=x0(this.board,this.active,0,1);if(Q)return this.active=Q,this.points+=1,{reward:1,moved:!0,done:!1,success:!1};let J=this.lockActive();return{reward:J.reward,moved:!0,done:this.over,success:this.hasWon(),randomEffects:J.randomEffects}}case"tick":{let Q=x0(this.board,this.active,0,1);if(Q)return this.active=Q,{reward:0,moved:!0,done:!1,success:!1};let J=this.lockActive();return{reward:J.reward,moved:!0,done:this.over,success:this.hasWon(),randomEffects:J.randomEffects}}case"hard-drop":{let Q=A0(this.board,this.active);this.active={...this.active,y:this.active.y+Q};let J=2*Q;this.points+=J;let q=this.lockActive();return{reward:J+q.reward,moved:!0,done:this.over,success:this.hasWon(),randomEffects:q.randomEffects}}}}noop(){return{reward:0,moved:!1,done:!1,success:!1}}lockActive(){let $=this.active,Q=$8(this.board,$);this.board=Q.board;let J=Q8(Q.cleared,this.level());if(this.points+=J,this.lines+=Q.cleared,this.targetLines>0&&this.lines>=this.targetLines)this.over=!0;if(Q.toppedOut)return this.over=!0,this.active=null,{reward:J};let q=this.queue.shift(),X=this.bag.next();this.queue.push(X);let H=c4(q);if(V4(this.board,H))this.over=!0,this.active=null;else this.active=H;return{reward:J,randomEffects:{kind:"piece_drawn",active_piece:q,queued_piece:X}}}state(){return{board:this.board.map(($)=>[...$]),active:this.active?{...this.active}:null,next:[...this.queue],score:this.points,lines:this.lines,level:this.level(),over:this.over}}score(){return this.points}level(){return J8(this.lines)}linesCleared(){return this.lines}isOver(){return this.over}hasWon(){return this.targetLines>0&&this.lines>=this.targetLines}gravityMs(){return Math.max(60,Math.round(q8(this.level())*this.gravityScale))}}var E0={id:"classic",title:"Standard",description:"Standard rules.",goal:"Standard rules"},X8=["2048","tetris","minesweeper"],y=[{id:"2048",version:"1",title:"2048",description:"Merge tiles to reach 2048.",create:($)=>new Z0($),variations:Z0.VARIATIONS},{id:"tetris",version:"1",title:"Tetris",description:"Clear lines with falling blocks.",create:($)=>new s($),variations:s.VARIATIONS},{id:"minesweeper",version:"1",title:"Minesweeper",description:"Clear the field, avoid the mines.",create:()=>new x4,variations:[E0]},{id:"snake",version:"1",title:"Snake",description:"Eat, grow, don't crash.",create:()=>new y4,variations:[E0]},{id:"sokoban",version:"1",title:"Sokoban",description:"Push crates onto goals.",create:()=>new m4,variations:[E0]},{id:"connect4",version:"1",title:"Connect Four",description:"Line up four before the bot.",create:()=>new w4,variations:[E0]},{id:"sudoku",version:"1",title:"Sudoku",description:"Fill every row, column, and box 1–9.",create:()=>new v4,variations:[E0]}];function W4($){return $.create!==null}function H8($){let Q=$.trim().toLowerCase();return y.find((J)=>J.id===Q)}function V8($){if($.outcome!=="completed")return null;return{game_id:$.gameId,game_type:$.gameType,variation_id:$.variationId,score:$.score,success:$.success,completed_at:new Date($.endedAtMs).toISOString(),duration_ms:Math.max(0,$.endedAtMs-$.startedAtMs),platform:$.platform}}var O=($,Q,J=Q)=>`<button type="button" class="control" data-action="${$}" aria-label="${J}">${Q}</button>`,Y0=($)=>`<div class="game-hud">${$.map(([Q,J])=>`<span><small>${Q}</small><strong>${J}</strong></span>`).join("")}</div>`;function o4($,Q,{gap:J=3,pad:q=12,maxBoard:X=340,maxHeight:H=280,min:V=12,max:Y=56}={}){let W=Math.floor((X-q-($-1)*J)/$),U=Math.floor((H-q-(Q-1)*J)/Q);return Math.max(V,Math.min(Y,W,U))}function d6($){let Q=$.state(),J=Q.board.flat().map((q,X)=>`<div class="tile tile-${q||"empty"}" data-cell="${X}" data-value="${q||0}" aria-label="${q||"empty"}">${q||""}</div>`).join("");return`${Y0([["Score",Q.score]])}
2
+ <div class="board board-2048" role="grid" aria-label="2048 board">${J}</div>
3
+ <div class="controls direction-pad" aria-label="2048 controls">
4
+ ${O("up","↑","Move up")}${O("left","←","Move left")}${O("down","↓","Move down")}${O("right","→","Move right")}
5
+ </div>`}function l4($){let Q=$.board.flat().map((q)=>q?{type:q}:null);if(!$.active)return Q;let J={...$.active,y:$.active.y+A0($.board,$.active)};for(let[q,X]of a(J))if(X>=0&&X<$0)Q[X*T+q]={type:J.type,ghost:!0};for(let[q,X]of a($.active))if(X>=0&&X<$0)Q[X*T+q]={type:$.active.type,active:!0};return Q}function s4($){if(!$)return"tetromino";return`tetromino piece-${$.type}${$.ghost?" ghost":""}${$.active?" active":""}`}function c6($){let Q=$.state(),J=l4(Q).map((q,X)=>`<i class="${s4(q)}" data-cell="${X}"></i>`).join("");return`${Y0([["Score",Q.score],["Lines",Q.lines],["Level",Q.level]])}
6
+ <div class="tetris-layout">
7
+ <div class="board board-tetris" role="grid" aria-label="Tetris board">${J}</div>
8
+ <aside class="next-pieces"><small>Next</small>${Q.next.slice(0,3).map((q)=>`<b class="piece-${q}">${q}</b>`).join("")}</aside>
9
+ </div>
10
+ <div class="controls tetris-controls" aria-label="Tetris controls">
11
+ ${O("left","←","Move left")}${O("rotate-ccw","↶","Rotate counterclockwise")}${O("rotate-cw","↷","Rotate clockwise")}${O("right","→","Move right")}${O("soft-drop","↓","Soft drop")}${O("hard-drop","Drop","Hard drop")}
12
+ </div>`}function i4($){return{className:`mine-cell cell-${$}`,content:$===-3?"✹":$===-2?"⚑":$<0?"":String($||""),label:$===-3?"mine":$===-2?"flagged":$===-1?"hidden":$===0?"empty":`${$} adjacent mines`}}function o6($){let Q=$.state(),J=Q.view.flat().filter((X)=>X===-2).length,q=Q.view.flatMap((X,H)=>X.map((V,Y)=>{let W=Y===Q.cursor.x&&H===Q.cursor.y,{className:U,content:Z,label:N}=i4(V);return`<button type="button" class="${U}${W?" selected":""}" data-cell="${H*X.length+Y}" data-cell-x="${Y}" data-cell-y="${H}" aria-label="Row ${H+1}, column ${Y+1}, ${N}">${Z}</button>`})).join("");return`${Y0([["Mines",Math.max(0,q4-J)]])}
13
+ <div class="board board-mines" role="grid" aria-label="Minesweeper field">${q}</div>
14
+ <div class="controls mine-controls">${O("reveal","Reveal")}${O("flag","⚑ Flag","Toggle flag")}</div>`}var F0=($)=>(Math.round($*1000)/1000).toString(),V0=0.18,z0=0.04,u0=1-z0*2;function l6($){return $.map((Q)=>`<rect class="snake-seg" x="${F0(Q.x+z0)}" y="${F0(Q.y+z0)}" width="${u0}" height="${u0}"/>`).join("")}var Y8={up:{x:0,y:-1},down:{x:0,y:1},left:{x:-1,y:0},right:{x:1,y:0}};function r4($,Q){let J=$[0]??{x:0,y:0},q=$[1],X=Y8[Q].x,H=Y8[Q].y;if(q){let Z=J.x-q.x,N=J.y-q.y,L=Math.hypot(Z,N);if(L>0.001)X=Z/L,H=N/L}let V=J.x+0.5+X*0.13,Y=J.y+0.5+H*0.13,W=-H*0.19,U=X*0.19;return[{x:V+W,y:Y+U},{x:V-W,y:Y-U}]}function s6($){let Q=$.state(),J=o4(Q.width,Q.height,{gap:0,pad:0,maxBoard:480,maxHeight:420,min:16,max:28}),[q,X]=r4(Q.snake,Q.dir),H=(V)=>`<rect class="snake-eye" x="${F0(V.x-V0/2)}" y="${F0(V.y-V0/2)}" width="${V0}" height="${V0}"/>`;return`${Y0([["Score",Q.score]])}
15
+ <div class="board board-snake" style="--cell:${J}px;--cols:${Q.width};--rows:${Q.height}" role="img" aria-label="Snake board">
16
+ <svg class="snake-svg" viewBox="0 0 ${Q.width} ${Q.height}" aria-hidden="true" focusable="false">
17
+ <g class="snake-food" transform="translate(${F0(Q.food.x+0.5)} ${F0(Q.food.y+0.5)})">
18
+ <g class="snake-food-pulse">
19
+ <circle class="snake-food-body" r="0.32"/>
20
+ <path class="snake-food-leaf" d="M0.05 -0.28 q0.19 -0.17 0.32 -0.09 q-0.08 0.18 -0.28 0.18 z"/>
21
+ </g>
22
+ </g>
23
+ <g class="snake-blocks">${l6(Q.snake)}</g>
24
+ ${H(q)}${H(X)}
25
+ </svg>
26
+ </div>
27
+ <div class="controls direction-pad" aria-label="Snake controls">
28
+ ${O("up","↑","Steer up")}${O("left","←","Steer left")}${O("down","↓","Steer down")}${O("right","→","Steer right")}
29
+ </div>`}function i6($){let Q=$.state(),J=H0(l[Q.level]),q=new Set(Q.boxes),X=new Set(Q.goals),H=o4(J.width,J.height,{gap:4,pad:24,maxBoard:540,maxHeight:460,min:32,max:72}),V=o4(J.width,J.height,{gap:4,pad:24,maxBoard:540,maxHeight:400,min:32,max:72}),Y=Array.from({length:J.height},(W,U)=>{return`<div class="sokoban-row" role="row">${Array.from({length:J.width},(N,L)=>{let D=`${L},${U}`,A=Q.player.x===L&&Q.player.y===U,R=q.has(D),C=X.has(D);return`<i class="sokoban-cell ${J.walls.has(D)?"wall":A?`player${C?" goal":""}`:R?`box${C?" goal":""}`:C?"goal":"floor"}" data-cell="${U*J.width+L}" aria-hidden="true"></i>`}).join("")}</div>`}).join("");return`${Y0([["Level",`${Q.level+1}/${l.length}`],["Moves",Q.moves],["Pushes",Q.pushes]])}
30
+ <div class="board board-sokoban" style="--cell:${H}px;--small-cell:${V}px" role="grid" aria-label="Sokoban board">${Y}</div>
31
+ <div class="controls direction-pad" aria-label="Sokoban controls">
32
+ ${O("up","↑","Move up")}${O("left","←","Move left")}${O("down","↓","Move down")}${O("right","→","Move right")}${O("undo","Undo")}
33
+ </div>`}function M0($){if($.result===1)return{label:"You won!",tone:"win"};if($.result===2)return{label:"You lost",tone:"loss"};if($.result===3)return{label:"Draw",tone:"draw"};return{label:"Your turn",tone:"play"}}function r6($){let Q=$.state(),{label:J}=M0(Q),q=Array.from({length:7},(X,H)=>{let V=Q.board[0][H]!==0,Y=Q.board.map((W,U)=>`<i class="disc disc-${W[H]}" data-cell="${U*7+H}" data-column="${H}"></i>`).join("");return`<button type="button" class="connect-col${H===Q.cursor?" selected":""}${V?" full":""}" data-column="${H}" aria-label="Drop in column ${H+1}${V?", full":""}"><span class="drop-hint" aria-hidden="true">▼</span>${Y}</button>`}).join("");return`${Y0([["Turn",J],["You",'<i class="hud-disc disc-1"></i>'],["Bot",'<i class="hud-disc disc-2"></i>']])}
34
+ <div class="connect-wrap"><div class="board board-connect" role="grid" aria-label="Connect Four board">${q}</div></div>`}function n4($,Q,J){return`sudoku-cell${$?" given":""}${Q?" conflict":""}${J?" selected":""}`}function n6($){let Q=$.state(),J=k0(Q.grid),q=Q.grid.flatMap((X,H)=>X.map((V,Y)=>{let W=Q.givens[H][Y]!==0,U=Q.cursor.row===H&&Q.cursor.col===Y;return`<button type="button" class="${n4(W,J.has(`${H},${Y}`),U)}" data-cell="${H*X.length+Y}" data-cell-row="${H}" data-cell-col="${Y}" aria-label="Row ${H+1}, column ${Y+1}${V?`, ${V}`:", empty"}" ${W?"disabled":""}>${V||""}</button>`})).join("");return`${Y0([["Filled",Q.filled],["Correct",Q.correct]])}
35
+ <div class="board board-sudoku" role="grid" aria-label="Sudoku board">${q}</div>
36
+ <div class="controls number-pad" aria-label="Sudoku number pad">${[1,2,3,4,5,6,7,8,9].map((X)=>O(String(X),String(X),`Place ${X}`)).join("")}${O("clear","×","Clear cell")}</div>`}var t6={"2048":d6,tetris:c6,minesweeper:o6,snake:s6,sokoban:i6,connect4:r6,sudoku:n6};function W8($){let Q=t6[$.name];if(!Q)throw Error(`No HTML renderer for ${$.name}`);let J=$.name==="connect4"?M0($.state()).tone:void 0,q=J&&J!=="play"?` game-tone-${J}`:"";return`<section class="game game-${$.name}${q}" data-game="${$.name}">${Q($)}</section>`}function a6($,Q){let J=Array.from({length:E},(q,X)=>$==="left"||$==="right"?Q*E+X:X*E+Q);return $==="right"||$==="down"?J.reverse():J}function K8($,Q){let J=$.flat(),q=[];for(let X=0;X<E;X++){let H=a6(Q,X),V=H.filter((W)=>J[W]!==0),Y=0;for(let W=0;W<V.length;W++){let U=H[Y],Z=W+1<V.length&&J[V[W]]===J[V[W+1]];if(q.push({from:V[W],to:U,merged:Z}),Z)q.push({from:V[W+1],to:U,merged:!0}),W++;Y++}}return q.filter((X)=>X.from!==X.to||X.merged)}function e6($,Q){return $.every((J,q)=>J.every((X,H)=>X===Q[q][H]))}function j8($,Q,J){if(!Q)return null;let q=A0($,Q);for(let X of q===0?[0]:[0,q]){let H={...Q,y:Q.y+X},V=$.map((L)=>[...L]),Y=a(H).filter(([L,D])=>D>=0&&D<$0&&L>=0&&L<T);for(let[L,D]of Y)V[D][L]=H.type;let W=[],U=[];V.forEach((L,D)=>{if(L.every((A)=>A!==null))W.push(D);else U.push(L)});let Z=[...Array.from({length:W.length},()=>Array(T).fill(null)),...U];if(!e6(Z,J))continue;return{cells:Y.filter(([,L])=>!W.includes(L)).map(([L,D])=>(D+W.filter((A)=>A>D).length)*T+L),clearedRows:W}}return null}function U8($,Q){let J=[],q=[],X=[],H=Q[0]?.length??0;return Q.forEach((V,Y)=>{V.forEach((W,U)=>{let Z=$[Y]?.[U]??-1;if(W===Z)return;let N=Y*H+U;if(W===-3)q.push(N);else if(W>=0)J.push(N);else if(W===-2||Z===-2)X.push(N)})}),{revealed:J,exploded:q,flagged:X}}function N8($,Q,J){let q=Q%J,X=Math.floor(Q/J),H=new Map;for(let V of $){let Y=Math.abs(V%J-q),W=Math.abs(Math.floor(V/J)-X);H.set(V,Math.max(Y,W))}return H}function D8($,Q){if($.level!==Q.level)return{step:null,pushedBox:null,landedOnGoal:!1};let J=Q.player.x-$.player.x,q=Q.player.y-$.player.y;if(J===0&&q===0)return{step:null,pushedBox:null,landedOnGoal:!1};let X=new Set($.boxes),H=`${Q.player.x+J},${Q.player.y+q}`,V=X.has(`${Q.player.x},${Q.player.y}`)&&Q.boxes.includes(H);return{step:{dx:J,dy:q},pushedBox:V?H:null,landedOnGoal:V&&Q.goals.includes(H)}}var $1=($)=>$.length===G&&$.every((Q)=>Q!==0);function L8($,Q){let J=null;for(let D=0;D<G&&J===null;D++)for(let A=0;A<G;A++)if($[D]?.[A]!==Q[D][A]){J=D*G+A;break}if(J===null)return{cell:null,placed:!1,completed:[]};let q=Math.floor(J/G),X=J%G,H=Q[q][X]!==0;if(!H)return{cell:J,placed:H,completed:[]};let V=[],Y=Array.from({length:G},(D,A)=>q*G+A),W=Array.from({length:G},(D,A)=>A*G+X),U=Math.floor(q/3)*3,Z=Math.floor(X/3)*3,N=Array.from({length:G},(D,A)=>(U+Math.floor(A/3))*G+Z+A%3),L=(D)=>D.map((A)=>Q[Math.floor(A/G)][A%G]);for(let D of[Y,W,N]){let A=L(D);if($1(A)&&new Set(A).size===G)V.push(...D)}return{cell:J,placed:H,completed:[...new Set(V)]}}function Z8($,Q){let J=Q[0]?.length??0;for(let q=0;q<Q.length;q++)for(let X=0;X<J;X++)if($[q]?.[X]===0&&Q[q][X]!==0)return q*J+X;return null}function P($,Q,J,q){if(J==="a"&&!q)throw TypeError("Private accessor was defined without a getter");if(typeof Q==="function"?$!==Q||!q:!Q.has($))throw TypeError("Cannot read private member from an object whose class did not declare it");return J==="m"?q:J==="a"?q.call($):q?q.value:Q.get($)}function W0($,Q,J,q,X){if(q==="m")throw TypeError("Private method is not writable");if(q==="a"&&!X)throw TypeError("Private accessor was defined without a setter");if(typeof Q==="function"?$!==Q||!X:!Q.has($))throw TypeError("Cannot write private member to an object whose class did not declare it");return q==="a"?X.call($,J):X?X.value=J:Q.set($,J),J}var K0,v,R0,K4,j4,f="__TAURI_TO_IPC_KEY__";function t4($,Q=!1){return window.__TAURI_INTERNALS__.transformCallback($,Q)}class Q1{constructor($){K0.set(this,void 0),v.set(this,0),R0.set(this,[]),K4.set(this,void 0),W0(this,K0,$||(()=>{}),"f"),this.id=t4((Q)=>{let J=Q.index;if("end"in Q){if(J==P(this,v,"f"))this.cleanupCallback();else W0(this,K4,J,"f");return}let q=Q.message;if(J==P(this,v,"f")){P(this,K0,"f").call(this,q),W0(this,v,P(this,v,"f")+1,"f");while(P(this,v,"f")in P(this,R0,"f")){let X=P(this,R0,"f")[P(this,v,"f")];P(this,K0,"f").call(this,X),delete P(this,R0,"f")[P(this,v,"f")],W0(this,v,P(this,v,"f")+1,"f")}if(P(this,v,"f")===P(this,K4,"f"))this.cleanupCallback()}else P(this,R0,"f")[J]=q})}cleanupCallback(){window.__TAURI_INTERNALS__.unregisterCallback(this.id)}set onmessage($){W0(this,K0,$,"f")}get onmessage(){return P(this,K0,"f")}[(K0=new WeakMap,v=new WeakMap,R0=new WeakMap,K4=new WeakMap,f)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[f]()}}async function K($,Q={},J){return window.__TAURI_INTERNALS__.invoke($,Q,J)}class a4{get rid(){return P(this,j4,"f")}constructor($){j4.set(this,void 0),W0(this,j4,$,"f")}async close(){return K("plugin:resources|close",{rid:this.rid})}}j4=new WeakMap;class O0{constructor(...$){if(this.type="Logical",$.length===1)if("Logical"in $[0])this.width=$[0].Logical.width,this.height=$[0].Logical.height;else this.width=$[0].width,this.height=$[0].height;else this.width=$[0],this.height=$[1]}toPhysical($){return new j0(this.width*$,this.height*$)}[f](){return{width:this.width,height:this.height}}toJSON(){return this[f]()}}class j0{constructor(...$){if(this.type="Physical",$.length===1)if("Physical"in $[0])this.width=$[0].Physical.width,this.height=$[0].Physical.height;else this.width=$[0].width,this.height=$[0].height;else this.width=$[0],this.height=$[1]}toLogical($){return new O0(this.width/$,this.height/$)}[f](){return{width:this.width,height:this.height}}toJSON(){return this[f]()}}class Q0{constructor($){this.size=$}toLogical($){return this.size instanceof O0?this.size:this.size.toLogical($)}toPhysical($){return this.size instanceof j0?this.size:this.size.toPhysical($)}[f](){return{[`${this.size.type}`]:{width:this.size.width,height:this.size.height}}}toJSON(){return this[f]()}}class U4{constructor(...$){if(this.type="Logical",$.length===1)if("Logical"in $[0])this.x=$[0].Logical.x,this.y=$[0].Logical.y;else this.x=$[0].x,this.y=$[0].y;else this.x=$[0],this.y=$[1]}toPhysical($){return new i(this.x*$,this.y*$)}[f](){return{x:this.x,y:this.y}}toJSON(){return this[f]()}}class i{constructor(...$){if(this.type="Physical",$.length===1)if("Physical"in $[0])this.x=$[0].Physical.x,this.y=$[0].Physical.y;else this.x=$[0].x,this.y=$[0].y;else this.x=$[0],this.y=$[1]}toLogical($){return new U4(this.x/$,this.y/$)}[f](){return{x:this.x,y:this.y}}toJSON(){return this[f]()}}class B0{constructor($){this.position=$}toLogical($){return this.position instanceof U4?this.position:this.position.toLogical($)}toPhysical($){return this.position instanceof i?this.position:this.position.toPhysical($)}[f](){return{[`${this.position.type}`]:{x:this.position.x,y:this.position.y}}}toJSON(){return this[f]()}}var u;(function($){$.WINDOW_RESIZED="tauri://resize",$.WINDOW_MOVED="tauri://move",$.WINDOW_CLOSE_REQUESTED="tauri://close-requested",$.WINDOW_DESTROYED="tauri://destroyed",$.WINDOW_FOCUS="tauri://focus",$.WINDOW_BLUR="tauri://blur",$.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",$.WINDOW_THEME_CHANGED="tauri://theme-changed",$.WINDOW_CREATED="tauri://window-created",$.WINDOW_SUSPENDED="tauri://suspended",$.WINDOW_RESUMED="tauri://resumed",$.WEBVIEW_CREATED="tauri://webview-created",$.DRAG_ENTER="tauri://drag-enter",$.DRAG_OVER="tauri://drag-over",$.DRAG_DROP="tauri://drag-drop",$.DRAG_LEAVE="tauri://drag-leave"})(u||(u={}));async function A8($,Q){window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener($,Q),await K("plugin:event|unlisten",{event:$,eventId:Q})}async function e4($,Q,J){var q;let X=typeof(J===null||J===void 0?void 0:J.target)==="string"?{kind:"AnyLabel",label:J.target}:(q=J===null||J===void 0?void 0:J.target)!==null&&q!==void 0?q:{kind:"Any"};return K("plugin:event|listen",{event:$,target:X,handler:t4(Q)}).then((H)=>{return async()=>A8($,H)})}async function F8($,Q,J){return e4($,(q)=>{A8($,q.id),Q(q)},J)}async function z8($,Q){await K("plugin:event|emit",{event:$,payload:Q})}async function M8($,Q,J){await K("plugin:event|emit_to",{target:typeof $==="string"?{kind:"AnyLabel",label:$}:$,event:Q,payload:J})}class y0 extends a4{constructor($){super($)}static async new($,Q,J){return K("plugin:image|new",{rgba:p0($),width:Q,height:J}).then((q)=>new y0(q))}static async fromBytes($){return K("plugin:image|from_bytes",{bytes:p0($)}).then((Q)=>new y0(Q))}static async fromPath($){return K("plugin:image|from_path",{path:$}).then((Q)=>new y0(Q))}async rgba(){return K("plugin:image|rgba",{rid:this.rid}).then(($)=>new Uint8Array($))}async size(){return K("plugin:image|size",{rid:this.rid})}}function p0($){return $==null?null:typeof $==="string"?$:$ instanceof y0?$.rid:$}var J2;(function($){$[$.Critical=1]="Critical",$[$.Informational=2]="Informational"})(J2||(J2={}));class P8{constructor($){this._preventDefault=!1,this.event=$.event,this.id=$.id}preventDefault(){this._preventDefault=!0}isPreventDefault(){return this._preventDefault}}var R8;(function($){$.None="none",$.Normal="normal",$.Indeterminate="indeterminate",$.Paused="paused",$.Error="error"})(R8||(R8={}));function q2(){return new X2(window.__TAURI_INTERNALS__.metadata.currentWindow.label,{skip:!0})}async function $2(){return K("plugin:window|get_all_windows").then(($)=>$.map((Q)=>new X2(Q,{skip:!0})))}var Q2=["tauri://created","tauri://error"];class X2{constructor($,Q={}){var J;if(this.label=$,this.listeners=Object.create(null),!(Q===null||Q===void 0?void 0:Q.skip))K("plugin:window|create",{options:{...Q,parent:typeof Q.parent==="string"?Q.parent:(J=Q.parent)===null||J===void 0?void 0:J.label,label:$}}).then(async()=>this.emit("tauri://created")).catch(async(q)=>this.emit("tauri://error",q))}static async getByLabel($){var Q;return(Q=(await $2()).find((J)=>J.label===$))!==null&&Q!==void 0?Q:null}static getCurrent(){return q2()}static async getAll(){return $2()}static async getFocusedWindow(){for(let $ of await $2())if(await $.isFocused())return $;return null}async listen($,Q){if(this._handleTauriEvent($,Q))return()=>{let J=this.listeners[$];J.splice(J.indexOf(Q),1)};return e4($,Q,{target:{kind:"Window",label:this.label}})}async once($,Q){if(this._handleTauriEvent($,Q))return()=>{let J=this.listeners[$];J.splice(J.indexOf(Q),1)};return F8($,Q,{target:{kind:"Window",label:this.label}})}async emit($,Q){if(Q2.includes($)){for(let J of this.listeners[$]||[])J({event:$,id:-1,payload:Q});return}return z8($,Q)}async emitTo($,Q,J){if(Q2.includes(Q)){for(let q of this.listeners[Q]||[])q({event:Q,id:-1,payload:J});return}return M8($,Q,J)}_handleTauriEvent($,Q){if(Q2.includes($)){if(!($ in this.listeners))this.listeners[$]=[Q];else this.listeners[$].push(Q);return!0}return!1}async scaleFactor(){return K("plugin:window|scale_factor",{label:this.label})}async innerPosition(){return K("plugin:window|inner_position",{label:this.label}).then(($)=>new i($))}async outerPosition(){return K("plugin:window|outer_position",{label:this.label}).then(($)=>new i($))}async innerSize(){return K("plugin:window|inner_size",{label:this.label}).then(($)=>new j0($))}async outerSize(){return K("plugin:window|outer_size",{label:this.label}).then(($)=>new j0($))}async isFullscreen(){return K("plugin:window|is_fullscreen",{label:this.label})}async isMinimized(){return K("plugin:window|is_minimized",{label:this.label})}async isMaximized(){return K("plugin:window|is_maximized",{label:this.label})}async isFocused(){return K("plugin:window|is_focused",{label:this.label})}async isDecorated(){return K("plugin:window|is_decorated",{label:this.label})}async isResizable(){return K("plugin:window|is_resizable",{label:this.label})}async isMaximizable(){return K("plugin:window|is_maximizable",{label:this.label})}async isMinimizable(){return K("plugin:window|is_minimizable",{label:this.label})}async isClosable(){return K("plugin:window|is_closable",{label:this.label})}async isVisible(){return K("plugin:window|is_visible",{label:this.label})}async title(){return K("plugin:window|title",{label:this.label})}async theme(){return K("plugin:window|theme",{label:this.label})}async isAlwaysOnTop(){return K("plugin:window|is_always_on_top",{label:this.label})}async activityName(){return K("plugin:window|activity_name",{label:this.label})}async sceneIdentifier(){return K("plugin:window|scene_identifier",{label:this.label})}async center(){return K("plugin:window|center",{label:this.label})}async requestUserAttention($){let Q=null;if($)if($===J2.Critical)Q={type:"Critical"};else Q={type:"Informational"};return K("plugin:window|request_user_attention",{label:this.label,value:Q})}async setResizable($){return K("plugin:window|set_resizable",{label:this.label,value:$})}async setEnabled($){return K("plugin:window|set_enabled",{label:this.label,value:$})}async isEnabled(){return K("plugin:window|is_enabled",{label:this.label})}async setMaximizable($){return K("plugin:window|set_maximizable",{label:this.label,value:$})}async setMinimizable($){return K("plugin:window|set_minimizable",{label:this.label,value:$})}async setClosable($){return K("plugin:window|set_closable",{label:this.label,value:$})}async setTitle($){return K("plugin:window|set_title",{label:this.label,value:$})}async maximize(){return K("plugin:window|maximize",{label:this.label})}async unmaximize(){return K("plugin:window|unmaximize",{label:this.label})}async toggleMaximize(){return K("plugin:window|toggle_maximize",{label:this.label})}async minimize(){return K("plugin:window|minimize",{label:this.label})}async unminimize(){return K("plugin:window|unminimize",{label:this.label})}async show(){return K("plugin:window|show",{label:this.label})}async hide(){return K("plugin:window|hide",{label:this.label})}async close(){return K("plugin:window|close",{label:this.label})}async destroy(){return K("plugin:window|destroy",{label:this.label})}async setDecorations($){return K("plugin:window|set_decorations",{label:this.label,value:$})}async setShadow($){return K("plugin:window|set_shadow",{label:this.label,value:$})}async setEffects($){return K("plugin:window|set_effects",{label:this.label,value:$})}async clearEffects(){return K("plugin:window|set_effects",{label:this.label,value:null})}async setAlwaysOnTop($){return K("plugin:window|set_always_on_top",{label:this.label,value:$})}async setAlwaysOnBottom($){return K("plugin:window|set_always_on_bottom",{label:this.label,value:$})}async setContentProtected($){return K("plugin:window|set_content_protected",{label:this.label,value:$})}async setSize($){return K("plugin:window|set_size",{label:this.label,value:$ instanceof Q0?$:new Q0($)})}async setMinSize($){return K("plugin:window|set_min_size",{label:this.label,value:$ instanceof Q0?$:$?new Q0($):null})}async setMaxSize($){return K("plugin:window|set_max_size",{label:this.label,value:$ instanceof Q0?$:$?new Q0($):null})}async setSizeConstraints($){function Q(J){return J?{Logical:J}:null}return K("plugin:window|set_size_constraints",{label:this.label,value:{minWidth:Q($===null||$===void 0?void 0:$.minWidth),minHeight:Q($===null||$===void 0?void 0:$.minHeight),maxWidth:Q($===null||$===void 0?void 0:$.maxWidth),maxHeight:Q($===null||$===void 0?void 0:$.maxHeight)}})}async setPosition($){return K("plugin:window|set_position",{label:this.label,value:$ instanceof B0?$:new B0($)})}async setFullscreen($){return K("plugin:window|set_fullscreen",{label:this.label,value:$})}async setSimpleFullscreen($){return K("plugin:window|set_simple_fullscreen",{label:this.label,value:$})}async setFocus(){return K("plugin:window|set_focus",{label:this.label})}async setFocusable($){return K("plugin:window|set_focusable",{label:this.label,value:$})}async setIcon($){return K("plugin:window|set_icon",{label:this.label,value:p0($)})}async setSkipTaskbar($){return K("plugin:window|set_skip_taskbar",{label:this.label,value:$})}async setCursorGrab($){return K("plugin:window|set_cursor_grab",{label:this.label,value:$})}async setCursorVisible($){return K("plugin:window|set_cursor_visible",{label:this.label,value:$})}async setCursorIcon($){return K("plugin:window|set_cursor_icon",{label:this.label,value:$})}async setBackgroundColor($){return K("plugin:window|set_background_color",{color:$})}async setCursorPosition($){return K("plugin:window|set_cursor_position",{label:this.label,value:$ instanceof B0?$:new B0($)})}async setIgnoreCursorEvents($){return K("plugin:window|set_ignore_cursor_events",{label:this.label,value:$})}async startDragging(){return K("plugin:window|start_dragging",{label:this.label})}async startResizeDragging($){return K("plugin:window|start_resize_dragging",{label:this.label,value:$})}async setBadgeCount($){return K("plugin:window|set_badge_count",{label:this.label,value:$})}async setBadgeLabel($){return K("plugin:window|set_badge_label",{label:this.label,value:$})}async setOverlayIcon($){return K("plugin:window|set_overlay_icon",{label:this.label,value:$?p0($):void 0})}async setProgressBar($){return K("plugin:window|set_progress_bar",{label:this.label,value:$})}async setVisibleOnAllWorkspaces($){return K("plugin:window|set_visible_on_all_workspaces",{label:this.label,value:$})}async setTitleBarStyle($){return K("plugin:window|set_title_bar_style",{label:this.label,value:$})}async setTheme($){return K("plugin:window|set_theme",{label:this.label,value:$})}async onResized($){return this.listen(u.WINDOW_RESIZED,(Q)=>{Q.payload=new j0(Q.payload),$(Q)})}async onMoved($){return this.listen(u.WINDOW_MOVED,(Q)=>{Q.payload=new i(Q.payload),$(Q)})}async onCloseRequested($){return this.listen(u.WINDOW_CLOSE_REQUESTED,async(Q)=>{let J=new P8(Q);if(await $(J),!J.isPreventDefault())await this.destroy()})}async onDragDropEvent($){let Q=await this.listen(u.DRAG_ENTER,(H)=>{$({...H,payload:{type:"enter",paths:H.payload.paths,position:new i(H.payload.position)}})}),J=await this.listen(u.DRAG_OVER,(H)=>{$({...H,payload:{type:"over",position:new i(H.payload.position)}})}),q=await this.listen(u.DRAG_DROP,(H)=>{$({...H,payload:{type:"drop",paths:H.payload.paths,position:new i(H.payload.position)}})}),X=await this.listen(u.DRAG_LEAVE,(H)=>{$({...H,payload:{type:"leave"}})});return()=>{Q(),q(),J(),X()}}async onFocusChanged($){let Q=await this.listen(u.WINDOW_FOCUS,(q)=>{$({...q,payload:!0})}),J=await this.listen(u.WINDOW_BLUR,(q)=>{$({...q,payload:!1})});return()=>{Q(),J()}}async onScaleChanged($){return this.listen(u.WINDOW_SCALE_FACTOR_CHANGED,$)}async onThemeChanged($){return this.listen(u.WINDOW_THEME_CHANGED,$)}}var O8;(function($){$.Disabled="disabled",$.Throttle="throttle",$.Suspend="suspend"})(O8||(O8={}));var B8;(function($){$.Default="default",$.FluentOverlay="fluentOverlay"})(B8||(B8={}));var G8;(function($){$.AppearanceBased="appearanceBased",$.Light="light",$.Dark="dark",$.MediumLight="mediumLight",$.UltraDark="ultraDark",$.Titlebar="titlebar",$.Selection="selection",$.Menu="menu",$.Popover="popover",$.Sidebar="sidebar",$.HeaderView="headerView",$.Sheet="sheet",$.WindowBackground="windowBackground",$.HudWindow="hudWindow",$.FullScreenUI="fullScreenUI",$.Tooltip="tooltip",$.ContentBackground="contentBackground",$.UnderWindowBackground="underWindowBackground",$.UnderPageBackground="underPageBackground",$.Mica="mica",$.Blur="blur",$.Acrylic="acrylic",$.Tabbed="tabbed",$.TabbedDark="tabbedDark",$.TabbedLight="tabbedLight"})(G8||(G8={}));var C8;(function($){$.FollowsWindowActiveState="followsWindowActiveState",$.Active="active",$.Inactive="inactive"})(C8||(C8={}));var h8="gamepigeon:preview-resize",V2={width:520,height:740},Y2={width:720,height:780},m0={width:144,height:48},W2={width:430,height:610};function U0(){if(typeof window>"u")return!1;let $=window;return Boolean($.__TAURI_INTERNALS__||$.__TAURI__)}class b8{width;height;constructor($,Q){this.width=$,this.height=Q}}function J1($){return{width:$.width,height:$.height}}function q1($,Q){let J={type:h8,width:$,height:Q};window.parent?.postMessage(J,window.location.origin),window.dispatchEvent(new CustomEvent(h8,{detail:J}))}function X1(){return{hide:async()=>{console.info("[preview] hide")},setSize:async($)=>{let{width:Q,height:J}=J1($);q1(Q,J)},setMinSize:async()=>{},center:async()=>{},startDragging:async()=>{}}}var H2;function _8(){if(!H2)H2=U0()?q2():X1();return H2}async function b($,Q){if(U0())return K($,Q);console.info(`[preview] invoke(${$})`,Q??{});return}function G0($,Q){return U0()?new O0($,Q):new b8($,Q)}var T8="",H1="https://us.i.posthog.com/capture/";function V1(){let Q=localStorage.getItem("gamepigeon.analytics.device_id");if(Q)return Q;let J=crypto.randomUUID();return localStorage.setItem("gamepigeon.analytics.device_id",J),J}function Y1($,Q){return{distinct_id:Q,...$.data,$insert_id:$.id,$timestamp:$.time,cloud_event_id:$.id,cloud_event_source:$.source,cloud_event_specversion:$.specversion,cloud_event_datacontenttype:$.datacontenttype,...$.subject?{cloud_event_subject:$.subject}:{}}}function N4($,Q,J){let q={specversion:"1.0",id:crypto.randomUUID(),source:"/tui-gamepigeon/overlay",type:$,time:new Date().toISOString(),datacontenttype:"application/json",...J?{subject:J}:{},data:Q};(T8?fetch(H1,{method:"POST",headers:{"Content-Type":"application/json"},keepalive:!0,body:JSON.stringify({api_key:T8,event:q.type,properties:Y1(q,V1())})}):Promise.reject(Error("PostHog capture key is not configured"))).then((H)=>{if(!H.ok)throw Error("PostHog capture failed")}).catch(()=>b("record_analytics_event",{event:JSON.stringify(q)}).catch(()=>{return}))}function w8($){let Q=$.gap??8,J=$.headingHeight+$.hudHeight+$.outcomeHeight+$.mainPaddingTop+$.mainPaddingBottom+Q*($.outcomeHeight>0?3:2),q=Math.max(120,$.mainClientHeight-J),X=Math.min(540,$.mainClientWidth-24,q*1.129032258064516);return Math.max(180,Math.floor(X))}var f8="usr_pending",W1=50,K1=122880;function j1($){return`${$}_${crypto.randomUUID()}`}function g0($,Q,J){return`${Q}_${$.gameId.slice(5)}_${J}`}function D4($){return structuredClone($)}function S8($){return D4($.checkpointState?.()??$.state())}function I8($,Q,J,q=Date.now(),X={width:window.innerWidth,height:window.innerHeight}){let H=$.create(Q);return{gameId:j1("game"),gameType:$.id,gameVersion:$.version,rulesetId:Q,seed:J,startedAtMs:q,viewport:X,controlSchema:[...H.actions],actions:[]}}function K2($,Q,J,q=Date.now()){$.actions.push({action:Q,actor:J,atMs:q})}function k8($){let Q=[],J=[];for(let q of $){let X=[...J,q];if(J.length>0&&(X.length>W1||new TextEncoder().encode(JSON.stringify(X)).byteLength>K1))Q.push(J),J=[q];else J=X}if(J.length>0)Q.push(J);return Q}function x8($,Q){let J=H8($.gameType);if(!J?.create)throw Error(`Unknown recorded game: ${$.gameType}`);let q=J.create($.rulesetId);q.reset($.seed);let X=0,H=0,V=g0($,"obs",H),Y=(Z)=>Math.max(0,Math.round((Z-$.startedAtMs)*1000)),W=(Z,N,L,D)=>{return X++,{schema_version:2,user_id:f8,game_id:$.gameId,chunk_id:"chk_pending",event_id:g0($,"evt",X),event_sequence:X,event_version:1,event_type:Z,visibility:N,client_time_ms:D,monotonic_time_us:Y(D),payload:L}},U=[W("episode_started","policy",{game_type:$.gameType,game_version:$.gameVersion,ruleset_id:$.rulesetId,telemetry_version:2,platform:"overlay",viewport:$.viewport,control_schema:$.controlSchema,input_semantics:"engine_impulse"},$.startedAtMs),W("engine_checkpoint","privileged",{state_version:1,reason:"episode_start",state:S8(q),seed:$.seed},$.startedAtMs),W("observation","policy",{observation_id:V,representation:"engine_state_v1",state:D4(q.state())},$.startedAtMs)];for(let Z of $.actions){let N=q.score(),L=W("control_changed","policy",{based_on_observation_id:V,control:Z.action,action:Z.action,kind:"impulse",actor:Z.actor},Z.atMs);U.push(L);let D=q.step(Z.action);V=g0($,"obs",++H),U.push(W("observation","policy",{observation_id:V,representation:"engine_state_v1",state:D4(q.state()),caused_by_event_id:L.event_id},Z.atMs)),U.push(W("outcome_changed","policy",{score_before:N,score_after:q.score(),score_delta:q.score()-N,engine_reward:D.reward,reward_spec_id:"engine_v1",terminal:D.done,caused_by_event_id:L.event_id,progress:{moved:D.moved,success:D.success}},Z.atMs)),U.push(W("engine_checkpoint","privileged",{state_version:1,reason:D.done?"terminal":D.randomEffects===void 0?"periodic":"random_outcome",state:S8(q),...D.randomEffects===void 0?{}:{random_effects:D4(D.randomEffects)},caused_by_event_id:L.event_id},Z.atMs))}if(Q){let{reason:Z,endedAtMs:N}=Q;U.push(W("episode_ended","policy",{reason:Z,final_event_sequence:X+1,final_score:q.score(),duration_us:Y(N),completed:Z==="game_over"||Z==="won"||Z==="lost"},N))}return U}function E8($,Q,J){return Q.map((q,X)=>{let H=g0($,"chk",X+1),V=q.map((Y)=>({...Y,chunk_id:H}));return{schema_version:2,user_id:f8,game_id:$.gameId,game_type:$.gameType,game_version:$.gameVersion,chunk_id:H,chunk_sequence:X+1,first_event_sequence:V[0].event_sequence,last_event_sequence:V.at(-1).event_sequence,event_count:V.length,created_at_ms:V.at(-1).client_time_ms,client:{platform:"tui",application_version:J,recording_sdk_version:"2"},events:V}})}function u8($,Q,J,q=Date.now()){let X=x8($,{reason:Q,endedAtMs:q});return E8($,k8(X),J)}function y8($,Q){let J=k8(x8($,null));return E8($,J.slice(0,-1),Q)}function p8($){if($.completedScore===void 0||$.endedAtMs===void 0)return null;return{result_id:g0($,"res",1),game_id:$.gameId,game_type:$.gameType,score:$.completedScore,completed_at:new Date($.endedAtMs).toISOString()}}function m8(){let $=document.querySelector("#update-banner"),Q=document.querySelector("#update-from"),J=document.querySelector("#update-to"),q=document.querySelector("#update-run"),X=document.querySelector("#update-status");if(!$||!Q||!J||!q||!X)return null;return{banner:$,from:Q,to:J,button:q,status:X}}function L4($,Q,J=""){$.button.disabled=Q==="running"||Q==="done",$.status.textContent=J,$.status.dataset.state=Q,$.banner.dataset.state=Q}async function Z4(){let $=m8();if(!$)return;try{let Q=await b("read_update_flag");if(!Q?.fromVersion||!Q?.toVersion){$.banner.hidden=!0;return}$.from.textContent=Q.fromVersion,$.to.textContent=Q.toVersion,$.banner.hidden=!1,L4($,"idle")}catch{$.banner.hidden=!0}}function g8(){let $=m8();if(!$)return;$.button.addEventListener("click",async()=>{L4($,"running","Updating…");try{let Q=await b("run_plugin_update");L4($,"done",Q),window.setTimeout(()=>{$.banner.hidden=!0},8000)}catch(Q){let J=Q instanceof Error?Q.message:String(Q);L4($,"error",J||"Update failed.")}})}var d=null,J0=null;function j2(){return d}function U2(){return d!==null}async function N2(){try{d=await b("read_auth_session")??null}catch{d=null}return d}function U1($){return $.replace(/[&<>"']/g,(Q)=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[Q])}function v8(){return`<section class="arcade-menu gate-screen">
37
+ <header class="menu-heading gate-heading"><div><p>Welcome</p><h1>Arcade</h1></div></header>
38
+ <div class="gate-welcome">
39
+ <p>Sign in to play a familiar game and keep your scores between sessions.</p>
40
+ </div>
41
+ <div class="gate-actions">
42
+ <span id="auth-signin-status" class="auth-signin-status" data-state="idle"></span>
43
+ <button id="auth-signin" type="button" class="auth-signin-button">Sign in</button>
44
+ <button id="auth-signin-cancel" type="button" class="auth-signin-cancel" hidden>Cancel</button>
45
+ </div>
46
+ </section>`}function A4(){let $=document.querySelector("#account-chip");if(!$)return;if(d)$.hidden=!1,$.dataset.state="in",$.dataset.sync=J0?"error":"ready",$.title=J0??"Click to sign out",$.setAttribute("aria-label",J0?`Signed in as ${d.email}. ${J0}`:`Signed in as ${d.email}. Click to sign out.`),$.setAttribute("aria-haspopup","dialog"),$.innerHTML=`<span class="account-dot" aria-hidden="true"></span><span class="account-email">${U1(J0?"Sync paused":d.email)}</span>`;else $.hidden=!0,$.dataset.state="out",delete $.dataset.sync,$.title="",$.removeAttribute("aria-label"),$.removeAttribute("aria-haspopup"),$.innerHTML=""}function D2(){let $=document.querySelector("#auth-signin-status");if($&&!d)$.dataset.state="idle",$.textContent=""}function C0($,Q=""){let J=document.querySelector("#auth-signin-status"),q=document.querySelector("#auth-signin"),X=document.querySelector("#auth-signin-cancel");if(J)J.dataset.state=$,J.textContent=Q;if(q)q.disabled=$==="pending";if(X)X.hidden=$!=="pending"}var P0=!1;async function d8(){if(P0)return!1;P0=!0,C0("pending","Opening your browser...");try{return await b("start_auth_login"),C0("pending","Waiting for you to finish signing in..."),!0}catch($){P0=!1;let Q=$ instanceof Error?$.message:String($);return C0("error",Q||"Could not start sign-in. Try again."),!1}}async function c8(){if(!P0)return;P0=!1,C0("idle",""),await b("cancel_auth_login")}function L2(){P0=!1}async function o8(){await b("sign_out"),d=null,J0=null}function l8($){d=$,J0=null}function F4($){J0=$,A4()}function N1($){if(!$||typeof $!=="object")return!1;let Q=$;return Q.schemaVersion===1&&typeof Q.ownerId==="string"&&typeof Q.gameId==="string"&&typeof Q.gameVersion==="string"&&typeof Q.variationId==="string"&&Number.isInteger(Q.seed)&&Array.isArray(Q.actions)&&Q.actions.length<=50000&&Q.actions.every((J)=>typeof J==="string")}function z4($=localStorage){try{let Q=$.getItem("gamepigeon.arcade.active-game.v1");if(!Q)return null;let J=JSON.parse(Q);return N1(J)?J:null}catch{return null}}function Z2($,Q=localStorage){try{Q.setItem("gamepigeon.arcade.active-game.v1",JSON.stringify($))}catch{}}function A2($=localStorage){try{$.removeItem("gamepigeon.arcade.active-game.v1")}catch{}}function F2($,Q){if(!$.create||Q.gameId!==$.id||Q.gameVersion!==$.version)return null;let J=$.create(Q.variationId);J.reset(Q.seed);let q=[];for(let X of Q.actions){if(!J.actions.includes(X))return null;if(J.step(X).moved)q.push(X)}return{game:J,actions:q}}var n=_8(),D1=document.querySelector(".titlebar"),M=document.querySelector("#screen"),z2=document.querySelector("#resize"),C2=document.querySelector("#pill"),N0=document.querySelector("#return-prompt"),s8=document.querySelector("#return-title"),M2=document.querySelector("#continue-game"),L1=document.querySelector("#return-menu");function e8($){switch($.key){case"ArrowUp":return"up";case"ArrowDown":return"down";case"ArrowLeft":return"left";case"ArrowRight":return"right";case"Enter":return"enter";case"Backspace":return"backspace"}if($.key.length!==1)return null;let Q=$.key.toLowerCase();if(Q==="w")return"up";if(Q==="s")return"down";if(Q==="a")return"left";if(Q==="d")return"right";if(Q==="q")return"quit";if(Q==="r")return"restart";return{char:$.key}}function $6($){if($==="left")return"left";if($==="right")return"right";if($==="down")return"soft-drop";if($==="up")return"rotate-cw";if(typeof $==="object"){let Q=$.char.toLowerCase();if(Q==="h")return"left";if(Q==="l")return"right";if(Q==="j")return"soft-drop";if(Q==="k"||Q==="x")return"rotate-cw";if(Q==="z")return"rotate-ccw";if(Q===" ")return"hard-drop"}return null}var z="gate",c=-1,w=0,F,j,M4,h0=!1,c0=!1,r,k,R4=0,D0=0,R2=!1,O4,p,B4={personal_bests:[],recent:[],top_scores:[]},O2={personal_bests:[{game_type:"2048",score:1384},{game_type:"tetris",score:9250},{game_type:"minesweeper",score:54},{game_type:"snake",score:18}],recent:[["2048","classic",1384,"2026-07-26T20:12:00.000Z"],["tetris","classic",9250,"2026-07-26T18:46:00.000Z"],["2048","classic",1304,"2026-07-25T22:10:00.000Z"],["snake","classic",18,"2026-07-25T19:15:00.000Z"],["minesweeper","classic",54,"2026-07-24T17:04:00.000Z"],["2048","classic",1036,"2026-07-23T21:48:00.000Z"]].map(([$,Q,J,q])=>({game_type:$,variation_id:Q,score:J,completed_at:q})),top_scores:[]};O2.top_scores=O2.recent.slice().sort(($,Q)=>Q.score-$.score).slice(0,10);var P2="gamepigeon:recording:";function G4($){try{localStorage.setItem(`${P2}${$.gameId}`,JSON.stringify($))}catch{}}function Q6(){return"0.2.6"}var Z1=5000,b0;function A1($){if(b0!==void 0)return;b0=window.setTimeout(()=>{if(b0=void 0,p===$)q6($)},Z1)}function J6(){if(b0!==void 0)window.clearTimeout(b0);b0=void 0}function q6($){try{let Q=y8($,Q6()),J=$.flushedChunks??0,q=Q.slice(J);if(q.length===0)return;$.flushedChunks=Q.length,G4($),b("queue_recording_chunks",{chunks:q,result:null}).catch(()=>{$.flushedChunks=J})}catch{}}function X6($,Q,J){try{$.endReason??=Q,$.endedAtMs??=Date.now(),$.completedScore??=J,G4($);let q=u8($,$.endReason,Q6(),$.endedAtMs);b("queue_recording_chunks",{chunks:q,result:p8($)}).then(()=>{localStorage.removeItem(`${P2}${$.gameId}`)}).catch(()=>{})}catch{}}function H6(){let $=[];for(let Q=0;Q<localStorage.length;Q++){let J=localStorage.key(Q);if(!J?.startsWith(P2))continue;try{$.push(JSON.parse(localStorage.getItem(J)))}catch{}}for(let Q of $)X6(Q,Q.endReason??"client_closed")}var I,o;function m($){return $.replace(/[&<>"']/g,(Q)=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[Q])}function F1($){if($.variation_id==="classic")return"";return y.find((Q)=>Q.id===$.game_type)?.variations.find((Q)=>Q.id===$.variation_id)?.title??$.variation_id}function z1($,Q){let J=$.variations[Q];if(!J||J.id==="classic"||$.variations.length===1)return null;return J.title}function M1($,Q){let J=z1($,Q),q=J?`<small class="mode-title">${m(J)}</small>`:"";return`<strong class="game-title">${m($.title)}</strong>${q}`}function R1($){let Q=new Date($);if(Number.isNaN(Q.getTime()))return"Completed run";return new Intl.DateTimeFormat(void 0,{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"}).format(Q)}function X0($,Q){let J=B4.personal_bests.find((q)=>q.game_type===$)?.score;return Q===void 0?J:Math.max(J??Q,Q)}function o0(){b("read_local_scores").then(($)=>{if(!$||!Array.isArray($.personal_bests)||!Array.isArray($.recent)||!Array.isArray($.top_scores))return;if(B4=$,z==="menu")e();else if(z==="variations")h2();else if(z==="scores")W6();else if(z==="game"&&k!=="game-over")b2()}).catch(()=>{return})}function O1($,Q){let J=X8.includes($.id),q=X0($.id);return`<button type="button" class="game-card${J?" featured":""}${Q===c?" selected":""}" data-game-index="${Q}">
47
+ <span class="game-icon icon-${$.id}" aria-hidden="true"></span>
48
+ <span><strong>${m($.title)}</strong><small>${m($.description)}</small></span>
49
+ <b aria-label="${q===void 0?"No personal best yet":`Personal best ${q}`}">${q===void 0?"Best —":`Best ${q}`} →</b>
50
+ </button>`}function e(){let $=I?`<button type="button" class="inline-back" data-resume>▶ Resume ${m(I.gameId)}</button>`:"";M.innerHTML=`<section class="arcade-menu">
51
+ <header class="menu-heading"><div><p>Choose a game</p><h1>Arcade</h1>${$}</div><button type="button" class="scores-button" data-open-scores aria-label="Open personal leaderboard">Scores</button></header>
52
+ <div class="game-list">${y.map(O1).join("")}</div>
53
+ </section>`,M.dataset.screen="menu"}function V6(){z="gate",M.innerHTML=v8(),M.dataset.screen="gate",A4(),D2()}function Y6($){l8($),c=-1,z="menu",e(),U6($.id),A4(),D2()}function h2(){if(!F)return;let $=F,Q=X0($.id);M.innerHTML=`<section class="variation-menu">
54
+ <header class="menu-heading"><button type="button" id="inline-back" class="inline-back">‹ Games</button><div><p>Mode</p><h1>${m($.title)}</h1></div></header>
55
+ <div class="variation-list">${$.variations.map((J,q)=>`<button type="button" class="variation-card${q===w?" selected":""}" data-variation-index="${q}">
56
+ <span><strong>${m(J.title)}</strong><small>${m(J.description)}</small></span><b>${m(J.goal)}${Q===void 0?"":`<em>Best ${Q}</em>`}</b>
57
+ </button>`).join("")}</div>
58
+ </section>`,M.dataset.screen="variations"}function W6(){z="scores";let $=y.map((Q)=>{let J=X0(Q.id),q=B4.recent.filter((X)=>X.game_type===Q.id);return`<article class="leaderboard-card">
59
+ <header><span class="game-icon icon-${Q.id}" aria-hidden="true"></span><div><strong>${m(Q.title)}</strong><small>Personal best</small></div><b>${J??"—"}</b></header>
60
+ <ol class="run-list">${q.map((X)=>{let H=[F1(X),R1(X.completed_at)].filter(Boolean).map(m).join(" · ");return`<li><b>${X.score}</b><small>${H}</small></li>`}).join("")||"<li class=empty>Play a run to set your first score.</li>"}</ol>
61
+ </article>`}).join("");M.innerHTML=`<section class="scores-menu">
62
+ <header class="menu-heading"><button type="button" id="inline-back" class="inline-back">‹ Games</button><div><p>Your local arcade record</p><h1>Personal leaderboard</h1><small>Best scores and completed runs on this device.</small></div></header>
63
+ <div class="leaderboard-grid">${$}</div>
64
+ </section>`,M.dataset.screen="scores"}var _={fast:110,travel:150,base:190,slide:240,slow:320,trail:360},i8=new WeakMap;function x($,Q,J){if($.length===0)return;let q=$.filter((X)=>X.classList.contains(Q));for(let X of q)X.classList.remove(Q);if(q.length>0)q[0].offsetWidth;for(let X of $){X.classList.add(Q);let H=i8.get(X);if(!H)i8.set(X,H=new Map);window.clearTimeout(H.get(Q)),H.set(Q,window.setTimeout(()=>{X.classList.remove(Q),H.delete(Q)},J))}}function l0($,Q,J){if($.dataset.base===Q)return;$.dataset.base=Q;let q=J.filter((X)=>$.classList.contains(X));$.className=q.length>0?`${Q} ${q.join(" ")}`:Q}function s0($,Q){if($.textContent!==Q)$.textContent=Q}function K6($,Q){if($.getAttribute("aria-label")!==Q)$.setAttribute("aria-label",Q)}function T0($){let Q=M.querySelectorAll(".game-hud span strong");$.forEach((J,q)=>{let X=Q[q];if(X)s0(X,J)})}function B2($,Q,J){$.style.setProperty("--dx",String(Q)),$.style.setProperty("--dy",String(J))}var B1=["up","down","left","right"];function G1($,Q){let J=M.querySelector(".board-2048");if(!J)return!1;let q=$.state();T0([String(q.score)]);let X=Array.from(J.querySelectorAll(".tile")),H=q.board.flat();if(X.length!==H.length)return!1;let V=Q&&B1.includes(Q.action)?Q.prev:void 0,Y=V?K8(V.board,Q.action):[],W=new Map;for(let D of Y){if(D.from===D.to)continue;let A=X[D.from],R=X[D.to],C={dx:A.offsetLeft-R.offsetLeft,dy:A.offsetTop-R.offsetTop},S=W.get(D.to),h=(L0)=>Math.abs(L0.dx)+Math.abs(L0.dy);if(!S||h(C)>h(S))W.set(D.to,C)}let U=new Set(Y.filter((D)=>D.merged).map((D)=>D.to)),Z=[],N=[],L=[];for(let D=0;D<H.length;D++){let A=X[D],R=H[D]??0,C=Number(A.dataset.value??"0");if(R!==C){let h=document.createElement("div");h.className=`tile tile-${R||"empty"}`,h.dataset.cell=String(D),h.dataset.value=String(R),h.setAttribute("aria-label",R?String(R):"empty"),h.textContent=R?String(R):"",A.replaceWith(h),X[D]=h,A=h}let S=W.get(D);if(S)A.style.setProperty("--dx",`${S.dx}px`),A.style.setProperty("--dy",`${S.dy}px`),Z.push(A);if(U.has(D))N.push(A);else if(R!==0&&C===0&&!S)L.push(A)}return x(Z,"tile-slid",_.slide),x(N,"tile-merged",_.slide),x(L,"tile-new",_.slide),!0}var C1=["shifted","spun","locked"];function P1($,Q,J){for(let q of J){let X=Q[q*T],H=Q[q*T+T-1];if(!X||!H)continue;let V=document.createElement("i");V.className="tetris-line-flash",V.setAttribute("aria-hidden","true"),V.style.left=`${X.offsetLeft}px`,V.style.top=`${X.offsetTop}px`,V.style.width=`${H.offsetLeft+H.offsetWidth-X.offsetLeft}px`,V.style.height=`${X.offsetHeight}px`,$.append(V),window.setTimeout(()=>V.remove(),_.slow)}}function h1($,Q){let J=M.querySelector(".board-tetris");if(!J)return!1;let q=$.state();T0([String(q.score),String(q.lines),String(q.level)]);let X=l4(q),H=Array.from(J.querySelectorAll(".tetromino"));if(H.length!==X.length)return!1;let V=Q?.prev,Y=V?j8(V.board,V.active,q.board):null;if(Y&&Y.clearedRows.length>0)P1(J,H,Y.clearedRows);for(let N=0;N<X.length;N++)l0(H[N],s4(X[N]??null),C1);let W=M.querySelectorAll(".next-pieces b");if(q.next.slice(0,W.length).forEach((N,L)=>{let D=W[L];l0(D,`piece-${N}`,[]),s0(D,N)}),Y)return x(Y.cells.map((N)=>H[N]).filter((N)=>!!N),"locked",_.base),!0;let U=q.active;if(!U||!V?.active)return!0;let Z=a(U).filter(([,N])=>N>=0).map(([N,L])=>H[L*T+N]).filter((N)=>!!N);if(U.rotation!==V.active.rotation){let N=(U.rotation-V.active.rotation+4)%4===1?1:-1;for(let L of Z)L.style.setProperty("--spin",String(N));x(Z,"spun",_.base)}else if(U.x!==V.active.x||U.y!==V.active.y){for(let N of Z)B2(N,U.x-V.active.x,U.y-V.active.y);x(Z,"shifted",_.fast)}return!0}var b1=["revealing","detonating","flagging"];function _1($,Q){let J=M.querySelector(".board-mines");if(!J)return!1;let q=$.state(),X=q.view[0]?.length??0,H=Array.from(J.querySelectorAll(".mine-cell"));if(X===0||H.length!==X*q.view.length)return!1;let V=q.view.flat().filter((N)=>N===-2).length;T0([String(Math.max(0,q4-V))]);let Y=Q?.prev,W=Y?U8(Y.view,q.view):null,U=W?N8(W.revealed,Y.cursor.y*X+Y.cursor.x,X):null;if(q.view.forEach((N,L)=>N.forEach((D,A)=>{let R=H[L*X+A],{className:C,content:S,label:h}=i4(D),L0=A===q.cursor.x&&L===q.cursor.y;l0(R,`${C}${L0?" selected":""}`,b1),s0(R,S),K6(R,`Row ${L+1}, column ${A+1}, ${h}`)})),!W)return!0;let Z=(N)=>N.map((L)=>H[L]).filter((L)=>!!L);for(let[N,L]of U??[])H[N]?.style.setProperty("--step",String(L));return x(Z(W.revealed),"revealing",_.base+22*Math.max(0,...U?.values()??[0])),x(Z(W.flagged),"flagging",_.base),x(Z(W.exploded),"detonating",_.slow),!0}function T1($,Q,J){let q=(Y)=>String(Math.round(Y*1000)/1000),X=$.querySelector(".snake-blocks");if(X){while(X.childElementCount>Q.length)X.lastElementChild?.remove();while(X.childElementCount<Q.length){let Y=document.createElementNS("http://www.w3.org/2000/svg","rect");Y.setAttribute("class","snake-seg"),Y.setAttribute("width",String(u0)),Y.setAttribute("height",String(u0)),X.append(Y)}Q.forEach((Y,W)=>{let U=X.children[W];if(!U)return;U.setAttribute("x",q(Y.x+z0)),U.setAttribute("y",q(Y.y+z0))})}let H=$.querySelectorAll(".snake-eye"),V=r4(Q,J);H.forEach((Y,W)=>{let U=V[W];if(!U)return;Y.setAttribute("x",q(U.x-V0/2)),Y.setAttribute("y",q(U.y-V0/2))})}function w1($){let Q=M.querySelector(".board-snake"),J=Q?.querySelector(".snake-svg");if(!Q||!J)return!1;let q=$.state();T0([String(q.score)]);let X=(H)=>String(Math.round((H+0.5)*1000)/1000);return J.querySelector(".snake-food")?.setAttribute("transform",`translate(${X(q.food.x)} ${X(q.food.y)})`),T1(J,q.snake,q.dir),!0}var S1=["stepped","pushed","snapped"];function f1($,Q){let J=M.querySelector(".board-sokoban");if(!J)return!1;let q=$.state(),X=H0(l[q.level]);T0([`${q.level+1}/${l.length}`,String(q.moves),String(q.pushes)]);let H=Array.from(J.querySelectorAll(".sokoban-cell"));if(H.length!==X.width*X.height)return!1;let V=new Set(q.boxes),Y=new Set(q.goals);for(let R=0;R<H.length;R++){let C=R%X.width,S=Math.floor(R/X.width),h=`${C},${S}`,L0=q.player.x===C&&q.player.y===S,G6=V.has(h),P4=Y.has(h),C6=X.walls.has(h)?"wall":L0?`player${P4?" goal":""}`:G6?`box${P4?" goal":""}`:P4?"goal":"floor";l0(H[R],`sokoban-cell ${C6}`,S1)}let W=Q?.prev;if(!W)return!0;let U=D8(W,q);if(!U.step)return!0;let Z=(R,C)=>H[C*X.width+R],N=Z(q.player.x,q.player.y);if(N)B2(N,U.step.dx,U.step.dy),x([N],"stepped",_.base);if(!U.pushedBox)return!0;let[L,D]=U.pushedBox.split(",").map(Number),A=Z(L,D);if(!A)return!0;if(B2(A,U.step.dx,U.step.dy),x([A],"pushed",_.base),U.landedOnGoal)window.setTimeout(()=>x([A],"snapped",_.slow),_.base);return!0}var I1=["placed","erased","unit-done"];function k1($,Q){let J=M.querySelector(".board-sudoku");if(!J)return!1;let q=$.state();T0([String(q.filled),String(q.correct)]);let X=Array.from(J.querySelectorAll(".sudoku-cell")),H=q.grid.length;if(X.length!==H*H)return!1;let V=k0(q.grid);q.grid.forEach((N,L)=>N.forEach((D,A)=>{let R=X[L*H+A],C=q.givens[L][A]!==0,S=q.cursor.row===L&&q.cursor.col===A;l0(R,n4(C,V.has(`${L},${A}`),S),I1),s0(R,D?String(D):""),K6(R,`Row ${L+1}, column ${A+1}${D?`, ${D}`:", empty"}`)}));let Y=Q?.prev;if(!Y)return!0;let W=L8(Y.grid,q.grid);if(W.cell===null)return!0;let U=X[W.cell];if(U)x([U],W.placed?"placed":"erased",W.placed?_.base:_.fast);if(W.completed.length===0)return!0;let Z=W.completed.map((N)=>X[N]).filter((N)=>!!N);return W.completed.forEach((N,L)=>X[N]?.style.setProperty("--step",String(L))),x(Z,"unit-done",_.slow+34*W.completed.length),!0}var x1={"2048":G1,tetris:h1,minesweeper:_1,snake:w1,sokoban:f1,connect4:o1,sudoku:k1};function E1(){if(!j||!F)return;let $=M.querySelector(".playing-heading .personal-best");if(!$)return;let Q=X0(F.id,j.score());if($.hidden=!Q,Q)s0($,`Personal best ${Q}`)}function j6(){if(!j||!F)return;let $=X0(F.id,j.score());if(M.innerHTML=`<header class="playing-heading"><button type="button" id="inline-back" class="inline-back">‹ Menu</button><div>${M1(F,w)}<small class="personal-best"${$?"":" hidden"}>Personal best ${$??""}</small></div><button type="button" data-restart aria-label="Restart game">↻ Restart</button></header>${W8(j)}`,M.dataset.screen="game",M.dataset.game=j.name,j.name==="connect4")i0()}function b2($){if(!j||!F)return;if(!(M.dataset.game===j.name?x1[j.name]:void 0)?.(j,$)){j6();return}E1()}function i0(){let $=document.querySelector(".connect-wrap"),Q=document.querySelector("main");if(!$||!Q||j?.name!=="connect4")return;let J=getComputedStyle(Q),q=w8({mainClientHeight:Q.clientHeight,mainClientWidth:Q.clientWidth,mainPaddingTop:parseFloat(J.paddingTop),mainPaddingBottom:parseFloat(J.paddingBottom),headingHeight:document.querySelector(".playing-heading")?.offsetHeight??0,hudHeight:document.querySelector(".game-hud")?.offsetHeight??0,outcomeHeight:0});$.style.setProperty("--connect-board-width",`${q}px`)}function u1($){if($ instanceof s)return $.gravityMs();return $.tickMs?$.tickMs():null}function w0(){if(M4)clearTimeout(M4);M4=void 0}function r0(){if(!j||j.isOver())return;let $=u1(j);if($===null)return;w0();let Q=j;M4=setTimeout(()=>{if(z!=="game"||j!==Q||Q.isOver())return;g("tick"),r0()},$)}function S0($,Q,J){n0("abandoned","restart"),w0(),F=$;let q=J?F2($,J):null,X=(Date.now()^Math.random()*4294967295)>>>0;if(j=q?.game??$.create(Q),!q)j.reset(X);if(I=q?{...J,actions:q.actions}:{schemaVersion:1,ownerId:j2()?.id??"",gameId:$.id,gameVersion:$.version,variationId:Q,seed:X,actions:[]},Z2(I),R4=Date.now(),D0=I.actions.length,R2=!1,O4=crypto.randomUUID(),J6(),U0()){p=I8($,Q,I.seed);for(let H of I.actions)K2(p,H,H==="tick"||H==="bot_move"?"environment":"human");G4(p),q6(p)}N4("game.started",{game_type:$.id,variation_id:Q},O4),z="game",f0(),j6(),r0()}function U6($=j2()?.id??""){let Q=I??z4();if(!Q||Q.ownerId!==$)return;let J=y.find((X)=>X.id===Q.gameId);if(!J||!W4(J))return;let q=J.variations.find((X)=>X.id===Q.variationId);if(!q)return;if(!F2(J,Q)){A2(),I=void 0,e();return}c=y.indexOf(J),F=J,w=J.variations.indexOf(q),S0(J,q.id,Q)}function C4(){if(F)S0(F,F.variations[w]?.id??F.variations[0].id)}function _0(){n0("abandoned","user_quit"),w0(),j=void 0,z="menu",f0(),delete M.dataset.game,e()}function n0($,Q=j?.hasWon()?"won":"game_over"){if(!j||!F||R2)return;R2=!0;let J=Date.now(),q=F.variations[w]?.id??"classic",X=V8({outcome:$,gameId:p?.gameId??`game_${O4??crypto.randomUUID()}`,gameType:F.id,variationId:q,score:j.score(),success:j.hasWon(),endedAtMs:J,startedAtMs:R4,platform:"overlay"});if(X)b("append_local_score",{score:X}).then(o0).catch(()=>{return});if($==="completed")A2(),I=void 0;if(N4("game.ended",{game_type:F.id,variation_id:q,outcome:$,score:j.score(),success:$==="completed"&&j.hasWon(),duration_ms:Math.max(0,J-R4),actions_taken:D0},O4),p){let H=p;p=void 0,J6(),X6(H,Q,$==="completed"?j.score():void 0)}}function r8(){if(!j)return"Game over";if(j.name==="connect4")return M0(j.state()).label;return j.hasWon()?"You won!":"Game over"}function n8(){if(j?.name!=="connect4")return j?.hasWon()?"win":void 0;let $=M0(j.state()).tone;return $==="play"?void 0:$}function y1(){if(j?.isOver()&&k!=="game-over"){n0("completed");let $=j.name==="minesweeper"&&!j.hasWon()?1500:j.name==="connect4"?2000:0,Q=()=>{if(z==="game"&&j&&j.isOver()&&k!=="game-over")N6("game-over")};if($>0)setTimeout(Q,$);else Q()}}function p1(){if(!j)return"";let $=Math.max(0,Math.floor((Date.now()-R4)/1000));switch(j.name){case"2048":{let Q=j.state();return`${Q.score} points in ${D0} moves (personal best: ${X0(F?.id??"",Q.score)??Q.score}; highest tile: ${Q.highest})`}case"tetris":{let Q=j.state();return`${Q.score} points (personal best: ${X0(F?.id??"",Q.score)??Q.score}), ${Q.lines} lines cleared (level ${Q.level})`}case"minesweeper":return`${j.state().revealed} cells revealed in ${D0} moves (${$}s)`;case"snake":{let Q=j.state();return`${Q.score} points (personal best: ${X0(F?.id??"",Q.score)??Q.score}), length ${Q.snake.length} (${D0} moves)`}case"sokoban":{let Q=j.state();return`Level ${Q.level+1}, ${Q.moves} moves, ${Q.pushes} pushes`}case"connect4":return`${D0} moves made`;case"sudoku":{let Q=j.state();return`${Q.filled}/81 cells filled (${Q.correct} correct)`}default:return""}}function f0(){k=void 0,N0.hidden=!0,N0.dataset.tone="";let $=M.querySelector(".game-end-overlay");if($)$.remove();if(z==="game")r0()}function N6($){if(k=$,$==="agent")s8.textContent="Paused",N0.dataset.tone="",M2.innerHTML="Continue playing",N0.hidden=!1,document.querySelector("#return-code").focus();else{N0.hidden=!0;let Q=M.querySelector(".board");if(Q){let J=Q.querySelector(".game-end-overlay");if(J)J.remove();let q=document.createElement("div");q.className="game-end-overlay";let X=n8();if(X)q.dataset.tone=X;q.innerHTML=`
65
+ <div class="game-end-content">
66
+ <h2 class="game-end-title">${m(r8())}</h2>
67
+ <p class="game-end-stats">${m(p1())}</p>
68
+ <div class="game-end-actions">
69
+ <button type="button" class="primary" data-restart><kbd>R</kbd> New run</button>
70
+ <button type="button" data-action="menu"><kbd>M</kbd> Menu</button>
71
+ <button type="button" data-action="return-code"><kbd>Enter</kbd> Coding</button>
72
+ </div>
73
+ </div>
74
+ `,Q.appendChild(q),q.querySelector("[data-restart]")?.focus()}else s8.textContent=r8(),N0.dataset.tone=n8()??"",M2.innerHTML="<kbd>R</kbd> New run",N0.hidden=!1,document.querySelector("#return-code").focus()}}async function _2(){f0(),await n.hide()}function t8($){if(c===-1)c=$>0?0:y.length-1;else c=(c+$+y.length)%y.length;e(),M.querySelector(`[data-game-index="${c}"]`)?.focus()}function m1($){if($==="up"||$==="left")t8(-1);else if($==="down"||$==="right")t8(1);else if($==="enter")L6(c);else if($==="quit")n.hide()}function D6($,Q="classic"){let J=y.findIndex((H)=>H.id===$);if(J<0)return;let q=y[J];if(!q||!W4(q))return;c=J,F=q;let X=q.variations.findIndex((H)=>H.id===Q);w=X>=0?X:0,S0(q,q.variations[w].id)}function L6($){let Q=y[$];if(!Q||!W4(Q))return;if(c=$,F=Q,w=0,Q.variations.length===1)S0(Q,Q.variations[0].id);else z="variations",h2()}function g1($){if(!F)return;if($==="up"||$==="left")w=(w-1+F.variations.length)%F.variations.length;else if($==="down"||$==="right")w=(w+1)%F.variations.length;else if($==="enter")return S0(F,F.variations[w].id);else if($==="quit"){z="menu",e();return}h2()}function v1($){if($==="quit")z="menu",e()}function Z6($){if(!j)return null;let Q=typeof $==="string"?$:$.char===" "?"space":$.char.toLowerCase(),J=j.keymap?.[Q]??Q;return j.actions.includes(J)?J:null}function A6(){document.querySelectorAll(".board-connect .disc.preview").forEach(($)=>$.classList.remove("preview"))}function d1($){if(!j||j.name!=="connect4"||j.isOver())return;let Q=j.state();if(Q.board[0][$]!==0)return;A6();for(let J=Q.board.length-1;J>=0;J--)if(Q.board[J][$]===0){document.querySelector(`.board-connect .disc[data-cell="${J*7+$}"]`)?.classList.add("preview");break}}function F6($,Q){let J=document.querySelector(`.connect-col[data-column="${$}"]`);if(!J)return;J.classList.remove("shake"),J.classList.toggle("column-full",Q==="full"),J.offsetWidth,J.classList.add("shake"),window.setTimeout(()=>{J.classList.remove("shake"),J.classList.remove("column-full")},450)}function c1($){let Q=$.state(),{label:J,tone:q}=M0(Q),X=document.querySelector(".game-connect4 .game-hud span:first-child strong");if(X){if(X.textContent=J,X.classList.remove("outcome-win","outcome-loss","outcome-draw"),q!=="play")X.classList.add(`outcome-${q}`)}let H=document.querySelector(".game-connect4");if(H?.classList.remove("game-tone-win","game-tone-loss","game-tone-draw"),q!=="play")H?.classList.add(`game-tone-${q}`);let V=document.querySelector(".connect-outcome");if(Q.result!==0){if(!V)V=document.createElement("div"),V.className="connect-outcome",V.setAttribute("role","status"),document.querySelector(".connect-wrap")?.prepend(V);V.className=`connect-outcome outcome-${q}`,V.textContent=J}else V?.remove();i0()}function o1($,Q){let J=document.querySelector(".board-connect");if(!J)return!1;let q=$.state(),X=Q?.prev,H=X?Z8(X.board,q.board):null;if(q.board.forEach((V,Y)=>{V.forEach((W,U)=>{let Z=Y*7+U,N=J.querySelector(`.disc[data-cell="${Z}"]`);if(!N)return;N.classList.remove("preview");let L=W===1?"disc-1":W===2?"disc-2":"disc-0";if(!N.classList.contains(L))if(W!==0)N.className=`disc ${L} falling`,N.style.setProperty("--row",String(Y));else N.className=`disc ${L}`})}),H!==null){J.querySelectorAll(".disc.landed").forEach((Y)=>Y.classList.remove("landed"));let V=J.querySelector(`.disc[data-cell="${H}"]`);if(V)x([V],"landed",950)}return document.querySelectorAll(".connect-col").forEach((V,Y)=>{V.classList.toggle("selected",Y===q.cursor),V.classList.toggle("full",q.board[0][Y]!==0)}),c1($),!0}function g($){if(!j||j.isOver()||!j.actions.includes($))return!1;let Q=j.state(),J=l1($,$==="tick"||$==="bot_move"?"environment":"human");if(D0++,J.moved&&I)I.actions.push($),Z2(I);if(j.name==="connect4"&&$==="drop"&&!J.moved)return F6(Q.cursor,"full"),!1;if(b2({action:$,prev:Q}),y1(),j.name==="connect4"&&$==="drop"&&!j.isOver())setTimeout(()=>{if(z==="game"&&j&&!j.isOver())g("bot_move")},700);return J.moved}function l1($,Q){if(!j)throw Error("No active game");let J=j.step($);if(p)K2(p,$,Q),G4(p),A1(p);return J}function z6($,Q){M.querySelector(`.control[data-action="${$}"]`)?.classList.toggle("key-pressed",Q)}function s1($){if(!j)return;if($==="quit")return _0();if($==="restart")return C4();if(j.isOver())return;let Q=j instanceof s?$6($):Z6($);if(Q)g(Q),z6(Q,!0)}function G2($){let Q=$.closest("[data-column]");if(!Q?.dataset.column)return;let J=Number(Q.dataset.column);return Number.isFinite(J)?J:void 0}function i1($){if(!j||j.name!=="connect4"||j.isOver())return;if(j.state().board[0][$]!==0){F6($,"full");return}d0($,0),g("drop")}function d0($,Q){if(!j)return;let q=j.state().cursor,X=typeof q==="number"?q:q?.x??q?.col,H=typeof q==="number"?0:q?.y??q?.row;if(X===void 0||H===void 0)return;for(let V=X;V>$;V--)g("left");for(let V=X;V<$;V++)g("right");for(let V=H;V>Q;V--)g("up");for(let V=H;V<Q;V++)g("down")}window.addEventListener("keydown",($)=>{if(c0){if($.key==="Enter"||$.key===" "||$.key==="Escape")$.preventDefault(),S2();return}if($.key==="Escape"){$.preventDefault(),T2();return}if(k){if(k==="signout"){if($.key==="Enter")O6()}else if($.key==="Enter")_2();else if(($.key==="r"||$.key==="R")&&k==="game-over")C4();else if($.key==="m"||$.key==="M")_0();$.preventDefault();return}if(z==="gate"){if($.key==="Enter")$.preventDefault(),w2();return}let Q=e8($);if(!Q)return;if($.preventDefault(),z==="menu")m1(Q);else if(z==="variations")g1(Q);else if(z==="scores")v1(Q);else s1(Q)});window.addEventListener("keyup",($)=>{if(z!=="game"||k||!j)return;let Q=e8($);if(!Q)return;let J=j instanceof s?$6(Q):Z6(Q);if(J)z6(J,!1)});M.addEventListener("click",($)=>{let Q=$.target.closest("button");if(!Q)return;if(z==="gate"){if(Q.id==="auth-signin")w2();else if(Q.id==="auth-signin-cancel"){if(o)clearTimeout(o),o=void 0;c8()}return}if(Q.id==="inline-back"){if(z==="game")_0();else if(z==="variations"||z==="scores")z="menu",e();return}if(Q.hasAttribute("data-open-scores"))return W6();if(Q.dataset.gameIndex)return L6(Number(Q.dataset.gameIndex));if(Q.hasAttribute("data-resume"))return U6();if(Q.dataset.variationIndex&&F)return w=Number(Q.dataset.variationIndex),S0(F,F.variations[w].id);if(Q.dataset.action==="menu")return _0();if(Q.dataset.action==="return-code")return void _2();if(Q.hasAttribute("data-restart"))return C4();if(Q.dataset.cellX&&Q.dataset.cellY)return d0(Number(Q.dataset.cellX),Number(Q.dataset.cellY)),g("reveal");if(Q.dataset.column&&Q.classList.contains("connect-col"))return i1(Number(Q.dataset.column));if(Q.dataset.column)return d0(Number(Q.dataset.column),0),g("drop");if(Q.dataset.cellRow&&Q.dataset.cellCol)return d0(Number(Q.dataset.cellCol),Number(Q.dataset.cellRow)),b2();if(Q.dataset.action)g(Q.dataset.action)});M.addEventListener("pointerover",($)=>{let Q=G2($.target);if(Q===void 0||!j||j.name!=="connect4"||j.isOver())return;d1(Q)});M.addEventListener("pointerout",($)=>{let Q=G2($.target),J=$.relatedTarget?G2($.relatedTarget):void 0;if(Q===void 0||!j||j.name!=="connect4")return;if(Q===J)return;A6()});M.addEventListener("contextmenu",($)=>{let Q=$.target.closest("[data-cell-x][data-cell-y]");if(!Q)return;$.preventDefault(),d0(Number(Q.dataset.cellX),Number(Q.dataset.cellY)),g("flag")});var v0;M.addEventListener("pointerdown",($)=>{v0={x:$.clientX,y:$.clientY}});M.addEventListener("pointerup",($)=>{if(!v0||j?.name!=="2048"&&j?.name!=="snake")return;let Q=$.clientX-v0.x,J=$.clientY-v0.y;if(v0=void 0,Math.max(Math.abs(Q),Math.abs(J))<30)return;g(Math.abs(Q)>Math.abs(J)?Q>0?"right":"left":J>0?"down":"up")});function M6(){return U0()&&!U2()}window.addEventListener("gamepigeon:launch",($)=>{if(M6()||z==="gate")return;let Q=$.detail;if(!Q?.game)return;D6(Q.game,Q.variation)});window.addEventListener("gamepigeon:pause",()=>{if(!M6()&&z==="game"&&!k)N6("agent")});window.addEventListener("gamepigeon:resume",()=>{if(S2(!0),k==="agent")f0()});window.addEventListener("gamepigeon:reset",()=>{if(z==="gate"){Z4();return}c=-1,w=0,F=void 0,_0(),o0(),Z4()});window.addEventListener("gamepigeon:auth-success",($)=>{if(L2(),o)clearTimeout(o),o=void 0;let Q=$.detail;N2().then((J)=>{let q=J??(Q?.email?{id:"",email:Q.email}:null);if(q)Y6(q),H6(),o0()})});window.addEventListener("gamepigeon:auth-error",($)=>{if(L2(),o)clearTimeout(o),o=void 0;let Q=$.detail;C0("error",typeof Q==="string"&&Q?Q:"Sign-in failed. Try again.")});window.addEventListener("gamepigeon:sync-success",()=>F4(null));window.addEventListener("gamepigeon:sync-error",($)=>{let Q=$.detail;F4(typeof Q==="string"&&Q?Q:"Cloud sync is paused.")});D1.addEventListener("mousedown",($)=>{let Q=$.target;if(Q instanceof HTMLElement&&Q.closest("button,a,input,select,textarea"))return;if($.buttons===1)n.startDragging()});async function T2(){if(r)await r;if(c0)return;let $=(async()=>{c0=!0,w0(),document.body.dataset.mode="pill",await n.setMinSize(G0(m0.width,m0.height)),await n.setSize(G0(m0.width,m0.height))})();r=$.finally(()=>{if(r===$)r=void 0}),await $}async function w2(){if(o)clearTimeout(o);if(await d8())o=window.setTimeout(()=>void T2(),500)}async function S2($=!1){if(r)await r;if(!c0&&!$)return;let Q=(async()=>{c0=!1,delete document.body.dataset.mode,await n.setMinSize(G0(W2.width,W2.height));let J=h0?Y2:V2;if(await n.setSize(G0(J.width,J.height)),i0(),z==="game"&&!k)r0()})();r=Q.finally(()=>{if(r===Q)r=void 0}),await Q}var q0;C2.addEventListener("mousedown",($)=>{if($.button!==0)return;q0={x:$.clientX,y:$.clientY,dragged:!1}});C2.addEventListener("mousemove",($)=>{if(!q0||q0.dragged||$.buttons!==1)return;if(Math.hypot($.clientX-q0.x,$.clientY-q0.y)<4)return;q0.dragged=!0,n.startDragging()});C2.addEventListener("click",()=>{let $=q0?.dragged??!1;if(q0=void 0,!$)S2()});document.querySelector("#hide").addEventListener("click",()=>void T2());document.querySelector("#shutdown").addEventListener("click",()=>{n0("abandoned","client_closed"),b("shutdown")});document.querySelector("#return-code").addEventListener("click",()=>void _2());M2.addEventListener("click",()=>k==="game-over"?C4():f0());L1.addEventListener("click",()=>_0());z2.addEventListener("click",async()=>{h0=!h0;let $=h0?Y2:V2;await n.setSize(G0($.width,$.height)),await n.center(),z2.textContent=h0?"↙":"↗",z2.setAttribute("aria-label",h0?"Compact overlay":"Expand overlay"),i0()});window.addEventListener("resize",()=>i0());async function r1(){n0("abandoned","user_quit");try{await o8()}catch($){let Q=$ instanceof Error?$.message:String($),J=document.querySelector("#account-chip");if(J)J.title=`Sign out failed: ${Q}`;return}F=void 0,j=void 0,w0(),f0(),V6()}function n1(){k="signout",w0();let $=document.getElementById("signout-prompt");if($)$.hidden=!1,document.getElementById("signout-cancel")?.focus()}function R6(){k=void 0;let $=document.getElementById("signout-prompt");if($)$.hidden=!0;if(z==="game")r0()}async function O6(){R6(),await r1()}document.querySelector("#account-chip")?.addEventListener("click",()=>{if(U2())n1();else w2()});document.getElementById("signout-confirm")?.addEventListener("click",()=>{O6()});document.getElementById("signout-cancel")?.addEventListener("click",()=>{R6()});N4("app.opened",{app_version:"0.2.6",platform:"overlay"});g8();Z4();if(!U0()){if(z="menu",new URLSearchParams(window.location.search).get("scores")==="demo")B4=O2;let $=z4();I=$?.ownerId===""?$:void 0,e(),o0()}else N2().then(($)=>{if($){let Q=z4();I=Q?.ownerId===$.id?Q:void 0,Y6($),b("read_sync_error").then(F4).catch(()=>{}),o0(),H6()}else V6()});var B6=new URLSearchParams(window.location.search),a8=B6.get("game");if(a8)D6(a8,B6.get("variation")??"classic");