Update chess/public/js/app.js

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