ctx.clearRect(0, 0, rect.width, rect.height); if (path.length < 1) return; const cellSize = rect.width / currentLevel.size; const half = cellSize / 2; ctx.beginPath(); ctx.strokeStyle = 'rgb(230, 138, 62)'; ctx.lineWidth = cellSize * 0.75; ctx.lineCap = 'round'; ctx.lineJoin = 'round'; path.forEach((pos, i) => { const x = pos.c * cellSize + half; const y = pos.r * cellSize + half; if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); }); ctx.stroke(); if (path.length > 0) { const head = path[path.length - 1]; ctx.beginPath(); ctx.fillStyle = 'white'; ctx.arc(head.c * cellSize + half, head.r * cellSize + half, cellSize * 0.15, 0, Math.PI * 2); ctx.fill(); } }; useEffect(() => { drawPath(); window.addEventListener('resize', drawPath); return () => window.removeEventListener('resize', drawPath); }, [path, levelIdx]); const getCoords = (clientX, clientY) => { if (!gridRef.current) return null; const rect = gridRef.current.getBoundingClientRect(); const x = clientX - rect.left; const y = clientY - rect.top; if (x < 0 || x > rect.width || y < 0 || y > rect.height) return null; const c = Math.floor((x / rect.width) * currentLevel.size); const r = Math.floor((y / rect.height) * currentLevel.size); return { r, c }; }; const handlePointerDown = (e) => { if (win) return; const coords = getCoords(e.clientX, e.clientY); if (!coords) return; const key = `${coords.r},${coords.c}`; if (path.length === 0) { if (currentLevel.nodes[key] === 1) { setPath([coords]); setIsDragging(true); } } else { const idx = path.findIndex(p => p.r === coords.r && p.c === coords.c); if (idx !== -1) { setPath(path.slice(0, idx + 1)); setIsDragging(true); } } }; const handlePointerMove = (e) => { if (!isDragging || win) return; const coords = getCoords(e.clientX, e.clientY); if (!coords) return; const headNode = path[path.length - 1]; if (headNode.r === coords.r && headNode.c === coords.c) return; if (Math.abs(coords.r - headNode.r) + Math.abs(coords.c - headNode.c) === 1) { if (path.length > 1) { const prev = path[path.length - 2]; if (prev.r === coords.r && prev.c === coords.c) { setPath(path.slice(0, -1)); return; } } if (path.some(p => p.r === coords.r && p.c === coords.c)) return; const nodeVal = currentLevel.nodes[`${coords.r},${coords.c}`]; if (nodeVal) { let last = 0; for (let i = path.length - 1; i >= 0; i--) { const v = currentLevel.nodes[`${path[i].r},${path[i].c}`]; if (v) { last = v; break; } } if (nodeVal !== last + 1) { setErrorCell(coords); setTimeout(() => setErrorCell(null), 250); return; } } const newPath = [...path, coords]; setPath(newPath); const total = currentLevel.size * currentLevel.size; const endVal = currentLevel.nodes[`${coords.r},${coords.c}`]; if (newPath.length === total && endVal === maxVal) { setWin(true); setIsDragging(false); setTimeout(() => { if (levelIdx < LEVELS.length - 1) { setLevelIdx(prev => prev + 1); setPath([]); setWin(false); } }, 3000); } else if (endVal === maxVal) { setShake(true); setErrorCell(coords); setTimeout(() => { setShake(false); setErrorCell(null); }, 600); } } }; return (
ZIP IT!
LINKEDIN GAME PRACTICE
{isMusicOn ? : }
setIsDragging(false)} className="relative w-full h-full overflow-hidden rounded-[38px] grid grid-cols-6 grid-rows-6"> {Array.from({ length: 36 }).map((_, i) => { const r = Math.floor(i / 6), c = i % 6; const val = currentLevel.nodes[`${r},${c}`]; const isInPath = path.some(p => p.r === r && p.c === c); const isError = errorCell?.r === r && errorCell?.c === c; const nodeBg = val ? (isInPath ? 'rgb(0, 65, 130)' : 'black') : 'transparent'; const isMissed = shake && !isInPath; return (
{val && (
{val}
)}
); })}
Level {levelIdx + 1} of 20
{win && (

ZIPPED!

{COMP_MESSAGES[levelIdx]}

)}
); } const root = ReactDOM.createRoot(document.getElementById('root')); root.render();