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

424 lines
18 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>Halli Galli - KinderWelt</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; user-select: none; }
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh; display: flex; flex-direction: column; align-items: center;
font-family: 'Comic Sans MS', cursive, sans-serif; padding: 15px;
}
h1 { color: white; margin-bottom: 5px; font-size: 24px; }
.age-hint {
color: #FEF3C7; font-size: 14px; margin-bottom: 10px; text-align: center;
}
.difficulty-select {
display: flex; gap: 8px; margin: 10px 0; flex-wrap: wrap; justify-content: center;
}
.diff-btn {
background: rgba(255,255,255,0.2); border: 2px solid white; color: white;
padding: 8px 15px; border-radius: 20px; cursor: pointer; font-family: inherit;
font-size: 13px; transition: all 0.2s;
}
.diff-btn.active {
background: white; color: #667eea; font-weight: bold;
transform: scale(1.05);
}
.diff-btn:hover { background: rgba(255,255,255,0.4); }
.diff-desc {
color: #FEF3C7; font-size: 12px; text-align: center; margin: 5px 0; max-width: 350px;
min-height: 30px;
}
.game-area {
display: flex; gap: 20px; margin: 15px 0; flex-wrap: wrap; justify-content: center;
}
.card-display {
width: 130px; height: 180px; background: white; border-radius: 15px;
display: flex; flex-direction: column; align-items: center; justify-content: center;
box-shadow: 0 10px 30px rgba(0,0,0,0.3); position: relative; border: 4px solid #333;
transition: all 0.3s;
}
.card-display.match {
animation: pulse-match 0.5s ease-in-out;
border-color: #FFD700;
box-shadow: 0 0 30px #FFD700;
}
@keyframes pulse-match {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.card-emoji { font-size: 60px; }
.card-number {
font-size: 36px; font-weight: bold; color: #333;
margin-top: 5px;
}
.card-count {
position: absolute; bottom: 10px; font-size: 12px; color: #666; font-weight: bold;
}
.player-name {
position: absolute; top: 10px; font-size: 11px; color: #999; font-weight: bold;
}
.big-hint {
position: absolute; top: -40px; left: 50%; transform: translateX(-50%);
background: #FFD700; color: #333; padding: 5px 15px; border-radius: 20px;
font-size: 14px; font-weight: bold; display: none; animation: bounce 0.5s infinite;
}
@keyframes bounce {
0%, 100% { transform: translateX(-50%) translateY(0); }
50% { transform: translateX(-50%) translateY(-5px); }
}
.bell-area {
width: 160px; height: 160px; background: linear-gradient(135deg, #FFD700, #FFA500);
border-radius: 50%; display: flex; flex-direction: column; align-items: center; justify-content: center;
cursor: pointer; box-shadow: 0 10px 30px rgba(0,0,0,0.4);
border: 8px solid #FF8C00; transition: all 0.1s; position: relative;
}
.bell-area:active { transform: scale(0.95); }
.bell { font-size: 80px; }
.bell.ringing { animation: ring 0.3s ease-in-out; }
@keyframes ring {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(-15deg); }
75% { transform: rotate(15deg); }
}
.bell-hint {
position: absolute; bottom: 15px; font-size: 11px; color: #333; font-weight: bold;
}
.score-board {
display: flex; gap: 30px; margin: 10px 0; color: white; font-size: 16px;
}
.score-item { text-align: center; }
.score-value { font-size: 28px; font-weight: bold; color: #feca57; }
.status {
color: white; font-size: 18px; margin: 10px 0; text-align: center;
min-height: 50px; font-weight: bold;
}
.fruit-counter {
display: flex; gap: 10px; margin: 10px 0; flex-wrap: wrap; justify-content: center;
}
.fruit-box {
background: rgba(255,255,255,0.2); padding: 8px 12px; border-radius: 10px;
color: white; font-size: 13px; text-align: center; min-width: 70px;
}
.fruit-box.highlight {
background: #FFD700; color: #333; transform: scale(1.1);
box-shadow: 0 0 15px rgba(255,215,0,0.5);
}
.fruit-count { font-size: 20px; font-weight: bold; }
.controls { display: flex; gap: 15px; margin-top: 15px; }
.btn {
background: white; border: none; border-radius: 10px; padding: 12px 25px;
font-size: 16px; cursor: pointer; font-family: inherit; font-weight: bold;
}
.btn-start { background: #4ade80; color: white; }
.btn-back { background: #ff6b6b; color: white; text-decoration: none; }
.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; }
</style>
</head>
<body>
<h1>🔔 Halli Galli</h1>
<div class="age-hint">👶 Kindermodus: Große Zahlen, visuelle Hilfen, mehr Zeit</div>
<div class="difficulty-select" id="diffSelect">
<button class="diff-btn active" onclick="setDifficulty('baby')">👶 Baby (5 J.)</button>
<button class="diff-btn" onclick="setDifficulty('easy')">🟢 Einfach</button>
<button class="diff-btn" onclick="setDifficulty('medium')">🟡 Mittel</button>
<button class="diff-btn" onclick="setDifficulty('hard')">🔴 Schwer</button>
</div>
<div class="diff-desc" id="diffDesc">Visuelle Hilfen + 4 Sekunden Zeit zum Reagieren</div>
<div class="score-board">
<div class="score-item">
<div>Deine Karten</div>
<div class="score-value" id="playerCards">20</div>
</div>
<div class="score-item">
<div>Computer</div>
<div class="score-value" id="botCards">20</div>
</div>
</div>
<div class="game-area">
<div class="card-display" id="playerCard">
<div class="big-hint" id="playerHint">🔔 KLINGELN!</div>
<div class="player-name">DU</div>
<div class="card-emoji" id="playerEmoji"></div>
<div class="card-number" id="playerNum"></div>
<div class="card-count" id="playerCount">20 Karten</div>
</div>
<div class="bell-area" id="bell" onclick="ringBell()">
<div class="bell">🔔</div>
<div class="bell-hint" id="bellHint">Klick mich!</div>
</div>
<div class="card-display" id="botCard">
<div class="player-name">COMPUTER</div>
<div class="card-emoji" id="botEmoji"></div>
<div class="card-number" id="botNum"></div>
<div class="card-count" id="botCount">20 Karten</div>
</div>
</div>
<div class="status" id="status">Wähle den Schwierigkeitsgrad für deine Tochter! 👧</div>
<div class="fruit-counter" id="fruitCounter">
<div class="fruit-box" id="appleBox">
<div>🍎</div>
<div class="fruit-count" id="appleCount">0</div>
</div>
<div class="fruit-box" id="bananaBox">
<div>🍌</div>
<div class="fruit-count" id="bananaCount">0</div>
</div>
<div class="fruit-box" id="grapeBox">
<div>🍇</div>
<div class="fruit-count" id="grapeCount">0</div>
</div>
<div class="fruit-box" id="strawberryBox">
<div>🍓</div>
<div class="fruit-count" id="strawberryCount">0</div>
</div>
</div>
<div class="controls">
<button class="btn btn-start" id="startBtn" onclick="startGame()">🎮 Start</button>
<a href="../index.html" class="btn btn-back">⬅️ Zurück</a>
</div>
<div class="game-over" id="gameOver">
<h2 id="winnerText">🎉 Gewonnen!</h2>
<button class="btn btn-start" onclick="resetGame()">🔄 Nochmal</button>
</div>
<script>
const FRUITS = ['🍎', '🍌', '🍇', '🍓'];
const DIFFICULTY = {
baby: { time: 4000, showHint: true, showCounter: true, desc: '👶 Baby: 4 Sekunden + große Hilfen' },
easy: { time: 2500, showHint: true, showCounter: true, desc: '🟢 Einfach: 2.5 Sekunden + Hilfen' },
medium: { time: 1500, showHint: false, showCounter: true, desc: '🟡 Mittel: 1.5 Sekunden + Zähler' },
hard: { time: 800, showHint: false, showCounter: false, desc: '🔴 Schwer: 0.8 Sekunden, alles selbst!' }
};
let difficulty = 'baby';
let playerDeck = [], botDeck = [];
let playerCard = null, botCard = null;
let gameRunning = false, canRing = false;
let botTimer = null;
function setDifficulty(diff) {
difficulty = diff;
document.querySelectorAll('.diff-btn').forEach(b => b.classList.remove('active'));
event.target.classList.add('active');
document.getElementById('diffDesc').textContent = DIFFICULTY[diff].desc;
}
function createDeck() {
const deck = [];
FRUITS.forEach(fruit => {
for (let i = 1; i <= 5; i++) deck.push({ fruit, num: i });
});
// Doppelte Menge für 40 Karten insgesamt
return shuffle([...deck, ...deck]);
}
function shuffle(a) {
for (let i = a.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[a[i], a[j]] = [a[j], a[i]];
}
return a;
}
function startGame() {
const deck = createDeck();
playerDeck = deck.slice(0, 20);
botDeck = deck.slice(20);
gameRunning = true; canRing = false;
document.getElementById('startBtn').style.display = 'none';
document.getElementById('diffSelect').style.display = 'none';
document.getElementById('diffDesc').style.display = 'none';
document.getElementById('fruitCounter').style.display =
DIFFICULTY[difficulty].showCounter ? 'flex' : 'none';
updateDisplay();
nextTurn();
}
function nextTurn() {
if (!gameRunning) return;
if (playerDeck.length === 0) { endGame(false); return; }
if (botDeck.length === 0) { endGame(true); return; }
// Verstecke Hinweise
document.getElementById('playerHint').style.display = 'none';
document.getElementById('bellHint').style.display = 'none';
document.querySelectorAll('.fruit-box').forEach(b => b.classList.remove('highlight'));
document.querySelectorAll('.card-display').forEach(c => c.classList.remove('match'));
playerCard = playerDeck.shift();
botCard = botDeck.shift();
updateDisplay();
updateCounters();
const counts = { '🍎': 0, '🍌': 0, '🍇': 0, '🍓': 0 };
if (playerCard) counts[playerCard.fruit] += playerCard.num;
if (botCard) counts[botCard.fruit] += botCard.num;
const hasFive = Object.values(counts).includes(5);
if (hasFive) {
canRing = true;
document.getElementById('status').textContent = '🔔 FÜNF! Schnell klingeln!';
document.getElementById('status').style.color = '#FFD700';
// Visuelle Hilfen für Kinder
if (DIFFICULTY[difficulty].showHint) {
document.getElementById('playerHint').style.display = 'block';
document.getElementById('bellHint').style.display = 'block';
document.getElementById('playerCard').classList.add('match');
document.getElementById('botCard').classList.add('match');
// Highlight richtige Frucht
for (let [fruit, count] of Object.entries(counts)) {
if (count === 5) {
const boxId = fruit === '🍎' ? 'appleBox' :
fruit === '🍌' ? 'bananaBox' :
fruit === '🍇' ? 'grapeBox' : 'strawberryBox';
document.getElementById(boxId).classList.add('highlight');
}
}
}
// Bot reagiert
botTimer = setTimeout(() => {
if (gameRunning && canRing) botRing();
}, DIFFICULTY[difficulty].time);
} else {
canRing = false;
document.getElementById('status').textContent = 'Keine 5 gleichen... Nächste Karte!';
document.getElementById('status').style.color = 'white';
setTimeout(nextTurn, 1500);
}
}
function updateCounters() {
const counts = { '🍎': 0, '🍌': 0, '🍇': 0, '🍓': 0 };
if (playerCard) counts[playerCard.fruit] += playerCard.num;
if (botCard) counts[botCard.fruit] += botCard.num;
document.getElementById('appleCount').textContent = counts['🍎'];
document.getElementById('bananaCount').textContent = counts['🍌'];
document.getElementById('grapeCount').textContent = counts['🍇'];
document.getElementById('strawberryCount').textContent = counts['🍓'];
}
function updateDisplay() {
document.getElementById('playerCards').textContent = playerDeck.length;
document.getElementById('botCards').textContent = botDeck.length;
document.getElementById('playerCount').textContent = (playerDeck.length + 1) + ' Karten';
document.getElementById('botCount').textContent = (botDeck.length + 1) + ' Karten';
if (playerCard) {
document.getElementById('playerEmoji').textContent = playerCard.fruit;
document.getElementById('playerNum').textContent = playerCard.num;
}
if (botCard) {
document.getElementById('botEmoji').textContent = botCard.fruit;
document.getElementById('botNum').textContent = botCard.num;
}
}
function ringBell() {
if (!canRing || !gameRunning) {
// Falsch geklingelt - Strafe!
if (gameRunning) {
document.getElementById('status').textContent = '❌ Zu früh! Computer bekommt deine Karten!';
botDeck.push(...playerDeck.splice(0, Math.min(3, playerDeck.length)));
updateDisplay();
setTimeout(nextTurn, 2000);
}
return;
}
clearTimeout(botTimer);
canRing = false;
document.querySelector('.bell').classList.add('ringing');
setTimeout(() => document.querySelector('.bell').classList.remove('ringing'), 300);
// Gewinner bekommt alle Karten
const wonCards = [playerCard, botCard, ...playerDeck.splice(0, 2), ...botDeck.splice(0, 2)];
playerDeck.push(...wonCards.filter(c => c));
document.getElementById('status').textContent = '🎉 Super! Du hast ' + wonCards.length + ' Karten gewonnen!';
updateDisplay();
setTimeout(nextTurn, 2000);
}
function botRing() {
if (!canRing || !gameRunning) return;
canRing = false;
document.querySelector('.bell').classList.add('ringing');
setTimeout(() => document.querySelector('.bell').classList.remove('ringing'), 300);
const wonCards = [playerCard, botCard, ...playerDeck.splice(0, 2), ...botDeck.splice(0, 2)];
botDeck.push(...wonCards.filter(c => c));
document.getElementById('status').textContent = '🤖 Computer war schneller!';
updateDisplay();
setTimeout(nextTurn, 2000);
}
function endGame(playerWon) {
gameRunning = false;
document.getElementById('winnerText').innerHTML = playerWon ?
'🎉 Du hast gewonnen!' : '🤖 Computer gewinnt!';
document.getElementById('gameOver').style.display = 'block';
}
function resetGame() {
document.getElementById('gameOver').style.display = 'none';
document.getElementById('startBtn').style.display = 'block';
document.getElementById('diffSelect').style.display = 'flex';
document.getElementById('diffDesc').style.display = 'block';
document.getElementById('fruitCounter').style.display = 'none';
document.getElementById('status').textContent = 'Wähle den Schwierigkeitsgrad!';
document.getElementById('status').style.color = 'white';
playerCard = null; botCard = null;
document.getElementById('playerEmoji').textContent = '❓';
document.getElementById('playerNum').textContent = '';
document.getElementById('botEmoji').textContent = '❓';
document.getElementById('botNum').textContent = '';
updateDisplay();
}
</script>
</body>
</html>