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

387 lines
14 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>Leiterspiel - KinderWelt</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; user-select: none; }
body {
background: linear-gradient(135deg, #4a5568 0%, #2d3748 100%);
min-height: 100vh; display: flex; flex-direction: column; align-items: center;
font-family: 'Comic Sans MS', cursive, sans-serif; padding: 10px;
}
h1 { color: white; margin-bottom: 10px; font-size: 22px; }
.board-container {
background: #8B7355; padding: 10px; border-radius: 15px;
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
.board {
display: grid; grid-template-columns: repeat(10, 30px); gap: 2px;
}
.cell {
width: 30px; height: 30px; border-radius: 4px;
display: flex; align-items: center; justify-content: center;
font-size: 9px; font-weight: bold; position: relative;
}
/* Schachbrett-Muster */
.cell:nth-child(even) { background: #F5DEB3; }
.cell:nth-child(odd) { background: #DEB887; }
.cell.start { background: #90EE90 !important; }
.cell.finish { background: #FFD700 !important; border: 2px solid #FFA500; }
.cell.ladder { background: #87CEEB !important; }
.cell.snake { background: #ff9999 !important; }
.cell-number { position: absolute; top: 2px; left: 2px; font-size: 7px; }
.piece {
width: 16px; height: 16px; border-radius: 50%;
position: absolute; border: 1px solid white;
box-shadow: 1px 1px 3px rgba(0,0,0,0.5);
z-index: 10; font-size: 8px; display: flex; align-items: center; justify-content: center;
}
.piece.p1 { background: #ff4444; color: white; }
.piece.p2 { background: #4444ff; color: white; }
/* Emoji auf Feldern */
.cell-icon { font-size: 14px; }
/* UI */
.turn-indicator {
background: rgba(255,255,255,0.2); padding: 10px 20px; border-radius: 20px;
color: white; margin: 10px 0; font-size: 16px;
}
.status { color: white; font-size: 14px; margin: 10px 0; text-align: center; max-width: 320px; }
/* Würfel */
.dice-area { margin: 15px 0; }
.dice {
width: 60px; height: 60px; background: white; border-radius: 10px;
display: flex; align-items: center; justify-content: center;
font-size: 30px; cursor: pointer; border: 3px solid #333;
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); }
}
.controls { display: flex; gap: 10px; margin-top: 15px; }
.btn {
background: white; border: none; border-radius: 10px; padding: 10px 20px;
font-size: 14px; cursor: pointer; font-family: inherit; font-weight: bold;
}
.btn-roll { background: #4ade80; color: white; }
.btn-back { background: #ff6b6b; color: white; text-decoration: none; }
.legend {
display: flex; gap: 15px; margin: 10px 0; flex-wrap: wrap; justify-content: center;
}
.legend-item { display: flex; align-items: center; gap: 5px; color: white; font-size: 12px; }
.legend-box { width: 18px; height: 18px; border-radius: 3px; }
.winner {
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);
}
.winner h2 { margin-bottom: 15px; }
.winner-emoji { font-size: 40px; }
</style>
</head>
<body>
<h1>🐍 Leiterspiel 🪜</h1>
<div class="turn-indicator" id="turnIndicator">
🔴 Spieler 1 ist dran!
</div>
<div class="board-container">
<div class="board" id="board"></div>
</div>
<div class="legend">
<div class="legend-item">
<div class="legend-box" style="background:#87CEEB"></div>
🪜 Leiter
</div>
<div class="legend-item">
<div class="legend-box" style="background:#ff9999"></div>
🐍 Schlange
</div>
</div>
<div class="status" id="status">Würfle und klettere hoch! Aber pass auf vor den Schlangen! 🐍</div>
<div class="dice-area">
<div class="dice" id="dice" onclick="roll()">🎲</div>
</div>
<div class="controls">
<button class="btn btn-roll" onclick="roll()">🎲 Würfeln</button>
<button class="btn" onclick="resetGame()">🔄 Neustart</button>
<a href="../index.html" class="btn btn-back">⬅️ Zurück</a>
</div>
<div class="winner" id="winner">
<h2>🎉 Gewinner! 🎉</h2>
<div class="winner-emoji" id="winnerText"></div>
<button class="btn btn-roll" onclick="resetGame()" style="margin-top: 15px">🔄 Nochmal</button>
</div>
<script>
// Leitern: von -> nach oben
const LADDERS = {
4: 14, // 4 -> 14
9: 31, // 9 -> 31
20: 38, // 20 -> 38
28: 84, // 28 -> 84
40: 59, // 40 -> 59
51: 67, // 51 -> 67
63: 81, // 63 -> 81
71: 91 // 71 -> 91
};
// Schlangen: von -> nach unten
const SNAKES = {
17: 7, // 17 -> 7
54: 34, // 54 -> 34
62: 19, // 62 -> 19
64: 60, // 64 -> 60
87: 24, // 87 -> 24
93: 73, // 93 -> 73
95: 75, // 95 -> 75
99: 78 // 99 -> 78
};
let positions = [1, 1]; // Spieler 1 und 2
let currentPlayer = 0; // 0 = Spieler 1, 1 = Spieler 2
let rolling = false;
let gameEnded = false;
function initBoard() {
const board = document.getElementById('board');
board.innerHTML = '';
// Brett: Zeile 10 (100-91), Zeile 9 (81-90), etc.
for (let row = 9; row >= 0; row--) {
const isEvenRow = row % 2 === 0;
const startNum = row * 10 + 1;
const endNum = (row + 1) * 10;
for (let i = 0; i < 10; i++) {
const num = isEvenRow ? startNum + i : endNum - i;
const cell = document.createElement('div');
cell.className = 'cell';
cell.dataset.num = num;
// Start
if (num === 1) {
cell.classList.add('start');
cell.innerHTML = '<span class="cell-icon">🏠</span>';
}
// Ziel
else if (num === 100) {
cell.classList.add('finish');
cell.innerHTML = '<span class="cell-icon">🏆</span>';
}
// Leiter
else if (LADDERS[num]) {
cell.classList.add('ladder');
cell.innerHTML = '<span class="cell-icon">🪜</span>';
cell.title = 'Nach ' + LADDERS[num];
}
// Schlange
else if (SNAKES[num]) {
cell.classList.add('snake');
cell.innerHTML = '<span class="cell-icon">🐍</span>';
cell.title = 'Nach ' + SNAKES[num];
}
else {
cell.innerHTML = '<span class="cell-number">' + num + '</span>';
}
board.appendChild(cell);
}
}
updatePieces();
}
function updatePieces() {
// Alte Figuren entfernen
document.querySelectorAll('.piece').forEach(p => p.remove());
// Neue Figuren setzen
positions.forEach((pos, idx) => {
const cell = document.querySelector(`[data-num="${pos}"]`);
if (cell) {
const piece = document.createElement('div');
piece.className = 'piece p' + (idx + 1);
piece.textContent = (idx + 1);
// Position innerhalb der Zelle
if (idx === 0) {
piece.style.top = '2px';
piece.style.left = '2px';
} else {
piece.style.bottom = '2px';
piece.style.right = '2px';
}
cell.appendChild(piece);
}
});
}
function roll() {
if (rolling || gameEnded) return;
rolling = true;
const dice = document.getElementById('dice');
dice.classList.add('rolling');
// Zufällige Zahlen zeigen während des Rollens
let rollInterval = setInterval(() => {
dice.textContent = Math.floor(Math.random() * 6) + 1;
}, 100);
setTimeout(() => {
clearInterval(rollInterval);
dice.classList.remove('rolling');
const result = Math.floor(Math.random() * 6) + 1;
dice.textContent = result;
movePlayer(result);
setTimeout(() => {
rolling = false;
}, 600);
}, 500);
}
function movePlayer(rollNum) {
const playerName = currentPlayer === 0 ? '🔴 Spieler 1' : '🔵 Spieler 2';
let currentPos = positions[currentPlayer];
let newPos = currentPos + rollNum;
const status = document.getElementById('status');
// Über 100?
if (newPos > 100) {
status.textContent = playerName + ' muss genau auf 100 kommen! Bleibt auf ' + currentPos;
speak(playerName + ' bleibt auf ' + currentPos);
switchPlayer();
return;
}
// Bewegen
status.textContent = playerName + ' würfelt ' + rollNum + ' und geht zu Feld ' + newPos;
speak(playerName.replace('🔴', '').replace('🔵', '') + ' zieht auf Feld ' + newPos);
positions[currentPlayer] = newPos;
updatePieces();
// Prüfen auf Leiter oder Schlange
setTimeout(() => {
checkSpecial(newPos);
}, 500);
}
function checkSpecial(pos) {
const status = document.getElementById('status');
const playerName = currentPlayer === 0 ? '🔴 Spieler 1' : '🔵 Spieler 2';
// Leiter?
if (LADDERS[pos]) {
const target = LADDERS[pos];
positions[currentPlayer] = target;
status.innerHTML = '🎉 ' + playerName + ' findet eine 🪜 Leiter! Hoch zu Feld ' + target + '!';
speak('Leiter! Hoch zu Feld ' + target);
updatePieces();
checkWin();
}
// Schlange?
else if (SNAKES[pos]) {
const target = SNAKES[pos];
positions[currentPlayer] = target;
status.innerHTML = '😱 ' + playerName + ' trifft auf eine 🐍 Schlange! Runter zu Feld ' + target + '!';
speak('Schlange! Runter zu Feld ' + target);
updatePieces();
checkWin();
}
// Gewonnen?
else if (pos === 100) {
checkWin();
}
else {
switchPlayer();
}
}
function checkWin() {
if (positions[currentPlayer] === 100) {
gameEnded = true;
const playerName = currentPlayer === 0 ? '🔴 Spieler 1' : '🔵 Spieler 2';
document.getElementById('winnerText').innerHTML = playerName + '<br><small>hat gewonnen! 🏆</small>';
document.getElementById('winner').style.display = 'block';
speak(playerName + ' hat gewonnen!');
} else {
switchPlayer();
}
}
function switchPlayer() {
currentPlayer = currentPlayer === 0 ? 1 : 0;
const indicator = document.getElementById('turnIndicator');
if (currentPlayer === 0) {
indicator.innerHTML = '🔴 Spieler 1 ist dran!';
} else {
indicator.innerHTML = '🔵 Spieler 2 ist dran!';
}
}
function resetGame() {
positions = [1, 1];
currentPlayer = 0;
gameEnded = false;
rolling = false;
document.getElementById('dice').textContent = '🎲';
document.getElementById('status').textContent = 'Würfle und klettere hoch! Aber pass auf vor den Schlangen! 🐍';
document.getElementById('turnIndicator').innerHTML = '🔴 Spieler 1 ist dran!';
document.getElementById('winner').style.display = 'none';
initBoard();
}
function speak(text) {
if ('speechSynthesis' in window) {
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = 'de-DE';
speechSynthesis.speak(utterance);
}
}
// Init
initBoard();
</script>
</body>
</html>