diff --git a/public/index.html b/public/index.html index 81b2cdc..937229a 100644 --- a/public/index.html +++ b/public/index.html @@ -408,18 +408,13 @@ function updateHistory(newState, forceJump = false) { const isAtEnd = historyIndex === history.length - 1; - if (newState.moveCount === 0) { history = [JSON.parse(JSON.stringify(newState))]; } else if (!state || newState.moveCount > state.moveCount) { history.push(JSON.parse(JSON.stringify(newState))); } - state = newState; - // Only jump the view to the latest state if the player was already at the end or if forced (like on restart) - if (isAtEnd || forceJump) { - historyIndex = history.length - 1; - } + if (isAtEnd || forceJump) historyIndex = history.length - 1; render(); } @@ -427,7 +422,6 @@ if (isLocal) return initLocalState(); const protocol = location.protocol === "https:" ? "wss" : "ws"; ws = new WebSocket(`${protocol}://${location.host}?room=${roomId}&sessionId=${sessionId}`); - ws.onopen = () => document.getElementById("dot").classList.add("conn-online"); ws.onmessage = e => { const msg = JSON.parse(e.data); @@ -447,27 +441,16 @@ }; } - // Keyboard controls for Navigation window.addEventListener("keydown", (e) => { if (history.length === 0) return; - switch (e.key) { - case "ArrowLeft": - if (historyIndex > 0) historyIndex--; - break; - case "ArrowRight": - if (historyIndex < history.length - 1) historyIndex++; - break; - case "ArrowUp": // Jump to Present - historyIndex = history.length - 1; - break; - case "ArrowDown": // Jump to Start - historyIndex = 0; - break; - default: - return; // Exit if other key + case "ArrowLeft": if (historyIndex > 0) historyIndex--; break; + case "ArrowRight": if (historyIndex < history.length - 1) historyIndex++; break; + case "ArrowUp": historyIndex = history.length - 1; break; + case "ArrowDown": historyIndex = 0; break; + default: return; } - selected = null; // Clear selection when moving through time + selected = null; render(); }); @@ -482,24 +465,33 @@ nextState.moveCount++; nextState.winner = checkWinConditions(nextState); - - // Branch history history = history.slice(0, historyIndex + 1); updateHistory(nextState, true); } function checkWinConditions(g) { + // 1. Wolf reaches sheep starting line (Row 0) if (g.wolf === 0) return "wolf"; + + // 2. Max moves reached if (g.moveCount >= 40) return "wolf"; + + // 3. Wolf is trapped const canWolfMove = bWolf[g.wolf].some(to => !g.sheep.includes(to)); if (!canWolfMove) return "sheep"; + + // 4. Sheep are trapped (Wolf wins) + const canAnySheepMove = g.sheep.some(sPos => { + return bSheep[sPos].some(to => to !== g.wolf && !g.sheep.includes(to)); + }); + if (!canAnySheepMove) return "wolf"; + return null; } function render() { const viewState = history[historyIndex]; if (!viewState) return; - const isViewingHistory = historyIndex < history.length - 1; const svg = document.querySelector("svg"); svg.innerHTML = ""; @@ -541,7 +533,6 @@ const isSheep = viewState.sheep.includes(i); const type = isWolf ? "wolf" : (isSheep ? "sheep" : "empty"); const isWinnerPiece = (viewState.winner === "wolf" && isWolf) || (viewState.winner === "sheep" && isSheep); - const canInteract = isLocal || (!isViewingHistory && state.turn === myRole); const isPossible = canInteract && selected !== null && (viewState.turn === "wolf" ? bWolf[selected] : bSheep[selected]).includes(i) && !isWolf && !isSheep; @@ -549,7 +540,6 @@ g.onclick = () => { if (viewState.winner || (!isLocal && isViewingHistory)) return; if (!isLocal && state.turn !== myRole) return; - const isMine = (viewState.turn === "wolf" && isWolf) || (viewState.turn === "sheep" && isSheep); if (isMine) selected = i; else if (isPossible) {