Jump to first and last state
This commit is contained in:
@@ -386,9 +386,9 @@
|
|||||||
|
|
||||||
// --- STATE & HISTORY ---
|
// --- STATE & HISTORY ---
|
||||||
let ws, myRole, selected = null;
|
let ws, myRole, selected = null;
|
||||||
let state = null; // Authoritative latest state
|
let state = null;
|
||||||
let history = []; // Array of state snapshots
|
let history = [];
|
||||||
let historyIndex = -1; // Current view index
|
let historyIndex = -1;
|
||||||
|
|
||||||
const pos = { 0: [80, 210], 1: [180, 110], 2: [180, 210], 3: [180, 310], 4: [280, 110], 5: [280, 210], 6: [280, 310], 7: [380, 110], 8: [380, 210], 9: [380, 310], 10: [480, 210] };
|
const pos = { 0: [80, 210], 1: [180, 110], 2: [180, 210], 3: [180, 310], 4: [280, 110], 5: [280, 210], 6: [280, 310], 7: [380, 110], 8: [380, 210], 9: [380, 310], 10: [480, 210] };
|
||||||
const edges = [[0, 1], [0, 2], [0, 3], [1, 2], [2, 3], [1, 4], [2, 5], [3, 6], [4, 5], [5, 6], [4, 7], [5, 8], [6, 9], [7, 8], [8, 9], [5, 1], [5, 3], [5, 7], [5, 9], [7, 10], [8, 10], [9, 10]];
|
const edges = [[0, 1], [0, 2], [0, 3], [1, 2], [2, 3], [1, 4], [2, 5], [3, 6], [4, 5], [5, 6], [4, 7], [5, 8], [6, 9], [7, 8], [8, 9], [5, 1], [5, 3], [5, 7], [5, 9], [7, 10], [8, 10], [9, 10]];
|
||||||
@@ -398,7 +398,7 @@
|
|||||||
function initLocalState() {
|
function initLocalState() {
|
||||||
const startState = { wolf: 5, sheep: [0, 1, 3], turn: "sheep", moveCount: 0, winner: null, lastMove: null };
|
const startState = { wolf: 5, sheep: [0, 1, 3], turn: "sheep", moveCount: 0, winner: null, lastMove: null };
|
||||||
history = [];
|
history = [];
|
||||||
updateHistory(startState);
|
updateHistory(startState, true);
|
||||||
document.getElementById("lobby").classList.add("hidden");
|
document.getElementById("lobby").classList.add("hidden");
|
||||||
document.getElementById("game").classList.remove("hidden");
|
document.getElementById("game").classList.remove("hidden");
|
||||||
document.getElementById("roomInfo").style.visibility = "hidden";
|
document.getElementById("roomInfo").style.visibility = "hidden";
|
||||||
@@ -406,15 +406,20 @@
|
|||||||
document.getElementById("copyBtn").style.opacity = "0.5";
|
document.getElementById("copyBtn").style.opacity = "0.5";
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateHistory(newState) {
|
function updateHistory(newState, forceJump = false) {
|
||||||
// If it's a reset (moveCount 0) or a new move, add to history
|
const isAtEnd = historyIndex === history.length - 1;
|
||||||
|
|
||||||
if (newState.moveCount === 0) {
|
if (newState.moveCount === 0) {
|
||||||
history = [JSON.parse(JSON.stringify(newState))];
|
history = [JSON.parse(JSON.stringify(newState))];
|
||||||
} else if (!state || newState.moveCount > state.moveCount) {
|
} else if (!state || newState.moveCount > state.moveCount) {
|
||||||
history.push(JSON.parse(JSON.stringify(newState)));
|
history.push(JSON.parse(JSON.stringify(newState)));
|
||||||
}
|
}
|
||||||
|
|
||||||
state = newState;
|
state = newState;
|
||||||
historyIndex = history.length - 1; // Snap to newest
|
// 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;
|
||||||
|
}
|
||||||
render();
|
render();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,24 +442,36 @@
|
|||||||
if (msg.type === "state") {
|
if (msg.type === "state") {
|
||||||
myRole = msg.yourRole;
|
myRole = msg.yourRole;
|
||||||
document.getElementById("overlay").className = msg.onlineCount < 2 ? "" : "hidden";
|
document.getElementById("overlay").className = msg.onlineCount < 2 ? "" : "hidden";
|
||||||
updateHistory(msg.game);
|
updateHistory(msg.game, msg.game.moveCount === 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keyboard controls for back/forward
|
// Keyboard controls for Navigation
|
||||||
window.addEventListener("keydown", (e) => {
|
window.addEventListener("keydown", (e) => {
|
||||||
if (e.key === "ArrowLeft" && historyIndex > 0) {
|
if (history.length === 0) return;
|
||||||
historyIndex--;
|
|
||||||
render();
|
switch (e.key) {
|
||||||
} else if (e.key === "ArrowRight" && historyIndex < history.length - 1) {
|
case "ArrowLeft":
|
||||||
historyIndex++;
|
if (historyIndex > 0) historyIndex--;
|
||||||
render();
|
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
|
||||||
}
|
}
|
||||||
|
selected = null; // Clear selection when moving through time
|
||||||
|
render();
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleLocalMove(from, to) {
|
function handleLocalMove(from, to) {
|
||||||
// If moving while viewing history, we branch off
|
|
||||||
const baseState = history[historyIndex];
|
const baseState = history[historyIndex];
|
||||||
const allowed = (baseState.turn === "wolf") ? bWolf[from] : bSheep[from];
|
const allowed = (baseState.turn === "wolf") ? bWolf[from] : bSheep[from];
|
||||||
if (!allowed?.includes(to) || baseState.sheep.includes(to) || baseState.wolf === to) return;
|
if (!allowed?.includes(to) || baseState.sheep.includes(to) || baseState.wolf === to) return;
|
||||||
@@ -466,9 +483,9 @@
|
|||||||
nextState.moveCount++;
|
nextState.moveCount++;
|
||||||
nextState.winner = checkWinConditions(nextState);
|
nextState.winner = checkWinConditions(nextState);
|
||||||
|
|
||||||
// Truncate history if we were looking at the past
|
// Branch history
|
||||||
history = history.slice(0, historyIndex + 1);
|
history = history.slice(0, historyIndex + 1);
|
||||||
updateHistory(nextState);
|
updateHistory(nextState, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkWinConditions(g) {
|
function checkWinConditions(g) {
|
||||||
@@ -525,7 +542,6 @@
|
|||||||
const type = isWolf ? "wolf" : (isSheep ? "sheep" : "empty");
|
const type = isWolf ? "wolf" : (isSheep ? "sheep" : "empty");
|
||||||
const isWinnerPiece = (viewState.winner === "wolf" && isWolf) || (viewState.winner === "sheep" && isSheep);
|
const isWinnerPiece = (viewState.winner === "wolf" && isWolf) || (viewState.winner === "sheep" && isSheep);
|
||||||
|
|
||||||
// Logic for possible moves
|
|
||||||
const canInteract = isLocal || (!isViewingHistory && state.turn === myRole);
|
const canInteract = isLocal || (!isViewingHistory && state.turn === myRole);
|
||||||
const isPossible = canInteract && selected !== null && (viewState.turn === "wolf" ? bWolf[selected] : bSheep[selected]).includes(i) && !isWolf && !isSheep;
|
const isPossible = canInteract && selected !== null && (viewState.turn === "wolf" ? bWolf[selected] : bSheep[selected]).includes(i) && !isWolf && !isSheep;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user