Create an original, fun puzzle or game in a single HTML file using only HTML, CSS, and JavaScript. The core challenge is twofold: keep the code as short as possible while still making the game genuinely fun and playable. Requirements: - Everything (HTML, CSS, JS) must be in a single file - No external dependencies or libraries - Immediately playable with no setup - Include brief instructions so a new player knows what to do - Must feel satisfying to interact with Aim for under 100 lines of code total — the shorter the better, as long as the game remains enjoyable. AI models will be judged on: 1. **Creativity** of the game idea 2. **How fun** it actually is to play 3. **How minimal** the code is Think of it as a code golf meets game jam challenge.
<!doctype html><meta charset=utf-8><title>Loop Lock</title>
<style>
html,body{margin:0;height:100%;background:#0b1020;color:#d7e1ff;font:16px/1.2 system-ui}
#h{position:fixed;inset:10px auto auto 10px;max-width:22em;opacity:.9}
#s{position:fixed;inset:10px 10px auto auto;text-align:right}
canvas{display:block;margin:auto;image-rendering:pixelated}
b{color:#fff}
</style>
<div id=h><b>Loop Lock</b><br>
Click a tile to rotate it. Make one continuous loop so <b>all tiles connect</b> with no loose ends.<br>
<b>R</b>=new, <b>Space</b>=hint (briefly shows solution). </div>
<div id=s></div>
<canvas id=c width=420 height=420></canvas>
<script>
let C=c.getContext("2d"),N=7,S=60,g=[],sol=[],t=0,show=0,mx=0,my=0,seed=Date.now()%1e9;
let R=_=>seed=(seed*1664525+1013904223)%4294967296,rand=_=>R()/4294967296;
let rot=(m,k)=>((m<<k)|(m>>(4-k)))&15,bit=(m,d)=>m>>d&1;
let dirs=[[0,-1,2],[1,0,3],[0,1,0],[-1,0,1]]; // dx,dy,opposite
function gen(){
g=[...Array(N*N)].map(_=>0); sol=g.slice();
let seen=new Set([0]),cur=0,stack=[0];
while(stack.length){
cur=stack[stack.length-1];
let x=cur%N,y=cur/N|0,opts=[];
for(let d=0;d<4;d++){
let nx=x+dirs[d][0],ny=y+dirs[d][1],ni=ny*N+nx;
if(nx>=0&&ny>=0&&nx<N&&ny<N&&!seen.has(ni)) opts.push([d,ni]);
}
if(!opts.length){stack.pop();continue}
let [d,ni]=opts[(rand()*opts.length)|0],od=dirs[d][2];
sol[cur]|=1<<d; sol[ni]|=1<<od; seen.add(ni); stack.push(ni);
}
// add extra random edges for loops (still solvable)
for(let i=0;i<N*N;i++)for(let d=0;d<4;d++){
if(rand()<.12){
let x=i%N,y=i/N|0,nx=x+dirs[d][0],ny=y+dirs[d][1],j=ny*N+nx,od=dirs[d][2];
if(nx>=0&&ny>=0&&nx<N&&ny<N){sol[i]|=1<<d; sol[j]|=1<<od;}
}
}
// scramble rotations
for(let i=0;i<N*N;i++){let k=(rand()*4)|0; g[i]=rot(sol[i],k)}
t=0;
}
function ok(){
for(let i=0;i<N*N;i++){
let x=i%N,y=i/N|0,m=g[i];
for(let d=0;d<4;d++){
if(!bit(m,d)) continue;
let nx=x+dirs[d][0],ny=y+dirs[d][1];
if(nx<0||ny<0||nx>=N||ny>=N) return 0;
let j=ny*N+nx,od=dirs[d][2];
if(!bit(g[j],od)) return 0;
}
}
// connectivity: all non-empty tiles in one component
let start=g.findIndex(m=>m); if(start<0) return 0;
let q=[start],vis=new Set([start]);
while(q.length){
let i=q.pop(),x=i%N,y=i/N|0,m=g[i];
for(let d=0;d<4;d++) if(bit(m,d)){
let nx=x+dirs[d][0],ny=y+dirs[d][1],j=ny*N+nx;
if(!vis.has(j)){vis.add(j);q.push(j)}
}
}
for(let i=0;i<N*N;i++) if(g[i]&&!vis.has(i)) return 0;
return 1;
}
function draw(){
requestAnimationFrame(draw);
C.clearRect(0,0,c.width,c.height);
let win=ok(),A=show?sol:g;
for(let i=0;i<N*N;i++){
let x=i%N,y=i/N|0,px=x*S,py=y*S,m=A[i];
C.fillStyle="rgba(255,255,255,.04)"; C.fillRect(px+1,py+1,S-2,S-2);
C.strokeStyle=win?"#7CFF9A":"#9fb3ff"; C.lineWidth=10; C.lineCap="round";
let cx=px+S/2,cy=py+S/2;
C.beginPath();
if(bit(m,0)) {C.moveTo(cx,cy);C.lineTo(cx,py+8)}
if(bit(m,1)) {C.moveTo(cx,cy);C.lineTo(px+S-8,cy)}
if(bit(m,2)) {C.moveTo(cx,cy);C.lineTo(cx,py+S-8)}
if(bit(m,3)) {C.moveTo(cx,cy);C.lineTo(px+8,cy)}
C.stroke();
C.fillStyle=win?"#7CFF9A":"#d7e1ff"; C.beginPath(); C.arc(cx,cy,5,0,7); C.fill();
}
if(!win)t++;
s.innerHTML=(win?"<b>LOCKED!</b> ":"")+"moves: "+t+(show?"<br><small>hint…</small>":"");
}
c.onpointermove=e=>{let r=c.getBoundingClientRect();mx=e.clientX-r.left;my=e.clientY-r.top}
c.onpointerdown=e=>{
let x=(mx/S)|0,y=(my/S)|0,i=y*N+x;
if(i>=0&&i<N*N){g[i]=rot(g[i],1);t++}
}
onkeydown=e=>{
if(e.key=="r"||e.key=="R") gen();
if(e.key==" "){show=1;setTimeout(_=>show=0,450)}
}
gen();draw();
</script>
Comments