(function() { var SIZE = 6; var NUM_CHECKPOINTS = 6; var TOTAL_CELLS = SIZE * SIZE; var WALL_PROBABILITY = 0.55; function mulberry32(seed) { return function() { seed |= 0; seed = (seed + 0x6D2B79F5) | 0; var t = Math.imul(seed ^ (seed >>> 15), 1 | seed); t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; } function hashSeed(str) { var h = 0; for (var i = 0; i < str.length; i++) h = (Math.imul(31, h) + str.charCodeAt(i)) | 0; return h; } function shuffle(arr, rng) { for (var i = arr.length - 1; i > 0; i--) { var j = Math.floor(rng() * (i + 1)); var tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } return arr; } function generateHamiltonianPath(size, rng) { var total = size * size; var visited = new Array(total).fill(false); var path = []; var attempts = 0, MAX_ATTEMPTS = 300000, aborted = false; function idx(r,c){ return r*size+c; } function neighbors(r,c) { var dirs = [[0,1],[0,-1],[1,0],[-1,0]], result = []; dirs.forEach(function(d){ var nr=r+d[0], nc=c+d[1]; if (nr>=0 && nr=0 && nc MAX_ATTEMPTS) { aborted = true; return false; } visited[idx(r,c)] = true; path.push(idx(r,c)); if (path.length === total) return true; var nbrs = neighbors(r,c); for (var i=0;i=0;c--) path.push(idx(r,c)); } } } return path; } function edgeKey(a, b) { return a < b ? a + '_' + b : b + '_' + a; } function allGridEdges(size) { var edges = []; for (var r = 0; r < size; r++) { for (var c = 0; c < size; c++) { var idx = r*size+c; if (c+1 < size) edges.push([idx, idx+1]); if (r+1 < size) edges.push([idx, idx+size]); } } return edges; } function buildPuzzle(seedStr) { var rng = mulberry32(hashSeed(seedStr)); var hamPath = generateHamiltonianPath(SIZE, rng); var checkpoints = {}; var step = (TOTAL_CELLS - 1) / (NUM_CHECKPOINTS - 1); for (var k = 0; k < NUM_CHECKPOINTS; k++) { var pos = Math.round(k * step); checkpoints[hamPath[pos]] = k + 1; } var usedEdges = new Set(); for (var i = 0; i < hamPath.length - 1; i++) usedEdges.add(edgeKey(hamPath[i], hamPath[i+1])); var walls = new Set(); allGridEdges(SIZE).forEach(function(e) { var key = edgeKey(e[0], e[1]); if (usedEdges.has(key)) return; if (rng() < WALL_PROBABILITY) walls.add(key); }); return { hamPath: hamPath, checkpoints: checkpoints, walls: walls }; } function isAdjacent(a, b) { var ra = Math.floor(a/SIZE), ca = a%SIZE, rb = Math.floor(b/SIZE), cb = b%SIZE; return (Math.abs(ra-rb)===1 && ca===cb) || (Math.abs(ca-cb)===1 && ra===rb); } function hasWall(walls, a, b) { return walls.has(edgeKey(a, b)); } function todayStr() { var d = new Date(); return d.getFullYear() + '-' + String(d.getMonth()+1).padStart(2,'0') + '-' + String(d.getDate()).padStart(2,'0'); } // ---- State ---- var puzzle = null; var path = []; var isDragging = false; var timerInterval = null; var elapsedSeconds = 0; var isDaily = true; var gridEl = document.getElementById('mm-zip-grid'); var svgEl = document.getElementById('mm-zip-svg'); var polylineEl = document.getElementById('mm-zip-polyline'); var timerEl = document.getElementById('mm-zip-timer'); var progressEl = document.getElementById('mm-zip-progress'); var titleEl = document.getElementById('mm-zip-title'); var modeTagEl = document.getElementById('mm-zip-mode-tag'); var playArea = document.getElementById('mm-zip-play-area'); var winArea = document.getElementById('mm-zip-win-area'); var cellEls = []; gridEl.style.gridTemplateColumns = 'repeat(' + SIZE + ', 1fr)'; gridEl.style.gridTemplateRows = 'repeat(' + SIZE + ', 1fr)'; function buildGridDOM() { gridEl.innerHTML = ''; cellEls = []; for (var i = 0; i < TOTAL_CELLS; i++) { var cell = document.createElement('div'); cell.className = 'mm-zip-cell'; cell.dataset.idx = i; if (puzzle.checkpoints[i] !== undefined) { cell.classList.add('mm-checkpoint'); cell.textContent = puzzle.checkpoints[i]; } var r = Math.floor(i/SIZE), c = i%SIZE; var up = i - SIZE, down = i + SIZE, left = c > 0 ? i-1 : null, right = c < SIZE-1 ? i+1 : null; if (r > 0 && hasWall(puzzle.walls, i, up)) cell.classList.add('mm-wall-top'); if (r < SIZE-1 && hasWall(puzzle.walls, i, down)) cell.classList.add('mm-wall-bottom'); if (left !== null && hasWall(puzzle.walls, i, left)) cell.classList.add('mm-wall-left'); if (right !== null && hasWall(puzzle.walls, i, right)) cell.classList.add('mm-wall-right'); gridEl.appendChild(cell); cellEls.push(cell); } } function cellCenter(idx) { var cellEl = cellEls[idx]; var gridRect = gridEl.getBoundingClientRect(); var cellRect = cellEl.getBoundingClientRect(); return { x: cellRect.left - gridRect.left + cellRect.width/2, y: cellRect.top - gridRect.top + cellRect.height/2 }; } function updateVisuals() { cellEls.forEach(function(cell) { cell.classList.remove('mm-filled', 'mm-current', 'mm-checkpoint-done'); }); path.forEach(function(idx) { cellEls[idx].classList.add('mm-filled'); if (puzzle.checkpoints[idx] !== undefined) cellEls[idx].classList.add('mm-checkpoint-done'); }); if (path.length) cellEls[path[path.length-1]].classList.add('mm-current'); var pts = path.map(function(idx) { var c = cellCenter(idx); return c.x + ',' + c.y; }).join(' '); polylineEl.setAttribute('points', pts); progressEl.textContent = path.length + '/' + TOTAL_CELLS; } function nextExpectedCheckpoint() { var maxSeen = 0; path.forEach(function(idx) { if (puzzle.checkpoints[idx] !== undefined) maxSeen = Math.max(maxSeen, puzzle.checkpoints[idx]); }); return maxSeen + 1; } function tryExtend(cellIdx) { if (path.indexOf(cellIdx) !== -1) { var pos = path.indexOf(cellIdx); path = path.slice(0, pos + 1); updateVisuals(); return; } if (path.length === 0) { path.push(cellIdx); startTimerIfNeeded(); updateVisuals(); return; } var last = path[path.length - 1]; if (!isAdjacent(last, cellIdx)) return; if (hasWall(puzzle.walls, last, cellIdx)) return; if (puzzle.checkpoints[cellIdx] !== undefined && puzzle.checkpoints[cellIdx] !== nextExpectedCheckpoint()) return; path.push(cellIdx); updateVisuals(); checkWin(); } function startTimerIfNeeded() { if (timerInterval) return; var start = Date.now() - elapsedSeconds * 1000; timerInterval = setInterval(function() { elapsedSeconds = Math.floor((Date.now() - start) / 1000); var m = Math.floor(elapsedSeconds / 60), s = elapsedSeconds % 60; timerEl.textContent = m + ':' + String(s).padStart(2, '0'); }, 250); } function stopTimer() { if (timerInterval) { clearInterval(timerInterval); timerInterval = null; } } function checkWin() { if (path.length !== TOTAL_CELLS) return; var seenCheckpoints = 0; path.forEach(function(idx) { if (puzzle.checkpoints[idx] !== undefined) seenCheckpoints++; }); if (seenCheckpoints !== NUM_CHECKPOINTS) return; stopTimer(); showWin(); if (isDaily) { try { localStorage.setItem('mm_zip_done_' + todayStr(), String(elapsedSeconds)); } catch(e) {} } } function showWin() { playArea.style.display = 'none'; winArea.style.display = 'block'; var m = Math.floor(elapsedSeconds / 60), s = elapsedSeconds % 60; winArea.innerHTML = '
🎉

Tamamlandı!

' + '

Süre: ' + m + ':' + String(s).padStart(2,'0') + '

' + '
'; document.getElementById('mm-zip-win-random').addEventListener('click', function() { startPuzzle(false); }); } function showAlreadyDoneToday(savedSeconds) { playArea.style.display = 'none'; winArea.style.display = 'block'; var m = Math.floor(savedSeconds / 60), s = savedSeconds % 60; winArea.innerHTML = '

Bugünkü bulmacayı zaten tamamladın!

' + '

Süre: ' + m + ':' + String(s).padStart(2,'0') + ' — yarın yeni bulmaca burada olacak.

' + '
'; document.getElementById('mm-zip-again-random').addEventListener('click', function() { startPuzzle(false); }); } function startPuzzle(daily) { isDaily = daily; stopTimer(); elapsedSeconds = 0; timerEl.textContent = '0:00'; path = []; var seed = daily ? ('zip-' + todayStr()) : ('zip-random-' + Math.random()); puzzle = buildPuzzle(seed); titleEl.textContent = daily ? 'Bugünün Bulmacası' : 'Rastgele Bulmaca'; modeTagEl.textContent = daily ? 'GÜNLÜK' : 'PRATİK'; playArea.style.display = 'block'; winArea.style.display = 'none'; buildGridDOM(); updateVisuals(); } function pointerCellFromEvent(evt) { var x = evt.clientX, y = evt.clientY; var el = document.elementFromPoint(x, y); if (!el) return null; var cellEl = el.closest ? el.closest('.mm-zip-cell') : null; if (!cellEl) return null; return parseInt(cellEl.dataset.idx, 10); } gridEl.addEventListener('pointerdown', function(evt) { var idx = pointerCellFromEvent(evt); if (idx === null) return; isDragging = true; tryExtend(idx); evt.preventDefault(); }); gridEl.addEventListener('pointermove', function(evt) { if (!isDragging) return; var idx = pointerCellFromEvent(evt); if (idx === null) return; tryExtend(idx); }); window.addEventListener('pointerup', function() { isDragging = false; }); window.addEventListener('resize', updateVisuals); document.getElementById('mm-zip-undo').addEventListener('click', function() { if (path.length > 0) { path.pop(); updateVisuals(); } }); document.getElementById('mm-zip-clear').addEventListener('click', function() { path = []; elapsedSeconds = 0; stopTimer(); timerEl.textContent = '0:00'; updateVisuals(); }); document.getElementById('mm-zip-random').addEventListener('click', function() { startPuzzle(false); }); var savedToday = null; try { savedToday = localStorage.getItem('mm_zip_done_' + todayStr()); } catch(e) {} startPuzzle(true); if (savedToday !== null) showAlreadyDoneToday(parseInt(savedToday, 10)); })();