Files
WolfSheepGame/server.js
2026-02-09 22:13:02 +01:00

127 lines
3.9 KiB
JavaScript

const express = require("express");
const http = require("http");
const WebSocket = require("ws");
const { randomBytes } = require("crypto");
const app = express();
app.use(express.static("public"));
const server = http.createServer(app);
const wss = new WebSocket.Server({ server });
const board_wolf = {
0: [1, 2, 3], 1: [0, 2, 4, 5], 2: [0, 1, 3, 5], 3: [0, 2, 5, 6], 4: [1, 5, 7],
5: [1, 2, 3, 4, 6, 7, 8, 9], 6: [3, 5, 9], 7: [4, 5, 8, 10], 8: [5, 7, 9, 10],
9: [5, 6, 8, 10], 10: [7, 8, 9]
};
const board_sheep = {
0: [1, 2, 3], 1: [2, 4, 5], 2: [1, 3, 5], 3: [2, 5, 6], 4: [5, 7],
5: [4, 6, 7, 8, 9], 6: [5, 9], 7: [8, 10], 8: [7, 9, 10], 9: [8, 10], 10: []
};
const rooms = {};
function broadcast(roomId) {
const room = rooms[roomId];
if (!room) return;
const msg = JSON.stringify({ type: "state", game: room.game });
room.players.forEach(p => {
if (p.ws && p.ws.readyState === WebSocket.OPEN) p.ws.send(msg);
});
}
function checkWinConditions(game) {
if (game.wolf === 0) return "wolf";
if (game.moveCount >= 40) return "wolf";
const canWolfMove = board_wolf[game.wolf].some(to => !game.sheep.includes(to));
const canSheepMove = game.sheep.some(from =>
board_sheep[from].some(to => to !== game.wolf && !game.sheep.includes(to))
);
if (!canWolfMove) return "sheep";
if (!canSheepMove && game.turn === "sheep") return "wolf";
return null;
}
function handleMove(roomId, role, { from, to }) {
const room = rooms[roomId];
if (!room || room.game.winner) return;
const game = room.game;
if (game.turn !== role) return;
const allowed = (role === "wolf") ? board_wolf[from] : board_sheep[from];
if (!allowed?.includes(to)) return;
if (game.sheep.includes(to) || game.wolf === to) return;
if (role === "wolf") {
if (from !== game.wolf) return;
game.wolf = to;
game.turn = "sheep";
} else {
const i = game.sheep.indexOf(from);
if (i === -1) return;
game.sheep[i] = to;
game.turn = "wolf";
}
game.moveCount++;
game.winner = checkWinConditions(game);
broadcast(roomId);
}
wss.on("connection", (ws, req) => {
const urlParams = new URLSearchParams(req.url.split('?')[1]);
let roomId = urlParams.get("room");
let sessionId = urlParams.get("sessionId");
if (!roomId || !rooms[roomId]) {
if (!roomId) roomId = randomBytes(3).toString("hex");
rooms[roomId] = {
game: { wolf: 5, sheep: [0, 1, 3], turn: "sheep", moveCount: 0, winner: null },
players: []
};
}
const room = rooms[roomId];
let player = room.players.find(p => p.sessionId === sessionId);
if (!player && room.players.length >= 2) {
ws.send(JSON.stringify({ type: "full" }));
ws.close();
return;
}
if (player) {
player.ws = ws; // Re-attach new socket to existing session
} else {
const role = room.players.length === 0 ? "sheep" : "wolf";
player = { ws, role, sessionId };
room.players.push(player);
}
ws.send(JSON.stringify({ type: "role", role: player.role, roomId }));
broadcast(roomId);
ws.on("message", msg => {
let data;
try { data = JSON.parse(msg); } catch { return; }
if (data.type === "restart") {
room.game = { wolf: 5, sheep: [0, 1, 3], turn: "sheep", moveCount: 0, winner: null };
broadcast(roomId);
} else if (data.type === "leave") {
room.players = room.players.filter(p => p.sessionId !== sessionId);
if (room.players.length === 0) delete rooms[roomId];
ws.close();
} else {
handleMove(roomId, player.role, data);
}
});
ws.on("close", () => {
// We don't remove the player here so they can reconnect on refresh
});
});
server.listen(3030, () => console.log("Server läuft auf Port 3030"));