move dashboard script block content into own files with new classes to update, render to have a better code overview
Build and Push Docker Container / build-and-push (push) Successful in 3m55s
Build and Push Docker Container / build-and-push (push) Successful in 3m55s
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
class GameState {
|
||||
constructor({ gameBoard, thinkingPanel, gamesTable, sliderEl, turnLabelEl }) {
|
||||
this._gameBoard = gameBoard;
|
||||
this._thinkingPanel = thinkingPanel;
|
||||
this._gamesTable = gamesTable;
|
||||
this._sliderEl = sliderEl;
|
||||
this._turnLabelEl = turnLabelEl;
|
||||
this._webSocket = null;
|
||||
|
||||
this.replay = null;
|
||||
this.turnIndex = 0;
|
||||
this.activeGameId = "";
|
||||
this.selectedSnakeId = null;
|
||||
this._timer = null;
|
||||
this._hasLoadedReplayOnce = false;
|
||||
}
|
||||
|
||||
setWebSocket(webSocket) {
|
||||
this._webSocket = webSocket;
|
||||
}
|
||||
|
||||
get isPlaying() { return Boolean(this._timer); }
|
||||
|
||||
async loadReplay(gameId) {
|
||||
let nextReplay = null;
|
||||
try {
|
||||
nextReplay = await this._webSocket.requestReplay(gameId);
|
||||
} catch {
|
||||
if (!this._hasLoadedReplayOnce) {
|
||||
this._thinkingPanel.render(
|
||||
{ my_move: "-", my_thinking: { error: `Replay websocket unavailable for ${gameId}` } },
|
||||
null,
|
||||
);
|
||||
return;
|
||||
}
|
||||
const response = await fetch(`/dashboard/game/${gameId}`);
|
||||
if (!response.ok) {
|
||||
this._thinkingPanel.render(
|
||||
{ my_move: "-", my_thinking: { error: `Replay load failed for ${gameId}` } },
|
||||
null,
|
||||
);
|
||||
return;
|
||||
}
|
||||
nextReplay = await response.json();
|
||||
}
|
||||
|
||||
this.replay = nextReplay;
|
||||
this._hasLoadedReplayOnce = true;
|
||||
this.activeGameId = String(gameId || "");
|
||||
await this._gameBoard.preloadSvgs(this.replay);
|
||||
this.turnIndex = 0;
|
||||
const count = Array.isArray(this.replay.turns) ? this.replay.turns.length : 0;
|
||||
this._sliderEl.max = String(Math.max(0, count - 1));
|
||||
this._sliderEl.value = "0";
|
||||
this._gamesTable.setActive(gameId);
|
||||
this.renderTurn();
|
||||
}
|
||||
|
||||
renderTurn() {
|
||||
if (!this.replay || !Array.isArray(this.replay.turns) || this.replay.turns.length === 0) {
|
||||
this._turnLabelEl.textContent = "Turn -";
|
||||
this._gameBoard.clearBoard();
|
||||
this._thinkingPanel.render(null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
const game = this.replay.game || {};
|
||||
const turns = this.replay.turns;
|
||||
const turn = turns[this.turnIndex];
|
||||
this._turnLabelEl.textContent = `Turn ${turn.turn} / ${turns[turns.length - 1].turn}`;
|
||||
this._sliderEl.value = String(this.turnIndex);
|
||||
this._gameBoard.paintBoard(turn, game.width, game.height, this.selectedSnakeId, this.replay);
|
||||
this._thinkingPanel.render(turn, this.replay);
|
||||
if (this.selectedSnakeId) {
|
||||
this._thinkingPanel.highlightSnake(this.selectedSnakeId);
|
||||
}
|
||||
}
|
||||
|
||||
stopPlayback() {
|
||||
if (this._timer) {
|
||||
clearInterval(this._timer);
|
||||
this._timer = null;
|
||||
}
|
||||
const playBtn = document.getElementById("play-btn");
|
||||
playBtn.textContent = "▶";
|
||||
playBtn.setAttribute("title", "Play");
|
||||
playBtn.setAttribute("aria-label", "Play");
|
||||
}
|
||||
|
||||
startPlayback() {
|
||||
if (!this.replay || !Array.isArray(this.replay.turns) || this.replay.turns.length < 2) return;
|
||||
if (this.turnIndex >= this.replay.turns.length - 1) {
|
||||
this.turnIndex = 0;
|
||||
this.renderTurn();
|
||||
}
|
||||
this.stopPlayback();
|
||||
const interval = Number(document.getElementById("speed").value || 650);
|
||||
this._timer = setInterval(() => {
|
||||
if (!this.replay || this.turnIndex >= this.replay.turns.length - 1) {
|
||||
this.stopPlayback();
|
||||
return;
|
||||
}
|
||||
this.turnIndex += 1;
|
||||
this.renderTurn();
|
||||
}, interval);
|
||||
const playBtn = document.getElementById("play-btn");
|
||||
playBtn.textContent = "❚❚";
|
||||
playBtn.setAttribute("title", "Pause");
|
||||
playBtn.setAttribute("aria-label", "Pause");
|
||||
}
|
||||
|
||||
stepBackward() {
|
||||
this.stopPlayback();
|
||||
if (!this.replay || this.turnIndex <= 0) return;
|
||||
this.turnIndex -= 1;
|
||||
this.renderTurn();
|
||||
}
|
||||
|
||||
stepForward() {
|
||||
this.stopPlayback();
|
||||
if (!this.replay || !Array.isArray(this.replay.turns) || this.turnIndex >= this.replay.turns.length - 1) return;
|
||||
this.turnIndex += 1;
|
||||
this.renderTurn();
|
||||
}
|
||||
|
||||
adjustSpeed(direction) {
|
||||
const speedEl = document.getElementById("speed");
|
||||
const optionCount = speedEl.options.length;
|
||||
if (optionCount <= 1) return;
|
||||
const currentIndex = speedEl.selectedIndex;
|
||||
const nextIndex = Math.max(0, Math.min(optionCount - 1, currentIndex + direction));
|
||||
if (nextIndex === currentIndex) return;
|
||||
speedEl.selectedIndex = nextIndex;
|
||||
speedEl.dispatchEvent(new Event("change"));
|
||||
}
|
||||
|
||||
setSelectedSnakeId(id) {
|
||||
this.selectedSnakeId = id;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user