387 lines
14 KiB
HTML
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> |