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) {