Persistant rooms
This commit is contained in:
69
server.js
69
server.js
@@ -9,16 +9,15 @@ app.use(express.static("public"));
|
||||
const server = http.createServer(app);
|
||||
const wss = new WebSocket.Server({ server });
|
||||
|
||||
// Movement logic: Wolf can move anywhere, Sheep only forward
|
||||
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]
|
||||
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:[]
|
||||
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 = {};
|
||||
@@ -28,39 +27,27 @@ function broadcast(roomId) {
|
||||
if (!room) return;
|
||||
const msg = JSON.stringify({ type: "state", game: room.game });
|
||||
room.players.forEach(p => {
|
||||
if (p.ws.readyState === WebSocket.OPEN) p.ws.send(msg);
|
||||
if (p.ws && p.ws.readyState === WebSocket.OPEN) p.ws.send(msg);
|
||||
});
|
||||
}
|
||||
|
||||
function checkWinConditions(game) {
|
||||
// 1. Wolf reaches node 0
|
||||
if (game.wolf === 0) return "wolf";
|
||||
|
||||
// 2. Turn limit (40 moves)
|
||||
if (game.moveCount >= 40) return "wolf";
|
||||
|
||||
// Mobility Check helpers
|
||||
const canWolfMove = board_wolf[game.wolf].some(to =>
|
||||
!game.sheep.includes(to)
|
||||
);
|
||||
|
||||
const canSheepMove = game.sheep.some(from =>
|
||||
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))
|
||||
);
|
||||
|
||||
// 3. Wolf trapped
|
||||
if (!canWolfMove) return "sheep";
|
||||
|
||||
// 4. Sheep cannot move
|
||||
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;
|
||||
|
||||
@@ -78,20 +65,16 @@ function handleMove(roomId, role, { from, to }) {
|
||||
game.sheep[i] = to;
|
||||
game.turn = "wolf";
|
||||
}
|
||||
|
||||
game.moveCount++;
|
||||
game.winner = checkWinConditions(game);
|
||||
broadcast(roomId);
|
||||
}
|
||||
|
||||
wss.on("connection", (ws, req) => {
|
||||
ws.isAlive = true;
|
||||
ws.on("pong", () => ws.isAlive = true);
|
||||
|
||||
const urlParams = new URLSearchParams(req.url.split('?')[1]);
|
||||
let roomId = urlParams.get("room");
|
||||
let sessionId = urlParams.get("sessionId");
|
||||
|
||||
// Room creation/joining logic
|
||||
if (!roomId || !rooms[roomId]) {
|
||||
if (!roomId) roomId = randomBytes(3).toString("hex");
|
||||
rooms[roomId] = {
|
||||
@@ -101,16 +84,23 @@ wss.on("connection", (ws, req) => {
|
||||
}
|
||||
|
||||
const room = rooms[roomId];
|
||||
if (room.players.length >= 2) {
|
||||
let player = room.players.find(p => p.sessionId === sessionId);
|
||||
|
||||
if (!player && room.players.length >= 2) {
|
||||
ws.send(JSON.stringify({ type: "full" }));
|
||||
ws.close();
|
||||
return;
|
||||
}
|
||||
|
||||
const role = room.players.length === 0 ? "sheep" : "wolf";
|
||||
room.players.push({ ws, role });
|
||||
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, roomId }));
|
||||
ws.send(JSON.stringify({ type: "role", role: player.role, roomId }));
|
||||
broadcast(roomId);
|
||||
|
||||
ws.on("message", msg => {
|
||||
@@ -120,23 +110,18 @@ wss.on("connection", (ws, req) => {
|
||||
if (data.type === "restart") {
|
||||
room.game = { wolf: 5, sheep: [0, 1, 3], turn: "sheep", moveCount: 0, winner: null };
|
||||
broadcast(roomId);
|
||||
return;
|
||||
} 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);
|
||||
}
|
||||
handleMove(roomId, role, data);
|
||||
});
|
||||
|
||||
ws.on("close", () => {
|
||||
room.players = room.players.filter(p => p.ws !== ws);
|
||||
if (room.players.length === 0) delete rooms[roomId];
|
||||
// We don't remove the player here so they can reconnect on refresh
|
||||
});
|
||||
});
|
||||
|
||||
setInterval(() => {
|
||||
wss.clients.forEach(ws => {
|
||||
if (!ws.isAlive) return ws.terminate();
|
||||
ws.isAlive = false;
|
||||
ws.ping();
|
||||
});
|
||||
}, 30000);
|
||||
|
||||
server.listen(3030, () => console.log("Server läuft auf Port 3030"));
|
||||
Reference in New Issue
Block a user