From 8dcc964d045959f724e4281bfdc45cfeea334495 Mon Sep 17 00:00:00 2001 From: admin01 Date: Sat, 22 Aug 2026 18:08:35 +0000 Subject: [PATCH] Update chess/public/js/app.js --- chess/public/js/app.js | 166 +++++++++++++++++++++++++++-------------- 1 file changed, 109 insertions(+), 57 deletions(-) diff --git a/chess/public/js/app.js b/chess/public/js/app.js index 3eece9e..5c221d9 100644 --- a/chess/public/js/app.js +++ b/chess/public/js/app.js @@ -98,6 +98,10 @@ const elements = { partySummary: document.querySelector("#partySummary"), copyInviteButton: document.querySelector("#copyInviteButton"), + + // ДОБАВЛЕНЫ КНОПКИ "НОВАЯ ИГРА" + newGameToolbarButton: document.querySelector("#newGameToolbarButton"), + newPartyGameButton: document.querySelector("#newPartyGameButton"), flipBoardButton: document.querySelector("#flipBoardButton"), @@ -520,22 +524,22 @@ function formatStatus() { const status = currentStatus(); if (status.phase === "checkmate") { - return "Checkmate"; + return "Мат!"; } if (status.phase === "draw") { - return "Draw"; + return "Ничья"; } if (status.check) { return appState.engine.state.turn === "w" - ? "White is in check" - : "Black is in check"; + ? "Шах белым" + : "Шах черным"; } return appState.engine.state.turn === "w" - ? "White to move" - : "Black to move"; + ? "Ход белых" + : "Ход черных"; } @@ -546,7 +550,7 @@ function getGameOverMessage() { if (!snapshot) { return ( appState.gameOverMessage || - "Game over." + "Игра окончена." ); } @@ -559,21 +563,21 @@ function getGameOverMessage() { switch (reason) { case "timeout": return winner === "w" - ? "White wins on time." - : "Black wins on time."; + ? "Белые выиграли по времени." + : "Черные выиграли по времени."; case "checkmate": return winner === "w" - ? "White wins by checkmate." - : "Black wins by checkmate."; + ? "Белые выиграли матом." + : "Черные выиграли матом."; case "draw": - return "Draw."; + return "Ничья."; default: return ( appState.gameOverMessage || - "Game over." + "Игра окончена." ); } } @@ -586,17 +590,17 @@ function getGameOverMessage() { function renderRoster() { if (appState.mode === "ai") { const human = - appState.playerName || "You"; + appState.playerName || "Вы"; const whiteName = appState.playerColor === "w" ? human - : `Computer (${appState.aiLevel})`; + : `Компьютер (${appState.aiLevel})`; const blackName = appState.playerColor === "b" ? human - : `Computer (${appState.aiLevel})`; + : `Компьютер (${appState.aiLevel})`; if (elements.whitePlayerLabel) { elements.whitePlayerLabel.textContent = @@ -620,7 +624,7 @@ function renderRoster() { if (elements.spectatorList) { elements.spectatorList.innerHTML = - "
  • None in AI mode
  • "; + "
  • В режиме ИИ зрителей нет
  • "; } if (elements.spectatorCount) { @@ -644,7 +648,7 @@ function renderRoster() { ? "" : " · offline" }` - : "Open seat"; + : "Свободно"; const blackName = black @@ -653,7 +657,7 @@ function renderRoster() { ? "" : " · offline" }` - : "Open seat"; + : "Свободно"; elements.whitePlayerLabel && (elements.whitePlayerLabel.textContent = @@ -685,7 +689,7 @@ function renderRoster() { if (!spectators.length) { elements.spectatorList.innerHTML = - "
  • None yet
  • "; + "
  • Пока никого нет
  • "; return; } @@ -717,7 +721,7 @@ function renderPartySummary() { if (!appState.party) { elements.partySummary.textContent = - "Create a room to become White. The next player joins as Black. Up to 20 spectators can watch live."; + "Создайте комнату, чтобы играть белыми. Следующий игрок присоединится за черных."; return; } @@ -727,18 +731,18 @@ function renderPartySummary() { const roleText = role === "white" - ? "playing as White" + ? "Играете за Белых" : role === "black" - ? "playing as Black" - : "watching as a spectator"; + ? "Играете за Черных" + : "Зритель"; const timeLabel = appState.partySnapshot ?.timeControl?.label || - "Без часов"; + "Без лимита"; elements.partySummary.textContent = - `Party ${appState.party.code} · ${roleText}. ${timeLabel}.`; + `Комната ${appState.party.code} · ${roleText}. ${timeLabel}.`; } @@ -770,7 +774,7 @@ function renderClocks() { elements.aiTimeControl ?.selectedOptions?.[0] ?.textContent || - "Без часов", + "Без лимита", }; } @@ -784,7 +788,7 @@ function renderClocks() { elements.whiteClock.textContent = "∞"; elements.whiteClock.classList.remove( "active", - "low" + "danger" ); } @@ -792,7 +796,7 @@ function renderClocks() { elements.blackClock.textContent = "∞"; elements.blackClock.classList.remove( "active", - "low" + "danger" ); } @@ -816,8 +820,8 @@ function renderClocks() { ); elements.whiteClock.classList.toggle( - "low", - white <= 10 + "danger", + white <= 10 && white > 0 ); } @@ -832,8 +836,8 @@ function renderClocks() { ); elements.blackClock.classList.toggle( - "low", - black <= 10 + "danger", + black <= 10 && black > 0 ); } } @@ -848,31 +852,37 @@ function renderConnectionBadge() { return; } + // Сбросим классы перед установкой + elements.connectionBadge.className = "status-chip"; + if (appState.mode === "ai") { + elements.connectionBadge.classList.add("connection-solo"); elements.connectionBadge.textContent = appState.isAiThinking - ? "Computer thinking" - : `AI: ${appState.aiLevel}`; + ? "Компьютер думает..." + : `Соло (${appState.aiLevel})`; return; } if (!appState.party) { + elements.connectionBadge.classList.add("connection-solo"); elements.connectionBadge.textContent = - "Party idle"; + "Вне комнаты"; return; } + elements.connectionBadge.classList.add("connection-party"); const role = appState.party.role === "white" - ? "White" + ? "Белые" : appState.party.role === "black" - ? "Black" - : "Spectator"; + ? "Черные" + : "Зритель"; elements.connectionBadge.textContent = - `Party ${appState.party.code} · ${role}`; + `Комната ${appState.party.code} · ${role}`; } @@ -891,7 +901,13 @@ function render() { if (elements.turnBadge) { elements.turnBadge.textContent = - status; + appState.engine.state.turn === "w" ? "Ход белых" : "Ход черных"; + + // Меняем класс цвета бейджа + elements.turnBadge.className = + appState.engine.state.turn === "w" + ? "status-chip turn-white" + : "status-chip turn-black"; } if (elements.statusMessage) { @@ -908,6 +924,12 @@ function render() { "hidden", !appState.party ); + + // Показываем кнопку "Новая игра" в мультиплеере только если мы в комнате (и опционально, если игра окончена) + elements.newPartyGameButton?.classList.toggle( + "hidden", + !appState.party + ); } @@ -1013,7 +1035,7 @@ async function submitMove(move) { showToast( response.error || - "Move rejected.", + "Ход отклонен.", "error" ); @@ -1039,7 +1061,7 @@ async function submitMove(move) { if (!result.ok) { showToast( result.error || - "Illegal move.", + "Недопустимый ход.", "error" ); @@ -1304,8 +1326,8 @@ function updateAiClock() { appState.gameOverMessage = color === "w" - ? "Black wins on time." - : "White wins on time."; + ? "Черные выиграли по времени." + : "Белые выиграли по времени."; stopAiClock(); @@ -1377,6 +1399,32 @@ function resetLocalGame() { startAiClock(); scheduleAiTurn(); + render(); +} + + +/* ========================================================= + NEW GAME HANDLER (Добавлено) +========================================================= */ + +async function startNewGame() { + if (appState.mode === "ai") { + resetLocalGame(); + showToast("Новая игра с ИИ начата!", "success"); + } else if (appState.mode === "party" && appState.party) { + // Если вы играете с другом, мы отправляем запрос на сервер, + // чтобы он сбросил состояние комнаты. (Предполагается, что такой API существует) + const response = await postJson("/api/party/restart", { + partyCode: appState.party.code, + clientId: appState.party.clientId + }); + + if (!response.ok) { + showToast(response.error || "Не удалось перезапустить игру на сервере.", "error"); + return; + } + showToast("Новая игра в комнате началась!", "success"); + } } @@ -1581,7 +1629,7 @@ function connectPartyStream() { elements.connectionBadge ) { elements.connectionBadge.textContent = - `Party ${code} · reconnecting`; + `Комната ${code} · переподключение...`; } }; @@ -1624,7 +1672,7 @@ async function createParty() { if (!response.ok) { showToast( response.error || - "Unable to create party.", + "Не удалось создать комнату.", "error" ); @@ -1644,7 +1692,7 @@ async function createParty() { connectPartyStream(); showToast( - `Party ${response.party.code} created.`, + `Комната ${response.party.code} создана.`, "success" ); } @@ -1662,7 +1710,7 @@ async function joinParty(code) { if (!normalizedCode) { showToast( - "Enter a party code first.", + "Сначала введите код комнаты.", "error" ); @@ -1674,7 +1722,7 @@ async function joinParty(code) { normalizedCode ) { showToast( - `You are already in party ${normalizedCode}.` + `Вы уже находитесь в комнате ${normalizedCode}.` ); return; @@ -1706,7 +1754,7 @@ async function joinParty(code) { if (!response.ok) { showToast( response.error || - "Unable to join party.", + "Не удалось войти в комнату.", "error" ); @@ -1726,7 +1774,7 @@ async function joinParty(code) { connectPartyStream(); showToast( - `Joined party ${response.party.code}.`, + `Вы присоединились к комнате ${response.party.code}.`, "success" ); } @@ -1774,7 +1822,7 @@ async function leaveParty( if (!silent) { showToast( - "Left the party room." + "Вы покинули комнату." ); } } @@ -1802,12 +1850,12 @@ async function copyInviteLink() { ); showToast( - "Invite link copied.", + "Ссылка-инвайт скопирована!", "success" ); } catch { showToast( - `Party code: ${appState.party.code}` + `Код комнаты: ${appState.party.code}` ); } } @@ -1872,12 +1920,16 @@ function removeStoredPartyId(code) { ========================================================= */ function bindEvents() { + // ПРИВЯЗКА КНОПОК НОВОЙ ИГРЫ + elements.newGameToolbarButton?.addEventListener("click", startNewGame); + elements.newPartyGameButton?.addEventListener("click", startNewGame); + elements.playerNameInput?.addEventListener( "input", event => { appState.playerName = event.target.value.trim() || - "Guest"; + "Гость"; localStorage.setItem( STORAGE_KEYS.name, @@ -1960,7 +2012,7 @@ function bindEvents() { resetLocalGame(); showToast( - "New AI game ready.", + "Новая игра с ИИ началась.", "success" ); }