757 lines
24 KiB
HTML
757 lines
24 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Lights Out | PonyWave Tools</title>
|
||
|
||
<!-- Open Graph Meta Tags -->
|
||
<meta property="og:title" content="Lights Out | PonyWave Tools">
|
||
<meta property="og:description" content="Klassisches Lights Out Puzzle - Schalte alle Lichter aus!">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://tools.ponywave.de/lights_out">
|
||
<meta property="og:image" content="https://tools.ponywave.de/header.png">
|
||
|
||
<!-- Favicons -->
|
||
<link rel="icon" type="image/png" href="https://tools.ponywave.de/favicon.png">
|
||
<link rel="apple-touch-icon" href="https://tools.ponywave.de/favicon.png">
|
||
|
||
<!-- Umami Tracking -->
|
||
<script defer src="https://stats.ponywave.de/script"
|
||
data-website-id="9ef713d2-adb9-4906-9df5-708d8a8b9131"
|
||
data-tag="lights_out"></script>
|
||
|
||
<style>
|
||
/* CSS Variables für Theme-System */
|
||
:root {
|
||
--primary-color: #7F006E;
|
||
--secondary-color: #FF7FED;
|
||
--bg-gradient: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
|
||
--text-color: #2c3e50;
|
||
--cell-size: 60px;
|
||
--cell-bg-off: #333333;
|
||
--cell-bg-on: #FFD700;
|
||
--glow-color: rgba(255, 215, 0, 0.8);
|
||
--cell-border: #555555;
|
||
--game-bg: rgba(255, 255, 255, 0.95);
|
||
--shadow-color: rgba(0, 0, 0, 0.1);
|
||
--footer-color: rgba(255, 255, 255, 0.8);
|
||
--button-bg: #f0f0f0;
|
||
--button-hover: #e0e0e0;
|
||
--button-active: var(--primary-color);
|
||
--modal-bg: rgba(255, 255, 255, 0.98);
|
||
}
|
||
|
||
.dark-mode {
|
||
--bg-gradient: linear-gradient(135deg, #4A0040 0%, #CC65B5 100%);
|
||
--text-color: #ffffff;
|
||
--cell-bg-off: #2a2a2a;
|
||
--cell-bg-on: #FFA500;
|
||
--glow-color: rgba(255, 165, 0, 0.8);
|
||
--cell-border: #444444;
|
||
--game-bg: rgba(45, 45, 45, 0.95);
|
||
--shadow-color: rgba(0, 0, 0, 0.3);
|
||
--footer-color: rgba(0, 0, 0, 0.8);
|
||
--button-bg: #555555;
|
||
--button-hover: #666666;
|
||
--modal-bg: rgba(45, 45, 45, 0.98);
|
||
}
|
||
|
||
/* Body & Layout */
|
||
* {
|
||
box-sizing: border-box;
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
|
||
body {
|
||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||
background-image: var(--bg-gradient);
|
||
background-attachment: fixed;
|
||
color: var(--text-color);
|
||
min-height: 100vh;
|
||
padding: 20px 20px 80px;
|
||
text-align: center;
|
||
transition: background-image 0.3s ease;
|
||
}
|
||
|
||
/* Theme Toggle Button */
|
||
.theme-toggle {
|
||
position: fixed;
|
||
top: 20px;
|
||
right: 20px;
|
||
background: var(--button-bg);
|
||
color: var(--text-color);
|
||
border: none;
|
||
border-radius: 50%;
|
||
width: 50px;
|
||
height: 50px;
|
||
font-size: 1.5em;
|
||
cursor: pointer;
|
||
box-shadow: 0 2px 10px var(--shadow-color);
|
||
transition: all 0.3s ease;
|
||
z-index: 100;
|
||
}
|
||
|
||
.theme-toggle:hover {
|
||
transform: scale(1.1) rotate(15deg);
|
||
box-shadow: 0 4px 15px var(--shadow-color);
|
||
}
|
||
|
||
/* Titel */
|
||
h1 {
|
||
margin: 20px 0 30px;
|
||
font-size: 2.5em;
|
||
text-shadow: 2px 2px 4px var(--shadow-color);
|
||
}
|
||
|
||
/* Game Container */
|
||
.game-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
margin: 0 auto;
|
||
max-width: 800px;
|
||
background: var(--game-bg);
|
||
padding: 30px;
|
||
border-radius: 20px;
|
||
box-shadow: 0 8px 20px var(--shadow-color);
|
||
backdrop-filter: blur(10px);
|
||
}
|
||
|
||
/* Schwierigkeitsauswahl */
|
||
.difficulty {
|
||
display: flex;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.difficulty button {
|
||
padding: 10px 15px;
|
||
background: var(--button-bg);
|
||
color: var(--text-color);
|
||
border: 2px solid transparent;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
font-size: 0.9em;
|
||
font-weight: bold;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.difficulty button:hover {
|
||
background: var(--button-hover);
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 8px var(--shadow-color);
|
||
}
|
||
|
||
.difficulty button.active {
|
||
background: var(--button-active);
|
||
color: white;
|
||
border-color: var(--secondary-color);
|
||
}
|
||
|
||
/* Game Header */
|
||
.game-header {
|
||
display: flex;
|
||
gap: 15px;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
width: 100%;
|
||
}
|
||
|
||
.moves-counter {
|
||
font-size: 1.3em;
|
||
font-weight: bold;
|
||
padding: 10px 20px;
|
||
background: var(--button-bg);
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.btn {
|
||
padding: 10px 20px;
|
||
background: var(--button-bg);
|
||
color: var(--text-color);
|
||
border: none;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
font-size: 1em;
|
||
font-weight: bold;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.btn:hover {
|
||
background: var(--button-hover);
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 8px var(--shadow-color);
|
||
}
|
||
|
||
.btn:active {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.btn:disabled {
|
||
opacity: 0.5;
|
||
cursor: not-allowed;
|
||
transform: none;
|
||
}
|
||
|
||
/* Grid */
|
||
.grid {
|
||
display: grid;
|
||
gap: 4px;
|
||
background: var(--cell-border);
|
||
border: 3px solid var(--cell-border);
|
||
border-radius: 10px;
|
||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
|
||
margin: 20px auto;
|
||
user-select: none;
|
||
-webkit-user-select: none;
|
||
touch-action: manipulation;
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
|
||
/* Cells */
|
||
.cell {
|
||
width: var(--cell-size);
|
||
height: var(--cell-size);
|
||
background: var(--cell-bg-off);
|
||
border: 2px solid var(--cell-border);
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
border-radius: 8px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
}
|
||
|
||
.cell.on {
|
||
background: var(--cell-bg-on);
|
||
box-shadow:
|
||
0 0 20px var(--glow-color),
|
||
0 0 40px var(--glow-color) inset,
|
||
0 0 10px rgba(255, 255, 255, 0.5) inset;
|
||
}
|
||
|
||
.cell:hover:not(.animating) {
|
||
transform: scale(1.05);
|
||
border-color: var(--secondary-color);
|
||
z-index: 10;
|
||
}
|
||
|
||
.cell.animating {
|
||
animation: toggle-animation 0.3s ease;
|
||
}
|
||
|
||
@keyframes toggle-animation {
|
||
0%, 100% { transform: scale(1); }
|
||
50% { transform: scale(1.15) rotate(5deg); }
|
||
}
|
||
|
||
/* Modal System */
|
||
.modal-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: rgba(0, 0, 0, 0.75);
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 1000;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transition: opacity 0.3s ease;
|
||
}
|
||
|
||
.modal-overlay.active {
|
||
opacity: 1;
|
||
pointer-events: all;
|
||
}
|
||
|
||
.modal {
|
||
background: var(--modal-bg);
|
||
padding: 30px;
|
||
border-radius: 15px;
|
||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
|
||
max-width: 500px;
|
||
width: 90%;
|
||
position: relative;
|
||
transform: translateY(-30px);
|
||
transition: transform 0.3s ease;
|
||
}
|
||
|
||
.modal-overlay.active .modal {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.modal h2 {
|
||
margin-bottom: 15px;
|
||
font-size: 2em;
|
||
}
|
||
|
||
.modal p {
|
||
margin: 10px 0;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.modal ul {
|
||
text-align: left;
|
||
margin: 15px 0;
|
||
padding-left: 25px;
|
||
}
|
||
|
||
.modal li {
|
||
margin: 8px 0;
|
||
}
|
||
|
||
.modal .btn {
|
||
margin: 10px 5px 0;
|
||
}
|
||
|
||
.close-modal {
|
||
position: absolute;
|
||
top: 15px;
|
||
right: 15px;
|
||
background: none;
|
||
border: none;
|
||
font-size: 2em;
|
||
cursor: pointer;
|
||
color: var(--text-color);
|
||
width: 40px;
|
||
height: 40px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 50%;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.close-modal:hover {
|
||
background: var(--button-hover);
|
||
transform: rotate(90deg);
|
||
}
|
||
|
||
/* Footer */
|
||
footer {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
background-color: var(--footer-color);
|
||
color: var(--text-color);
|
||
padding: 15px;
|
||
text-align: center;
|
||
backdrop-filter: blur(10px);
|
||
}
|
||
|
||
footer a {
|
||
color: var(--text-color);
|
||
text-decoration: none;
|
||
font-weight: bold;
|
||
transition: color 0.3s ease;
|
||
}
|
||
|
||
footer a:hover {
|
||
color: var(--primary-color);
|
||
}
|
||
|
||
/* Responsive Design */
|
||
@media (max-width: 600px) {
|
||
:root {
|
||
--cell-size: 50px;
|
||
}
|
||
|
||
h1 {
|
||
font-size: 2em;
|
||
}
|
||
|
||
.game-container {
|
||
padding: 20px 15px;
|
||
}
|
||
|
||
.difficulty button {
|
||
padding: 8px 12px;
|
||
font-size: 0.85em;
|
||
}
|
||
|
||
.moves-counter {
|
||
font-size: 1.1em;
|
||
padding: 8px 15px;
|
||
}
|
||
|
||
.btn {
|
||
padding: 8px 15px;
|
||
font-size: 0.9em;
|
||
}
|
||
|
||
.modal {
|
||
padding: 20px;
|
||
}
|
||
|
||
.modal h2 {
|
||
font-size: 1.5em;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 400px) {
|
||
:root {
|
||
--cell-size: 40px;
|
||
}
|
||
|
||
h1 {
|
||
font-size: 1.5em;
|
||
margin: 10px 0 20px;
|
||
}
|
||
|
||
.difficulty {
|
||
gap: 5px;
|
||
}
|
||
|
||
.difficulty button {
|
||
padding: 6px 10px;
|
||
font-size: 0.8em;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<!-- Theme Toggle Button -->
|
||
<button class="theme-toggle" onclick="toggleTheme()">🌙</button>
|
||
|
||
<!-- Titel -->
|
||
<h1>💡 Lights Out 💡</h1>
|
||
|
||
<!-- Game Container -->
|
||
<div class="game-container">
|
||
<!-- Schwierigkeitsauswahl -->
|
||
<div class="difficulty">
|
||
<button data-size="3" onclick="changeGridSize(3)">3×3</button>
|
||
<button data-size="4" onclick="changeGridSize(4)">4×4</button>
|
||
<button data-size="5" class="active" onclick="changeGridSize(5)">5×5 (Standard)</button>
|
||
<button data-size="6" onclick="changeGridSize(6)">6×6</button>
|
||
<button data-size="7" onclick="changeGridSize(7)">7×7</button>
|
||
</div>
|
||
|
||
<!-- Game Header -->
|
||
<div class="game-header">
|
||
<div class="moves-counter">
|
||
Züge: <span id="moves">0</span>
|
||
</div>
|
||
<button class="btn" onclick="neuesSpiel()">🔄 Neues Spiel</button>
|
||
<button class="btn" id="undoBtn" onclick="undo()">↶ Undo</button>
|
||
<button class="btn" onclick="zeigeAnleitung()">❓ Anleitung</button>
|
||
</div>
|
||
|
||
<!-- Grid (dynamisch generiert) -->
|
||
<div class="grid" id="grid"></div>
|
||
</div>
|
||
|
||
<!-- Anleitung Modal -->
|
||
<div id="instructionModal" class="modal-overlay">
|
||
<div class="modal">
|
||
<button class="close-modal" onclick="schliesseModal('instructionModal')">×</button>
|
||
<h2>📖 Spielanleitung</h2>
|
||
<p><strong>Ziel:</strong> Schalte alle Lichter aus!</p>
|
||
<p><strong>Regeln:</strong></p>
|
||
<ul>
|
||
<li>Klicke auf eine Zelle, um sie und ihre 4 orthogonal angrenzenden Nachbarn umzuschalten (oben, unten, links, rechts)</li>
|
||
<li>Eingeschaltet → Ausgeschaltet, Ausgeschaltet → Eingeschaltet</li>
|
||
<li>Versuche, alle Lichter mit möglichst wenigen Zügen auszuschalten</li>
|
||
<li>Du kannst Züge mit dem Undo-Button rückgängig machen</li>
|
||
</ul>
|
||
<p><strong>Tipp:</strong> Die Reihenfolge der Klicks ist egal! Jede Zelle muss maximal einmal geklickt werden.</p>
|
||
<button class="btn" onclick="schliesseModal('instructionModal')">Verstanden!</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Gewinn-Modal -->
|
||
<div id="winModal" class="modal-overlay">
|
||
<div class="modal">
|
||
<h2>🎉 Gewonnen! 🎉</h2>
|
||
<p>Alle Lichter sind aus!</p>
|
||
<p style="font-size: 1.3em; font-weight: bold;">Züge: <span id="finalMoves">0</span></p>
|
||
<p id="bestScore" style="font-size: 1.1em; color: var(--primary-color);">
|
||
Bester Score (<span id="gridSizeLabel">5×5</span>): <span id="bestMoves">--</span> Züge
|
||
</p>
|
||
<p id="newRecord" style="display: none; font-weight: bold; color: #4CAF50; font-size: 1.2em;">
|
||
🏆 Neuer Rekord! 🏆
|
||
</p>
|
||
<button class="btn" onclick="neuesSpiel()">🔄 Neues Spiel</button>
|
||
<button class="btn" onclick="schliesseModal('winModal')">Schließen</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Footer -->
|
||
<footer>
|
||
<a href="https://tools.ponywave.de/">← Zurück zur Startseite</a> |
|
||
© <span id="currentYear"></span> <a href="https://akamaru.de" target="_blank">Akamaru</a>
|
||
</footer>
|
||
|
||
<script>
|
||
// ===== STATE MANAGEMENT =====
|
||
let gridSize = 5; // Aktuelle Grid-Größe (3-7)
|
||
let moves = 0; // Aktuelle Züge
|
||
let grid = []; // 2D-Array: grid[row][col] = true/false (on/off)
|
||
let gameWon = false; // Gewinn-Flag
|
||
let bestScores = {}; // localStorage: { '3': 15, '5': 22, ... }
|
||
let moveHistory = []; // Stack für Undo: [[row, col], ...]
|
||
|
||
// ===== INITIALISIERUNG =====
|
||
function init() {
|
||
initTheme();
|
||
loadBestScores();
|
||
neuesSpiel();
|
||
document.getElementById('currentYear').textContent = new Date().getFullYear();
|
||
}
|
||
|
||
// ===== GRID-FUNKTIONEN =====
|
||
function initGrid() {
|
||
// Starte mit leerem Grid (alle Lichter aus)
|
||
grid = Array(gridSize).fill(null).map(() => Array(gridSize).fill(false));
|
||
|
||
// Rückwärts-Simulation: Zufällige Klicks für lösbare Konfiguration
|
||
const numRandomClicks = Math.floor(gridSize * gridSize * 0.6);
|
||
const clickedCells = new Set();
|
||
|
||
for (let i = 0; i < numRandomClicks; i++) {
|
||
const row = Math.floor(Math.random() * gridSize);
|
||
const col = Math.floor(Math.random() * gridSize);
|
||
const key = `${row},${col}`;
|
||
|
||
// Vermeide doppelte Klicks (da sie sich aufheben würden)
|
||
if (!clickedCells.has(key)) {
|
||
clickedCells.add(key);
|
||
toggleCellAndNeighbors(row, col, true); // silent=true
|
||
}
|
||
}
|
||
}
|
||
|
||
function toggleCellAndNeighbors(row, col, silent = false) {
|
||
// Hauptzelle togglen
|
||
grid[row][col] = !grid[row][col];
|
||
|
||
// 4 orthogonale Nachbarn (oben, unten, links, rechts)
|
||
const neighbors = [
|
||
[row - 1, col], // Oben
|
||
[row + 1, col], // Unten
|
||
[row, col - 1], // Links
|
||
[row, col + 1] // Rechts
|
||
];
|
||
|
||
neighbors.forEach(([r, c]) => {
|
||
// Nur wenn innerhalb des Grids
|
||
if (r >= 0 && r < gridSize && c >= 0 && c < gridSize) {
|
||
grid[r][c] = !grid[r][c];
|
||
}
|
||
});
|
||
|
||
if (!silent) {
|
||
moves++;
|
||
moveHistory.push([row, col]);
|
||
updateMovesDisplay();
|
||
updateUndoButton();
|
||
renderGrid();
|
||
checkWin();
|
||
}
|
||
}
|
||
|
||
function renderGrid() {
|
||
const gridElement = document.getElementById('grid');
|
||
gridElement.innerHTML = '';
|
||
gridElement.style.gridTemplateColumns = `repeat(${gridSize}, var(--cell-size))`;
|
||
|
||
for (let row = 0; row < gridSize; row++) {
|
||
for (let col = 0; col < gridSize; col++) {
|
||
const cell = document.createElement('div');
|
||
cell.className = 'cell';
|
||
cell.dataset.row = row;
|
||
cell.dataset.col = col;
|
||
|
||
if (grid[row][col]) {
|
||
cell.classList.add('on');
|
||
}
|
||
|
||
// Event Listeners
|
||
cell.addEventListener('click', () => handleCellClick(row, col));
|
||
cell.addEventListener('touchstart', (e) => {
|
||
e.preventDefault();
|
||
handleCellClick(row, col);
|
||
}, { passive: false });
|
||
|
||
gridElement.appendChild(cell);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ===== EVENT HANDLING =====
|
||
function handleCellClick(row, col) {
|
||
if (gameWon) return;
|
||
|
||
// Animation
|
||
const cellElement = document.querySelector(`.cell[data-row="${row}"][data-col="${col}"]`);
|
||
if (cellElement) {
|
||
cellElement.classList.add('animating');
|
||
setTimeout(() => cellElement.classList.remove('animating'), 300);
|
||
}
|
||
|
||
toggleCellAndNeighbors(row, col);
|
||
}
|
||
|
||
function undo() {
|
||
if (moveHistory.length === 0 || gameWon) return;
|
||
|
||
const [row, col] = moveHistory.pop();
|
||
|
||
// Toggle ohne Züge zu erhöhen (nur Grid-State zurücksetzen)
|
||
grid[row][col] = !grid[row][col];
|
||
|
||
const neighbors = [
|
||
[row - 1, col],
|
||
[row + 1, col],
|
||
[row, col - 1],
|
||
[row, col + 1]
|
||
];
|
||
|
||
neighbors.forEach(([r, c]) => {
|
||
if (r >= 0 && r < gridSize && c >= 0 && c < gridSize) {
|
||
grid[r][c] = !grid[r][c];
|
||
}
|
||
});
|
||
|
||
moves--;
|
||
updateMovesDisplay();
|
||
updateUndoButton();
|
||
renderGrid();
|
||
}
|
||
|
||
function changeGridSize(size) {
|
||
gridSize = size;
|
||
|
||
// Active-Button aktualisieren
|
||
document.querySelectorAll('.difficulty button').forEach(btn => {
|
||
btn.classList.toggle('active', parseInt(btn.dataset.size) === size);
|
||
});
|
||
|
||
// Zellengröße anpassen für große Grids
|
||
if (size >= 6) {
|
||
document.documentElement.style.setProperty('--cell-size', '50px');
|
||
} else if (size >= 5) {
|
||
document.documentElement.style.setProperty('--cell-size', '60px');
|
||
} else {
|
||
document.documentElement.style.setProperty('--cell-size', '70px');
|
||
}
|
||
|
||
neuesSpiel();
|
||
}
|
||
|
||
function neuesSpiel() {
|
||
moves = 0;
|
||
gameWon = false;
|
||
moveHistory = [];
|
||
schliesseModal('winModal');
|
||
updateMovesDisplay();
|
||
updateUndoButton();
|
||
initGrid();
|
||
renderGrid();
|
||
}
|
||
|
||
// ===== GEWINN-ERKENNUNG =====
|
||
function checkWin() {
|
||
const allOff = grid.every(row => row.every(cell => !cell));
|
||
|
||
if (allOff && !gameWon) {
|
||
gameWon = true;
|
||
|
||
// Bestscores aktualisieren
|
||
const isNewRecord = !bestScores[gridSize] || moves < bestScores[gridSize];
|
||
if (isNewRecord) {
|
||
bestScores[gridSize] = moves;
|
||
saveBestScores();
|
||
}
|
||
|
||
setTimeout(() => showWinModal(isNewRecord), 500);
|
||
}
|
||
}
|
||
|
||
function showWinModal(isNewRecord) {
|
||
document.getElementById('finalMoves').textContent = moves;
|
||
document.getElementById('gridSizeLabel').textContent = `${gridSize}×${gridSize}`;
|
||
|
||
const bestMoves = bestScores[gridSize];
|
||
document.getElementById('bestMoves').textContent = bestMoves || '--';
|
||
|
||
const newRecordElement = document.getElementById('newRecord');
|
||
newRecordElement.style.display = isNewRecord ? 'block' : 'none';
|
||
|
||
const modal = document.getElementById('winModal');
|
||
modal.classList.add('active');
|
||
}
|
||
|
||
// ===== UI-UPDATES =====
|
||
function updateMovesDisplay() {
|
||
document.getElementById('moves').textContent = moves;
|
||
}
|
||
|
||
function updateUndoButton() {
|
||
const undoBtn = document.getElementById('undoBtn');
|
||
undoBtn.disabled = moveHistory.length === 0 || gameWon;
|
||
}
|
||
|
||
// ===== MODAL-FUNKTIONEN =====
|
||
function zeigeAnleitung() {
|
||
document.getElementById('instructionModal').classList.add('active');
|
||
}
|
||
|
||
function schliesseModal(modalId) {
|
||
document.getElementById(modalId).classList.remove('active');
|
||
}
|
||
|
||
// Modal schließen bei Klick auf Overlay
|
||
document.querySelectorAll('.modal-overlay').forEach(overlay => {
|
||
overlay.addEventListener('click', (e) => {
|
||
if (e.target === overlay) {
|
||
overlay.classList.remove('active');
|
||
}
|
||
});
|
||
});
|
||
|
||
// ===== LOCALSTORAGE =====
|
||
function loadBestScores() {
|
||
const saved = localStorage.getItem('lightsOutBestScores');
|
||
bestScores = saved ? JSON.parse(saved) : {};
|
||
}
|
||
|
||
function saveBestScores() {
|
||
localStorage.setItem('lightsOutBestScores', JSON.stringify(bestScores));
|
||
}
|
||
|
||
// ===== THEME TOGGLE =====
|
||
function toggleTheme() {
|
||
document.body.classList.toggle('dark-mode');
|
||
const btn = document.querySelector('.theme-toggle');
|
||
btn.textContent = document.body.classList.contains('dark-mode') ? '☀️' : '🌙';
|
||
localStorage.setItem('theme', document.body.classList.contains('dark-mode') ? 'dark' : 'light');
|
||
}
|
||
|
||
function initTheme() {
|
||
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||
const savedTheme = localStorage.getItem('theme');
|
||
|
||
if (savedTheme === 'dark' || (!savedTheme && prefersDark)) {
|
||
document.body.classList.add('dark-mode');
|
||
document.querySelector('.theme-toggle').textContent = '☀️';
|
||
}
|
||
}
|
||
|
||
// ===== START =====
|
||
window.addEventListener('DOMContentLoaded', init);
|
||
</script>
|
||
</body>
|
||
</html>
|