Show waiting players during practice
This commit is contained in:
65
game.js
65
game.js
@@ -35,6 +35,8 @@ let roomId = "";
|
|||||||
let gameMode = "practice";
|
let gameMode = "practice";
|
||||||
let multiplayerState = "local";
|
let multiplayerState = "local";
|
||||||
let botTimer = 0;
|
let botTimer = 0;
|
||||||
|
let lobbyTimer = 0;
|
||||||
|
let waitingPlayers = 0;
|
||||||
|
|
||||||
function createBoard() {
|
function createBoard() {
|
||||||
return Array.from({ length: size }, () => Array(size).fill(empty));
|
return Array.from({ length: size }, () => Array(size).fill(empty));
|
||||||
@@ -54,6 +56,7 @@ function setupGame() {
|
|||||||
|
|
||||||
function connectToServer() {
|
function connectToServer() {
|
||||||
gameMode = "online";
|
gameMode = "online";
|
||||||
|
stopLobbyPolling();
|
||||||
closeSocket();
|
closeSocket();
|
||||||
localPlayer = "";
|
localPlayer = "";
|
||||||
roomId = "";
|
roomId = "";
|
||||||
@@ -103,7 +106,8 @@ function startPracticeMode() {
|
|||||||
roomId = "";
|
roomId = "";
|
||||||
multiplayerState = "local";
|
multiplayerState = "local";
|
||||||
setupGame();
|
setupGame();
|
||||||
setMultiplayerState("local", "BOT practice. You are X. Random O replies after each move.");
|
setPracticeStatus("BOT practice. You are X. Random O replies after each move.");
|
||||||
|
startLobbyPolling();
|
||||||
updateModeButtons();
|
updateModeButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +119,40 @@ function closeSocket() {
|
|||||||
socket = null;
|
socket = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function startLobbyPolling() {
|
||||||
|
stopLobbyPolling();
|
||||||
|
checkLobby();
|
||||||
|
lobbyTimer = window.setInterval(checkLobby, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopLobbyPolling() {
|
||||||
|
if (lobbyTimer) {
|
||||||
|
window.clearInterval(lobbyTimer);
|
||||||
|
lobbyTimer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkLobby() {
|
||||||
|
if (gameMode !== "practice") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/lobby", { cache: "no-store" });
|
||||||
|
if (!response.ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const status = await response.json();
|
||||||
|
waitingPlayers = Number(status.waitingPlayers || 0);
|
||||||
|
if (!gameOver && currentPlayer === localPlayer) {
|
||||||
|
setPracticeStatus("BOT practice. You are X. Random O replies after each move.");
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
waitingPlayers = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function handleServerMessage(payload) {
|
function handleServerMessage(payload) {
|
||||||
if (payload.type === "waiting") {
|
if (payload.type === "waiting") {
|
||||||
localPlayer = "";
|
localPlayer = "";
|
||||||
@@ -255,7 +293,7 @@ function playLocalMove(row, col) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!gameOver) {
|
if (!gameOver) {
|
||||||
setMultiplayerState("local", "Bot thinking...");
|
setPracticeStatus("Bot thinking...");
|
||||||
botTimer = window.setTimeout(playBotMove, 360);
|
botTimer = window.setTimeout(playBotMove, 360);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -276,14 +314,14 @@ function applyMove(row, col, player, source) {
|
|||||||
if (win.length > 0) {
|
if (win.length > 0) {
|
||||||
winningCells = win;
|
winningCells = win;
|
||||||
gameOver = true;
|
gameOver = true;
|
||||||
setMultiplayerState(activeState(), `${player} wins with four in a row.`);
|
setActiveStatus(`${player} wins with four in a row.`);
|
||||||
render();
|
render();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDraw()) {
|
if (isDraw()) {
|
||||||
gameOver = true;
|
gameOver = true;
|
||||||
setMultiplayerState(activeState(), "Draw. The board is full.");
|
setActiveStatus("Draw. The board is full.");
|
||||||
render();
|
render();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -291,7 +329,7 @@ function applyMove(row, col, player, source) {
|
|||||||
currentPlayer = opponentOf(player);
|
currentPlayer = opponentOf(player);
|
||||||
const captureMessage = captured.length > 0 ? `${player} captured ${captured.length}. ` : "";
|
const captureMessage = captured.length > 0 ? `${player} captured ${captured.length}. ` : "";
|
||||||
const turnMessage = currentPlayer === localPlayer ? "Your turn." : waitingMessage();
|
const turnMessage = currentPlayer === localPlayer ? "Your turn." : waitingMessage();
|
||||||
setMultiplayerState(activeState(), `${captureMessage}${turnMessage}`);
|
setActiveStatus(`${captureMessage}${turnMessage}`);
|
||||||
render();
|
render();
|
||||||
flashCapturedCells(captured);
|
flashCapturedCells(captured);
|
||||||
|
|
||||||
@@ -306,6 +344,15 @@ function activeState() {
|
|||||||
return gameMode === "practice" ? "local" : "paired";
|
return gameMode === "practice" ? "local" : "paired";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setActiveStatus(text) {
|
||||||
|
if (gameMode === "practice") {
|
||||||
|
setPracticeStatus(text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setMultiplayerState(activeState(), text);
|
||||||
|
}
|
||||||
|
|
||||||
function waitingMessage() {
|
function waitingMessage() {
|
||||||
return gameMode === "practice" ? "Bot turn." : `Waiting for ${currentPlayer}.`;
|
return gameMode === "practice" ? "Bot turn." : `Waiting for ${currentPlayer}.`;
|
||||||
}
|
}
|
||||||
@@ -401,6 +448,11 @@ function setMultiplayerState(state, text) {
|
|||||||
messageElement.textContent = text;
|
messageElement.textContent = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setPracticeStatus(text) {
|
||||||
|
const suffix = waitingPlayers > 0 ? " NET: player waiting." : " NET: no one waiting.";
|
||||||
|
setMultiplayerState("local", `${text}${suffix}`);
|
||||||
|
}
|
||||||
|
|
||||||
function playBotMove() {
|
function playBotMove() {
|
||||||
if (gameMode !== "practice" || gameOver || currentPlayer !== "O") {
|
if (gameMode !== "practice" || gameOver || currentPlayer !== "O") {
|
||||||
return;
|
return;
|
||||||
@@ -471,7 +523,7 @@ resetButton.addEventListener("click", () => {
|
|||||||
setupGame();
|
setupGame();
|
||||||
|
|
||||||
if (gameMode === "practice") {
|
if (gameMode === "practice") {
|
||||||
setMultiplayerState("local", "BOT practice. You are X. Random O replies after each move.");
|
setPracticeStatus("BOT practice. You are X. Random O replies after each move.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,6 +534,7 @@ resetButton.addEventListener("click", () => {
|
|||||||
practiceButton.addEventListener("click", startPracticeMode);
|
practiceButton.addEventListener("click", startPracticeMode);
|
||||||
onlineButton.addEventListener("click", () => {
|
onlineButton.addEventListener("click", () => {
|
||||||
gameMode = "online";
|
gameMode = "online";
|
||||||
|
stopLobbyPolling();
|
||||||
localPlayer = "";
|
localPlayer = "";
|
||||||
roomId = "";
|
roomId = "";
|
||||||
multiplayerState = "connecting";
|
multiplayerState = "connecting";
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
|
|
||||||
<div class="rule-card">
|
<div class="rule-card">
|
||||||
<h2>MODES</h2>
|
<h2>MODES</h2>
|
||||||
<p>BOT is local practice against random moves. NET pairs the first two connected players automatically.</p>
|
<p>BOT is local practice against random moves and shows if NET has a player waiting. NET pairs the first two connected players automatically.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ol id="moveList" class="move-list" aria-label="Move history"></ol>
|
<ol id="moveList" class="move-list" aria-label="Move history"></ol>
|
||||||
|
|||||||
16
server.js
16
server.js
@@ -76,6 +76,15 @@ const server = http.createServer((request, response) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (requestUrl.pathname === "/lobby") {
|
||||||
|
response.writeHead(200, {
|
||||||
|
"Cache-Control": "no-store",
|
||||||
|
"Content-Type": "application/json; charset=utf-8",
|
||||||
|
});
|
||||||
|
response.end(request.method === "HEAD" ? undefined : JSON.stringify(lobbyStatus()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const staticName = staticFiles.get(requestUrl.pathname);
|
const staticName = staticFiles.get(requestUrl.pathname);
|
||||||
if (!staticName) {
|
if (!staticName) {
|
||||||
response.writeHead(404);
|
response.writeHead(404);
|
||||||
@@ -257,6 +266,13 @@ function pairClients(xClient, oClient) {
|
|||||||
send(oClient, { type: "paired", player: "O", roomId });
|
send(oClient, { type: "paired", player: "O", roomId });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function lobbyStatus() {
|
||||||
|
return {
|
||||||
|
activeGames: rooms.size,
|
||||||
|
waitingPlayers: waitingClientId && clients.has(waitingClientId) ? 1 : 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function handleSocketData(client, buffer) {
|
function handleSocketData(client, buffer) {
|
||||||
if (!clients.has(client.id)) {
|
if (!clients.has(client.id)) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user