Show code
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Conway's Game of Life</title>
<style>
html,body{height:100%}
body{margin:0;background:#05070d;color:#8ea6c8;font:12px/1.4 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;min-height:100vh}
canvas{display:block;width:min(95vw,960px);height:auto;border:1px solid #17263f;border-radius:6px;box-shadow:0 0 60px #071427}
#hud{display:flex;flex-wrap:wrap;gap:20px;letter-spacing:.14em;text-transform:uppercase}
b{color:#7fe6ff;font-weight:600}
</style></head><body>
<canvas id="c" width="960" height="640"></canvas>
<div id="hud"><span>Life · 120×80 torus</span><span>gen <b id="G">0</b></span><span>alive <b id="P">0</b></span><span>run <b id="R">1</b></span></div>
<script>
const W=120,H=80,S=8,N=W*H,x=document.getElementById('c').getContext('2d');
let g=new Uint8Array(N),n=new Uint8Array(N),age=new Int16Array(N),tr=new Int8Array(N),p1=new Uint8Array(N),p2=new Uint8Array(N);
let gen=0,pop=0,stall=0,run=1;
const CA=[],CT=[];
for(let i=0;i<48;i++){const t=i/47;CA.push('hsl('+(188-t*158)+','+(94-t*26)+'%,'+(70-t*22)+'%)')}
for(let i=0;i<7;i++)CT.push('rgba(74,138,255,'+(0.3*(7-i)/7).toFixed(3)+')');
const I=(c,r)=>((r%H)+H)%H*W+(((c%W)+W)%W);
const PT={
gl:[[1,0],[2,1],[0,2],[1,2],[2,2]],
lw:[[0,0],[3,0],[4,1],[0,2],[4,2],[1,3],[2,3],[3,3],[4,3]],
bl:[[0,0],[1,0],[2,0]],
td:[[1,0],[2,0],[3,0],[0,1],[1,1],[2,1]],
bc:[[0,0],[1,0],[0,1],[1,1],[2,2],[3,2],[2,3],[3,3]],
pd:[[0,1],[1,1],[2,0],[2,2],[3,1],[4,1],[5,1],[6,1],[7,0],[7,2],[8,1],[9,1]],
rp:[[1,0],[2,0],[0,1],[1,1],[1,2]]};
function place(p,c,r){let mw=0,mh=0;for(const q of p){if(q[0]>mw)mw=q[0];if(q[1]>mh)mh=q[1]}
for(let j=-2;j<=mh+2;j++)for(let i=-2;i<=mw+2;i++)g[I(c+i,r+j)]=0;
for(const q of p)g[I(c+q[0],r+q[1])]=1}
function seed(){
g.fill(0);n.fill(0);age.fill(0);tr.fill(0);p1.fill(0);p2.fill(0);gen=0;stall=0;
const d=0.12+Math.random()*0.1;
for(let i=0;i<N;i++)if(Math.random()<d)g[i]=1;
place(PT.gl,4,4);place(PT.gl,W-16,6);place(PT.gl,10,H-14);
place(PT.lw,6,H-8);
place(PT.bl,30,20);place(PT.bl,W-30,H-22);
place(PT.td,58,12);place(PT.bc,90,54);
place(PT.pd,44,H>>1);
place(PT.rp,20+((Math.random()*70)|0),24+((Math.random()*30)|0));
count()}
function count(){pop=0;for(let i=0;i<N;i++)if(g[i])pop++}
function step(){
for(let r=0;r<H;r++){const u=(r?r-1:H-1)*W,m=r*W,dn=(r+1<H?r+1:0)*W;
for(let c=0;c<W;c++){const l=c?c-1:W-1,e=c+1<W?c+1:0;
const k=g[u+l]+g[u+c]+g[u+e]+g[m+l]+g[m+e]+g[dn+l]+g[dn+c]+g[dn+e];
n[m+c]=(k===3||(k===2&&g[m+c]))?1:0}}
p2.set(p1);p1.set(g);const t=g;g=n;n=t;
pop=0;
for(let i=0;i<N;i++){if(g[i]){pop++;if(age[i]<9999)age[i]++;tr[i]=0}
else if(age[i]){age[i]=0;tr[i]=7}
else if(tr[i]>0)tr[i]--}
stall=(eq(g,p1)||eq(g,p2))?stall+1:0;gen++}
function eq(a,b){for(let i=0;i<N;i++)if(a[i]!==b[i])return 0;return 1}
function draw(){
x.fillStyle='#05070d';x.fillRect(0,0,960,640);
for(let r=0,i=0;r<H;r++)for(let c=0;c<W;c++,i++){
if(g[i]){x.fillStyle=CA[age[i]<1?0:age[i]<48?age[i]-1:47];x.fillRect(c*S,r*S,S-1,S-1)}
else if(tr[i]>0){x.fillStyle=CT[7-tr[i]];x.fillRect(c*S+2,r*S+2,S-4,S-4)}}}
const G=document.getElementById('G'),P=document.getElementById('P'),R=document.getElementById('R');
let last=0,acc=0;
function frame(t){requestAnimationFrame(frame);
if(!last)last=t;acc+=t-last;last=t;if(acc<52)return;acc=0;
step();draw();
G.textContent=gen;P.textContent=pop;R.textContent=run;
if(!pop||stall>24||gen>2600){run++;seed();draw()}}
seed();draw();requestAnimationFrame(frame);
</script></body></html>