Files
WolfSheepGame/public/index.html
2026-02-09 21:24:45 +01:00

198 lines
7.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Wolf & Schafe</title>
<style>
body {
font-family: Arial, sans-serif;
background: #f2f2f2;
text-align: center;
}
#status {
font-size: 18px;
margin-bottom: 15px;
}
svg {
background: white;
border: 2px solid #ccc;
margin: auto;
display: block;
}
.node {
cursor: pointer;
stroke: #333;
stroke-width: 2;
}
.empty {
fill: #ddd;
}
.sheep {
fill: #3498db;
}
.wolf {
fill: #e74c3c;
}
.selected {
stroke: gold;
stroke-width: 5;
}
text {
pointer-events: none;
}
button {
margin: 5px;
padding: 8px 15px;
font-size: 16px;
cursor: pointer;
}
</style>
</head>
<body>
<h2 id="role">Verbinde…</h2>
<div id="status"></div>
<svg width="600" height="420"></svg>
<button id="restartBtn">🔄 Spiel neu starten</button>
<button id="copyRoomBtn">📋 Raum-Link kopieren</button>
<script>
// --- Room handling ---
const params = new URLSearchParams(window.location.search);
let roomId = params.get("room"); // Use room from URL if exists
// Prompt user only if no room in URL
if (!roomId) {
roomId = prompt("Gib den Raumcode ein oder leer lassen für neuen Raum:");
if (!roomId) roomId = ""; // server will create new room
}
// --- WebSocket connection ---
const protocol = location.protocol === "https:" ? "wss" : "ws";
const ws = new WebSocket(`${protocol}://${location.host}?room=${roomId}`);
const svg = document.querySelector("svg");
let role = null, state = null, selected = null;
// --- Board and positions ---
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 pos = { 0: [100, 210], 1: [200, 110], 2: [200, 210], 3: [200, 310], 4: [300, 110], 5: [300, 210], 6: [300, 310], 7: [400, 110], 8: [400, 210], 9: [400, 310], 10: [500, 210] };
const edges = [[0, 1], [0, 2], [0, 3], [1, 2], [2, 3], [1, 4], [2, 5], [3, 6], [4, 5], [5, 6], [4, 7], [5, 8], [6, 9], [7, 8], [8, 9], [5, 1], [5, 3], [5, 7], [5, 9], [7, 10], [8, 10], [9, 10]];
// --- WebSocket events ---
ws.onmessage = e => {
const msg = JSON.parse(e.data);
if (msg.type === "role") {
role = msg.role;
roomId = msg.roomId;
document.getElementById("role").innerText = "Du bist: " + role + " (Raum: " + roomId + ")";
}
if (msg.type === "state") { state = msg.game; render(); }
if (msg.type === "full") { alert("Raum ist voll."); }
};
// --- Render ---
function render() {
svg.innerHTML = "";
document.getElementById("status").innerText = state.turn === role ? "🟢 Du bist am Zug" : "⏳ Gegner ist am Zug";
// Draw Edges
edges.forEach(([a, b]) => {
const [x1, y1] = pos[a], [x2, y2] = pos[b];
const line = document.createElementNS("http://www.w3.org/2000/svg", "line");
line.setAttribute("x1", x1); line.setAttribute("y1", y1);
line.setAttribute("x2", x2); line.setAttribute("y2", y2);
line.setAttribute("stroke", "#aaa"); line.setAttribute("stroke-width", "4");
svg.appendChild(line);
});
// Draw Nodes
for (let i = 0; i <= 10; i++) {
const [x, y] = pos[i];
let cls = "empty";
if (state.wolf === i) cls = "wolf";
if (state.sheep.includes(i)) cls = "sheep";
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circle.setAttribute("cx", x); circle.setAttribute("cy", y); circle.setAttribute("r", 26);
// --- HIGHLIGHT LOGIC ---
let isPossibleMove = false;
if (selected !== null) {
const allowed = (role === "wolf") ? board_wolf[selected] : board_sheep[selected];
const isTargetEmpty = (state.wolf !== i && !state.sheep.includes(i));
if (allowed?.includes(i) && isTargetEmpty) {
isPossibleMove = true;
}
}
circle.setAttribute("class", "node " + cls + (selected === i ? " selected" : ""));
// Visual feedback for possible moves
if (isPossibleMove) {
circle.setAttribute("stroke", "lime");
circle.setAttribute("stroke-width", "6");
circle.setAttribute("stroke-dasharray", "4"); // Makes it look like a target
}
circle.onclick = () => handleClick(i);
svg.appendChild(circle);
// Add index numbers
const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
text.setAttribute("x", x); text.setAttribute("y", y + 6);
text.setAttribute("text-anchor", "middle");
text.setAttribute("fill", "white");
text.textContent = i;
svg.appendChild(text);
}
}
// --- Handle clicks ---
function handleClick(i) {
if (!state || state.turn !== role) return;
const isMyPiece = (role === "wolf" && state.wolf === i) || (role === "sheep" && state.sheep.includes(i));
if (selected === null) { if (!isMyPiece) return; selected = i; render(); }
else { ws.send(JSON.stringify({ from: selected, to: i })); selected = null; render(); }
}
// --- Restart button ---
document.getElementById("restartBtn").onclick = () => {
ws.send(JSON.stringify({ type: "restart" }));
selected = null;
};
// --- Copy room link button ---
document.getElementById("copyRoomBtn").onclick = () => {
if (!roomId) return;
const url = `${location.origin}?room=${roomId}`;
navigator.clipboard.writeText(url)
.then(() => alert("Raum-Link kopiert!"))
.catch(() => alert("Kopieren fehlgeschlagen"));
};
</script>
</body>
</html>