Files
2026-04-26 09:44:19 +02:00

661 lines
26 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>Mensch ärgere dich nicht - KinderWelt</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; user-select: none; }
body {
background: linear-gradient(135deg, #FEF3C7 0%, #FDE68A 100%);
min-height: 100vh; display: flex; flex-direction: column; align-items: center;
font-family: 'Comic Sans MS', cursive, sans-serif; padding: 10px;
}
h1 { color: #92400E; margin-bottom: 5px; font-size: 22px; text-align: center; }
.setup-screen {
background: white; padding: 20px; border-radius: 15px; max-width: 400px;
width: 95%; box-shadow: 0 10px 30px rgba(0,0,0,0.2);
}
.setup-screen h2 { color: #333; margin-bottom: 15px; text-align: center; font-size: 20px; }
.player-setup { margin: 12px 0; }
.player-label {
display: flex; align-items: center; padding: 8px 12px; border-radius: 8px;
font-weight: bold; margin-bottom: 5px; font-size: 14px;
}
.player-label.red { background: #FEE2E2; color: #991B1B; }
.player-label.blue { background: #DBEAFE; color: #1E40AF; }
.player-label.green { background: #D1FAE5; color: #065F46; }
.player-label.yellow { background: #FEF3C7; color: #92400E; }
.player-setup input[type="text"] {
width: 100%; padding: 10px; border: 2px solid #E5E7EB; border-radius: 8px;
font-family: inherit; font-size: 14px;
}
.player-setup input.name-red { border-color: #EF4444; }
.player-setup input.name-blue { border-color: #3B82F6; }
.player-setup input.name-green { border-color: #10B981; }
.player-setup input.name-yellow { border-color: #F59E0B; }
.checkbox-wrapper { display: flex; align-items: center; gap: 8px; margin-top: 5px; font-size: 13px; }
.checkbox-wrapper input { width: 18px; height: 18px; }
.rules-check {
background: #F3F4F6; padding: 12px; border-radius: 8px; margin: 15px 0;
}
.rules-check label { display: flex; align-items: center; gap: 8px; font-size: 14px; cursor: pointer; }
.btn {
background: #10B981; color: white; border: none; border-radius: 10px;
padding: 12px 30px; font-size: 16px; cursor: pointer; font-family: inherit; font-weight: bold;
width: 100%; margin-top: 10px;
}
.btn:hover { background: #059669; }
.btn-back { background: #EF4444; text-decoration: none; display: inline-block; text-align: center; }
/* Spielbrett */
.game-container { display: none; flex-direction: column; align-items: center; }
.board {
display: grid; grid-template-columns: repeat(11, 32px); gap: 1px;
background: #D1D5DB; padding: 8px; border-radius: 10px;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}
.cell {
width: 32px; height: 32px; background: white; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
position: relative; font-size: 10px;
}
/* Home-Bereiche (Ecken) */
.home-red { background: #FEE2E2; }
.home-blue { background: #DBEAFE; }
.home-green { background: #D1FAE5; }
.home-yellow { background: #FEF3C7; }
/* Ziel-Bereiche */
.goal-red { background: #FECACA; }
.goal-blue { background: #BFDBFE; }
.goal-green { background: #A7F3D0; }
.goal-yellow { background: #FDE68A; }
/* Startfelder */
.start-red { background: #EF4444; }
.start-blue { background: #3B82F6; }
.start-green { background: #10B981; }
.start-yellow { background: #F59E0B; }
/* Figuren */
.piece {
width: 26px; height: 26px; border-radius: 50%; position: absolute;
border: 2px solid white; box-shadow: 2px 2px 4px rgba(0,0,0,0.4);
display: flex; align-items: center; justify-content: center;
font-size: 11px; font-weight: bold; color: white; cursor: pointer;
transition: all 0.3s;
}
.piece:hover { transform: scale(1.2); }
.piece.red { background: #DC2626; }
.piece.blue { background: #2563EB; }
.piece.green { background: #059669; }
.piece.yellow { background: #D97706; color: white; }
.piece.selected { box-shadow: 0 0 0 3px #FFD700, 0 0 15px #FFD700; }
.piece.movable { animation: pulse 1s infinite; }
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.1); }
}
/* Würfel */
.dice-area { margin: 15px 0; }
.dice {
width: 70px; height: 70px; background: white; border-radius: 12px;
display: flex; align-items: center; justify-content: center;
font-size: 40px; cursor: pointer; border: 3px solid #374151;
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
.dice.rolling { animation: shake 0.5s ease-in-out; }
@keyframes shake {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(-10deg); }
75% { transform: rotate(10deg); }
}
.status-bar {
background: white; padding: 12px 20px; border-radius: 25px;
margin: 10px 0; font-size: 15px; text-align: center;
box-shadow: 0 3px 10px rgba(0,0,0,0.1); max-width: 350px;
}
.current-player { font-weight: bold; font-size: 17px; }
.throw-indicator {
color: #059669; font-weight: bold; margin-top: 5px;
}
.controls { display: flex; gap: 10px; margin-top: 15px; flex-wrap: wrap; justify-content: center; }
.game-btn {
padding: 10px 20px; border: none; border-radius: 8px;
font-size: 14px; cursor: pointer; font-family: inherit; font-weight: bold;
}
.btn-roll { background: #10B981; color: white; }
.btn-skip { background: #6B7280; color: white; }
.game-over {
position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
background: white; padding: 30px; border-radius: 20px; text-align: center;
display: none; z-index: 100; box-shadow: 0 10px 50px rgba(0,0,0,0.5);
}
.game-over h2 { margin-bottom: 15px; color: #333; }
</style>
</head>
<body>
<h1>🎲 Mensch ärgere dich nicht</h1>
<!-- Setup -->
<div class="setup-screen" id="setupScreen">
<h2>👥 Spieler einrichten</h2>
<div class="player-setup">
<div class="player-label red">🔴 Spieler 1 (Rot)</div>
<input type="text" id="name1" class="name-red" placeholder="Name..." value="Peter">
</div>
<div class="player-setup">
<div class="player-label blue">🔵 Spieler 2 (Blau)</div>
<input type="text" id="name2" class="name-blue" placeholder="Name..." value="Anna">
<div class="checkbox-wrapper">
<input type="checkbox" id="bot2" onchange="toggleBot(2)">
<label for="bot2">🤖 Computer</label>
</div>
</div>
<div class="player-setup">
<div class="player-label green">🟢 Spieler 3 (Grün)</div>
<input type="text" id="name3" class="name-green" placeholder="Name...">
<div class="checkbox-wrapper">
<input type="checkbox" id="bot3" onchange="toggleBot(3)">
<label for="bot3">🤖 Computer</label>
</div>
</div>
<div class="player-setup">
<div class="player-label yellow">🟡 Spieler 4 (Gelb)</div>
<input type="text" id="name4" class="name-yellow" placeholder="Name...">
<div class="checkbox-wrapper">
<input type="checkbox" id="bot4" onchange="toggleBot(4)">
<label for="bot4">🤖 Computer</label>
</div>
</div>
<div class="rules-check">
<label>
<input type="checkbox" id="forceKick" checked>
<span>🎯 Schmeißen ist Pflicht</span>
</label>
</div>
<button class="btn" onclick="startGame()">🎮 Spiel starten</button>
<a href="../index.html" class="btn btn-back" style="margin-top:10px;display:block">⬅️ Zurück</a>
</div>
<!-- Spiel -->
<div class="game-container" id="gameScreen">
<div class="status-bar" id="statusBar">
<div class="current-player" id="currentPlayerName">Peter ist dran!</div>
<div id="gameStatus">Würfle eine 6 zum Starten!</div>
<div class="throw-indicator" id="throwIndicator"></div>
</div>
<div class="board" id="board"></div>
<div class="dice-area">
<div class="dice" id="dice" onclick="roll()">🎲</div>
</div>
<div class="controls">
<button class="game-btn btn-roll" onclick="roll()">🎲 Würfeln</button>
<button class="game-btn btn-skip" onclick="skipTurn()">⏭️ Zug beenden</button>
<button class="game-btn" onclick="resetGame()">🔄 Neustart</button>
<a href="../index.html" class="game-btn btn-back">⬅️ Menü</a>
</div>
</div>
<div class="game-over" id="gameOver">
<h2 id="winnerText">🎉 Gewinner!</h2>
<button class="btn" onclick="resetGame()" style="width:auto">🔄 Nochmal</button>
</div>
<script>
// Spielbrett-Layout (11x11 Grid)
// Positionen: -4 bis -1 = Home, 0-39 = Weg, 40-43 = Ziel
const PLAYERS = [
{ color: 'red', name: 'Rot', emoji: '🔴', startField: 0 },
{ color: 'blue', name: 'Blau', emoji: '🔵', startField: 10 },
{ color: 'green', name: 'Grün', emoji: '🟢', startField: 20 },
{ color: 'yellow', name: 'Gelb', emoji: '🟡', startField: 30 }
];
let players = []; // { name, color, isBot, pieces: [pos, pos, pos, pos], finished }
let currentPlayer = 0;
let currentRoll = 0;
let throwsLeft = 0; // 3 Würfe wenn alle im Start
let selectedPiece = null;
let gameRunning = false;
let forceKickRule = true;
let hasRolled = false;
function toggleBot(num) {
const checkbox = document.getElementById('bot' + num);
const input = document.getElementById('name' + num);
if (checkbox.checked) {
input.value = '🤖 Computer ' + (num-1);
input.disabled = true;
} else {
input.value = '';
input.disabled = false;
}
}
function startGame() {
forceKickRule = document.getElementById('forceKick').checked;
players = [];
for (let i = 0; i < 4; i++) {
const name = document.getElementById('name' + (i+1)).value.trim();
if (name) {
players.push({
id: i,
name: name,
color: PLAYERS[i].color,
isBot: document.getElementById('bot' + (i+1))?.checked || false,
pieces: [-1, -1, -1, -1], // -1 = Home, 0-39 = Weg, 40-43 = Ziel
finished: 0
});
}
}
if (players.length < 2) {
alert('Mindestens 2 Spieler!');
return;
}
document.getElementById('setupScreen').style.display = 'none';
document.getElementById('gameScreen').style.display = 'flex';
initBoard();
currentPlayer = 0;
throwsLeft = calculateThrows();
updateStatus();
gameRunning = true;
if (players[0].isBot) setTimeout(botTurn, 1000);
}
function calculateThrows() {
const p = players[currentPlayer];
const inStart = p.pieces.filter(pos => pos === -1).length;
return (inStart === 4) ? 3 : 1;
}
function initBoard() {
const board = document.getElementById('board');
board.innerHTML = '';
// 11x11 Grid erstellen
for (let row = 0; row < 11; row++) {
for (let col = 0; col < 11; col++) {
const cell = document.createElement('div');
cell.className = 'cell';
cell.dataset.row = row;
cell.dataset.col = col;
// Home-Bereiche (Ecken)
if (row < 4 && col < 4) {
cell.classList.add('home-red');
cell.dataset.home = '0';
} else if (row < 4 && col > 6) {
cell.classList.add('home-blue');
cell.dataset.home = '1';
} else if (row > 6 && col < 4) {
cell.classList.add('home-green');
cell.dataset.home = '2';
} else if (row > 6 && col > 6) {
cell.classList.add('home-yellow');
cell.dataset.home = '3';
}
// Ziel-Bereiche
else if (row === 5 && col === 5) {
cell.style.background = '#FEF3C7'; // Mitte
}
else if (row === 5 && col >= 1 && col <= 4) {
cell.classList.add('goal-red');
}
else if (col === 5 && row >= 1 && row <= 4) {
cell.classList.add('goal-blue');
}
else if (row === 5 && col >= 6 && col <= 9) {
cell.classList.add('goal-green');
}
else if (col === 5 && row >= 6 && row <= 9) {
cell.classList.add('goal-yellow');
}
// Weg mit Startfeldern
else if (isPath(row, col)) {
const pathIdx = getPathIndex(row, col);
if (pathIdx !== null) {
// Startfelder markieren
if (pathIdx === 0) cell.classList.add('start-red');
else if (pathIdx === 10) cell.classList.add('start-blue');
else if (pathIdx === 20) cell.classList.add('start-green');
else if (pathIdx === 30) cell.classList.add('start-yellow');
cell.dataset.path = pathIdx;
}
}
board.appendChild(cell);
}
}
updatePieces();
}
function isPath(row, col) {
// Äußerer Ring + Verbindungen
return (row === 0 || row === 10 || col === 0 || col === 10 ||
(row === 4 || row === 6) && col >= 4 && col <= 6 ||
(col === 4 || col === 6) && row >= 4 && row <= 6);
}
function getPathIndex(row, col) {
// Vereinfachte Pfad-Berechnung
const paths = [
[4,0], [4,1], [4,2], [4,3], [4,4], // Rot Start
[3,4], [2,4], [1,4], [0,4], [0,5], [0,6], // Oben
[1,6], [2,6], [3,6], [4,6], // Blau Start
[4,7], [4,8], [4,9], [4,10], [5,10], [6,10], // Rechts
[6,9], [6,8], [6,7], [6,6], // Grün Start
[7,6], [8,6], [9,6], [10,6], [10,5], [10,4], // Unten
[9,4], [8,4], [7,4], [6,4], // Gelb Start
[6,3], [6,2], [6,1], [6,0], [5,0], // Links
[5,1], [5,2], [5,3] // Ziel rot
];
for (let i = 0; i < paths.length; i++) {
if (paths[i][0] === row && paths[i][1] === col) return i;
}
return null;
}
function updatePieces() {
document.querySelectorAll('.piece').forEach(p => p.remove());
players.forEach((player, pIdx) => {
player.pieces.forEach((pos, pieceIdx) => {
let cell;
if (pos === -1) {
// Home - finde freie Position
const homeCells = document.querySelectorAll(`[data-home="${pIdx}"]`);
cell = homeCells[pieceIdx] || homeCells[0];
} else if (pos >= 0 && pos < 40) {
// Auf dem Weg
const pathCells = document.querySelectorAll('[data-path]');
// Position relativ zum Startfeld
const playerStart = PLAYERS[pIdx].startField;
const adjustedPos = (pos + playerStart) % 40;
pathCells.forEach(pc => {
if (parseInt(pc.dataset.path) === adjustedPos) cell = pc;
});
} else if (pos >= 40) {
// Im Ziel
const goalPos = pos - 40;
const goalCells = document.querySelectorAll(`[class*="goal-${player.color}"]`);
cell = goalCells[goalPos];
}
if (cell) {
const piece = document.createElement('div');
piece.className = `piece ${player.color}`;
piece.textContent = pieceIdx + 1;
piece.onclick = (e) => {
e.stopPropagation();
selectPiece(pIdx, pieceIdx);
};
// Markieren wenn bewegbar
if (pIdx === currentPlayer && hasRolled && canMovePiece(pIdx, pieceIdx)) {
piece.classList.add('movable');
}
cell.appendChild(piece);
}
});
});
}
function roll() {
if (!gameRunning || hasRolled) return;
const dice = document.getElementById('dice');
dice.classList.add('rolling');
setTimeout(() => {
dice.classList.remove('rolling');
currentRoll = Math.floor(Math.random() * 6) + 1;
dice.textContent = ['⚀','⚁','⚂','⚃','⚄','⚅'][currentRoll-1];
hasRolled = true;
handleRoll(currentRoll);
}, 500);
}
function handleRoll(roll) {
const player = players[currentPlayer];
const inStart = player.pieces.filter(p => p === -1).length;
document.getElementById('gameStatus').textContent =
`${player.name} würfelt ${roll}!`;
throwsLeft--;
// Prüfen ob Zug möglich
const movable = player.pieces.map((pos, idx) => ({ pos, idx }))
.filter(({ pos, idx }) => canMove(player, idx, roll));
if (movable.length === 0) {
if (throwsLeft > 0) {
document.getElementById('gameStatus').textContent +=
` Kein Zug möglich. Noch ${throwsLeft} Versuch(e).`;
hasRolled = false;
} else {
document.getElementById('gameStatus').textContent += ' Kein Zug möglich.';
setTimeout(nextPlayer, 1500);
}
} else {
document.getElementById('gameStatus').textContent +=
` Wähle eine Figur!`;
updatePieces(); // Markiere bewegliche
if (player.isBot) {
setTimeout(() => botSelectPiece(movable), 1000);
}
}
updateThrowIndicator();
}
function canMove(player, pieceIdx, roll) {
const pos = player.pieces[pieceIdx];
if (pos === -1) {
// Starten nur mit 6
return roll === 6;
} else if (pos >= 0 && pos < 40) {
const newPos = pos + roll;
// Kann ins Ziel oder weiter
if (newPos <= 43) return true;
// Prüfen ob exakt ins Ziel
const goalEntry = 40 + (player.id * 4); // vereinfacht
return newPos <= goalEntry + 3;
}
return false;
}
function selectPiece(playerIdx, pieceIdx) {
if (playerIdx !== currentPlayer || !hasRolled) return;
const player = players[currentPlayer];
if (!canMove(player, pieceIdx, currentRoll)) {
speak('Diese Figur kann nicht bewegt werden!');
return;
}
movePiece(pieceIdx);
}
function movePiece(pieceIdx) {
const player = players[currentPlayer];
const oldPos = player.pieces[pieceIdx];
let newPos;
if (oldPos === -1) {
// Starten
newPos = 0;
} else {
newPos = oldPos + currentRoll;
}
player.pieces[pieceIdx] = newPos;
// Schmeißen?
if (forceKickRule) {
checkKick(player, newPos, pieceIdx);
}
// Gewonnen?
const inGoal = player.pieces.filter(p => p >= 40).length;
if (inGoal === 4) {
endGame(player);
return;
}
updatePieces();
if (currentRoll === 6) {
throwsLeft = calculateThrows();
hasRolled = false;
document.getElementById('gameStatus').textContent = 'Nochmal würfeln!';
} else {
setTimeout(nextPlayer, 1000);
}
}
function checkKick(player, pos, pieceIdx) {
if (pos >= 40) return; // Im Ziel nicht schmeißen
players.forEach((other, idx) => {
if (idx === currentPlayer) return;
other.pieces.forEach((otherPos, otherIdx) => {
if (otherPos === pos && otherPos >= 0 && otherPos < 40) {
other.pieces[otherIdx] = -1;
speak(`${player.name} schmeißt ${other.name} raus!`);
}
});
});
}
function botSelectPiece(movable) {
// Priorität: Kann schmeißen > ins Ziel > vorne
let best = movable[0];
movable.forEach(({ pos, idx }) => {
const newPos = pos === -1 ? 0 : pos + currentRoll;
// Kann schmeißen?
players.forEach((other, oIdx) => {
if (oIdx === currentPlayer) return;
if (other.pieces.includes(newPos)) {
best = { pos, idx };
}
});
});
movePiece(best.idx);
}
function skipTurn() {
if (!gameRunning) return;
nextPlayer();
}
function nextPlayer() {
currentPlayer = (currentPlayer + 1) % players.length;
currentRoll = 0;
hasRolled = false;
throwsLeft = calculateThrows();
selectedPiece = null;
updateStatus();
updatePieces();
if (players[currentPlayer].isBot) {
setTimeout(botTurn, 1000);
}
}
function botTurn() {
if (!gameRunning) return;
roll();
}
function updateStatus() {
const p = players[currentPlayer];
document.getElementById('currentPlayerName').textContent =
`${p.emoji} ${p.name} ist dran!`;
document.getElementById('currentPlayerName').style.color =
p.color === 'red' ? '#DC2626' :
p.color === 'blue' ? '#2563EB' :
p.color === 'green' ? '#059669' : '#D97706';
throwsLeft = calculateThrows();
updateThrowIndicator();
}
function updateThrowIndicator() {
const indicator = document.getElementById('throwIndicator');
if (throwsLeft > 1) {
indicator.textContent = `🎲 ${throwsLeft} Würfe verbleibend`;
} else if (throwsLeft === 1) {
indicator.textContent = `🎲 Letzter Wurf`;
} else {
indicator.textContent = '';
}
}
function endGame(winner) {
gameRunning = false;
document.getElementById('winnerText').innerHTML =
`🎉 ${winner.emoji} ${winner.name} hat gewonnen!`;
document.getElementById('gameOver').style.display = 'block';
}
function resetGame() {
document.getElementById('gameScreen').style.display = 'none';
document.getElementById('setupScreen').style.display = 'block';
document.getElementById('gameOver').style.display = 'none';
gameRunning = false;
}
function speak(text) {
if ('speechSynthesis' in window) {
const u = new SpeechSynthesisUtterance(text);
u.lang = 'de-DE';
speechSynthesis.speak(u);
}
}
</script>
</body>
</html>