Sudoku mit JavaScript erstellen
Von den Grundlagen zur funktionsfähigen Sudoku-Anwendung
💻 Warum JavaScript für Sudoku?
JavaScript ist die perfekte Wahl für Sudoku-Entwicklung, da es sowohl frontend- als auch backend-Fähigkeiten bietet, eine große Community hat und sofortige visuelle Ergebnisse im Browser ermöglicht. Mit modernem JavaScript können Sie komplexe Algorithmen implementieren und gleichzeitig eine ansprechende Benutzeroberfläche erstellen.
Einfacher Einstieg
Keine Installation erforderlich
Sofortige Ergebnisse
Direkt im Browser testen
Web-ready
Einfache Veröffentlichung
🏗️ Projekt-Setup
Grundlegende HTML-Struktur
Beginnen Sie mit einer einfachen HTML-Datei, die das Sudoku-Gitter und die notwendigen JavaScript-Dateien einbindet:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Mein Sudoku Spiel</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<h2>Sudoku Spiel</h2>
<div class="game-controls">
<button id="newGame">Neues Spiel</button>
<button id="checkSolution">Lösung prüfen</button>
<button id="showHint">Hinweis</button>
</div>
<div id="sudoku-grid" class="sudoku-grid"></div>
<div class="game-info">
<div id="timer">Zeit: 00:00</div>
<div id="difficulty">Schwierigkeit: Leicht</div>
</div>
</div>
<script src="sudoku.js"></script>
</body>
</html>CSS-Styling für das Sudoku-Gitter
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
font-family: 'Arial', sans-serif;
}
.sudoku-grid {
display: grid;
grid-template-columns: repeat(9, 1fr);
gap: 1px;
background-color: #333;
border: 3px solid #333;
margin: 20px 0;
width: 450px;
height: 450px;
}
.cell {
background-color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
font-weight: bold;
cursor: pointer;
transition: background-color 0.2s;
}
.cell:hover {
background-color: #e6f3ff;
}
.cell.selected {
background-color: #cce7ff;
}
.cell.error {
background-color: #ffe6e6;
}
.cell.given {
background-color: #f0f0f0;
color: #333;
cursor: not-allowed;
}
/* Dickere Grenzen für 3x3-Boxen */
.cell:nth-child(3n) {
border-right: 2px solid #333;
}
.cell:nth-child(n+19):nth-child(-n+27),
.cell:nth-child(n+46):nth-child(-n+54) {
border-bottom: 2px solid #333;
}🧠 JavaScript-Kern: Die Sudoku-Klasse
Grundstruktur der Sudoku-Klasse
Sudoku-Klassen-Architektur:
class SudokuGame {
constructor() {
this.grid = this.createEmptyGrid();
this.solution = null;
this.difficulty = 'medium';
this.timer = 0;
this.timerInterval = null;
this.selectedCell = null;
this.initializeGame();
}
createEmptyGrid() {
return Array(9).fill(null).map(() => Array(9).fill(0));
}
initializeGame() {
this.createGridHTML();
this.setupEventListeners();
this.generateNewPuzzle();
this.startTimer();
}
// Weitere Methoden folgen...
}Gitter-Validierung implementieren
isValidMove(grid, row, col, num) {
// Zeile prüfen
for (let x = 0; x < 9; x++) {
if (grid[row][x] === num) return false;
}
// Spalte prüfen
for (let x = 0; x < 9; x++) {
if (grid[x][col] === num) return false;
}
// 3x3 Box prüfen
const boxRow = Math.floor(row / 3) * 3;
const boxCol = Math.floor(col / 3) * 3;
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (grid[boxRow + i][boxCol + j] === num) return false;
}
}
return true;
}
validateGrid() {
for (let row = 0; row < 9; row++) {
for (let col = 0; col < 9; col++) {
if (this.grid[row][col] !== 0) {
const num = this.grid[row][col];
this.grid[row][col] = 0; // Temporär entfernen für Test
if (!this.isValidMove(this.grid, row, col, num)) {
this.grid[row][col] = num; // Zurücksetzen
return false;
}
this.grid[row][col] = num; // Zurücksetzen
}
}
}
return true;
}🎲 Sudoku-Generierung: Der Algorithmus
Backtracking-Löser
Der Herzstück jeder Sudoku-Anwendung ist der Lösungsalgorithmus. Backtracking ist die bewährte Methode:
solveSudoku(grid) {
for (let row = 0; row < 9; row++) {
for (let col = 0; col < 9; col++) {
if (grid[row][col] === 0) {
for (let num = 1; num <= 9; num++) {
if (this.isValidMove(grid, row, col, num)) {
grid[row][col] = num;
if (this.solveSudoku(grid)) {
return true;
}
grid[row][col] = 0; // Backtrack
}
}
return false;
}
}
}
return true;
}
generateCompleteSolution() {
const grid = this.createEmptyGrid();
// Zufällige Zahlen in erste Zeile
const numbers = [1,2,3,4,5,6,7,8,9];
for (let i = numbers.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[numbers[i], numbers[j]] = [numbers[j], numbers[i]];
}
for (let col = 0; col < 9; col++) {
grid[0][col] = numbers[col];
}
this.solveSudoku(grid);
return grid;
}Puzzle-Generierung durch Zellenentfernung
Schwierigkeitsgrad durch strategische Entfernung:
generatePuzzle(difficulty = 'medium') {
const solution = this.generateCompleteSolution();
const puzzle = solution.map(row => [...row]);
const cellsToRemove = this.getCellsToRemove(difficulty);
for (let i = 0; i < cellsToRemove; i++) {
let row, col;
do {
row = Math.floor(Math.random() * 9);
col = Math.floor(Math.random() * 9);
} while (puzzle[row][col] === 0);
const backup = puzzle[row][col];
puzzle[row][col] = 0;
// Prüfen ob Puzzle noch eindeutig lösbar
if (!this.hasUniqueSolution(puzzle)) {
puzzle[row][col] = backup; // Rückgängig machen
}
}
this.grid = puzzle;
this.solution = solution;
}
getCellsToRemove(difficulty) {
const levels = {
'easy': 35,
'medium': 45,
'hard': 55,
'expert': 65
};
return levels[difficulty] || levels['medium'];
}🎮 Benutzerinteraktion und Event-Handling
Event-Listeners einrichten
setupEventListeners() {
// Zellen-Klicks handhaben
document.addEventListener('click', (e) => {
if (e.target.classList.contains('cell')) {
this.selectCell(e.target);
}
});
// Tastatur-Eingaben
document.addEventListener('keydown', (e) => {
if (this.selectedCell) {
const num = parseInt(e.key);
if (num >= 1 && num <= 9) {
this.enterNumber(num);
} else if (e.key === 'Delete' || e.key === 'Backspace') {
this.clearCell();
}
}
});
// Spielsteuerungs-Buttons
document.getElementById('newGame').addEventListener('click', () => {
this.startNewGame();
});
document.getElementById('checkSolution').addEventListener('click', () => {
this.checkCurrentSolution();
});
document.getElementById('showHint').addEventListener('click', () => {
this.showHint();
});
}
selectCell(cellElement) {
// Vorherige Auswahl entfernen
document.querySelectorAll('.cell.selected')
.forEach(cell => cell.classList.remove('selected'));
// Neue Zelle auswählen
cellElement.classList.add('selected');
this.selectedCell = {
element: cellElement,
row: parseInt(cellElement.dataset.row),
col: parseInt(cellElement.dataset.col)
};
}Zahlen-Eingabe und Validierung
enterNumber(num) {
if (!this.selectedCell) return;
const { row, col, element } = this.selectedCell;
// Prüfen ob Zelle editierbar
if (element.classList.contains('given')) return;
// Zahl setzen
this.grid[row][col] = num;
element.textContent = num;
// Validierung und visuelles Feedback
if (this.isValidMove(this.removeCurrentNumber(this.grid), row, col, num)) {
element.classList.remove('error');
this.checkWinCondition();
} else {
element.classList.add('error');
}
this.updateHighlights();
}
removeCurrentNumber(grid) {
const { row, col } = this.selectedCell;
const newGrid = grid.map(r => [...r]);
newGrid[row][col] = 0;
return newGrid;
}
updateHighlights() {
if (!this.selectedCell) return;
const selectedValue = this.grid[this.selectedCell.row][this.selectedCell.col];
document.querySelectorAll('.cell').forEach((cell, index) => {
const row = Math.floor(index / 9);
const col = index % 9;
cell.classList.remove('highlighted', 'same-number');
// Highlight-Zeile, Spalte und Box
if (row === this.selectedCell.row || col === this.selectedCell.col ||
(Math.floor(row / 3) === Math.floor(this.selectedCell.row / 3) &&
Math.floor(col / 3) === Math.floor(this.selectedCell.col / 3))) {
cell.classList.add('highlighted');
}
// Gleiche Zahlen markieren
if (selectedValue && this.grid[row][col] === selectedValue) {
cell.classList.add('same-number');
}
});
}⚡ Erweiterte Features
Timer und Statistiken
Game-State-Management:
startTimer() {
this.startTime = Date.now();
this.timerInterval = setInterval(() => {
const elapsed = Date.now() - this.startTime;
const minutes = Math.floor(elapsed / 60000);
const seconds = Math.floor((elapsed % 60000) / 1000);
document.getElementById('timer').textContent =
`Zeit: ${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
}, 1000);
}
saveGameState() {
const gameState = {
grid: this.grid,
timer: Date.now() - this.startTime,
difficulty: this.difficulty,
timestamp: Date.now()
};
localStorage.setItem('sudokuGameState', JSON.stringify(gameState));
}
loadGameState() {
const saved = localStorage.getItem('sudokuGameState');
if (saved) {
const gameState = JSON.parse(saved);
this.grid = gameState.grid;
this.difficulty = gameState.difficulty;
this.startTime = Date.now() - gameState.timer;
this.updateDisplay();
return true;
}
return false;
}Hint-System
showHint() {
// Einfachsten leeren Zelle finden
let bestCell = null;
let minOptions = 10;
for (let row = 0; row < 9; row++) {
for (let col = 0; col < 9; col++) {
if (this.grid[row][col] === 0) {
const options = this.getPossibleNumbers(row, col);
if (options.length < minOptions && options.length > 0) {
minOptions = options.length;
bestCell = { row, col, options };
}
}
}
}
if (bestCell) {
if (bestCell.options.length === 1) {
// Direkte Lösung zeigen
this.highlightCell(bestCell.row, bestCell.col);
this.showMessage(`Zelle (${bestCell.row + 1}, ${bestCell.col + 1}) kann nur ${bestCell.options[0]} sein!`);
} else {
// Mögliche Zahlen anzeigen
this.highlightCell(bestCell.row, bestCell.col);
this.showMessage(`Zelle (${bestCell.row + 1}, ${bestCell.col + 1}) kann ${bestCell.options.join(', ')} sein`);
}
} else {
this.showMessage('Keine Hinweise verfügbar - prüfen Sie Ihre bisherigen Eingaben!');
}
}
getPossibleNumbers(row, col) {
const possible = [];
for (let num = 1; num <= 9; num++) {
if (this.isValidMove(this.grid, row, col, num)) {
possible.push(num);
}
}
return possible;
}🏆 Optimierung und Best Practices
Performance-Optimierungen
- Memoization: Cache für wiederholte Berechnungen
- Efficient DOM Updates: Minimieren Sie DOM-Manipulationen
- Web Workers: Schwere Berechnungen in Background-Threads
- Local Storage: Spiel-Zustand persistent speichern
Code-Organisation
Modulare Struktur:
- • sudoku-core.js: Kernlogik und Algorithmen
- • sudoku-ui.js: Benutzeroberflächen-Management
- • sudoku-generator.js: Puzzle-Generierung
- • sudoku-solver.js: Lösungsalgorithmen
- • sudoku-utils.js: Hilfsfunktionen und Konstanten
Testing-Strategien
// Beispiel Unit-Test mit Jest
describe('Sudoku Validation', () => {
let sudoku;
beforeEach(() => {
sudoku = new SudokuGame();
});
test('should validate correct row', () => {
const grid = sudoku.createEmptyGrid();
grid[0] = [1,2,3,4,5,6,7,8,9];
expect(sudoku.isValidMove(grid, 1, 0, 1)).toBe(false);
expect(sudoku.isValidMove(grid, 1, 0, 2)).toBe(false);
});
test('should generate valid complete solution', () => {
const solution = sudoku.generateCompleteSolution();
expect(sudoku.isValidSolution(solution)).toBe(true);
});
test('should solve puzzle correctly', () => {
const puzzle = /* test puzzle */;
const solved = sudoku.solveSudoku([...puzzle]);
expect(solved).toBe(true);
expect(sudoku.isValidSolution(puzzle)).toBe(true);
});
});🚀 Deployment und Veröffentlichung
Web-Deployment-Optionen
Kostenlose Optionen
- • GitHub Pages: Direkt von Repository
- • Netlify: Drag-and-Drop Deployment
- • Vercel: Automatische Git-Integration
- • Firebase Hosting: Google's Platform
Premium-Optionen
- • Custom Domain: Ihre eigene URL
- • CDN-Integration: Globale Performance
- • Analytics: Nutzer-Tracking
- • Progressive Web App: App-ähnliche Erfahrung
Progressive Web App (PWA) Features
- Service Worker: Offline-Funktionalität
- Manifest.json: App-Installation ermöglichen
- Responsive Design: Alle Bildschirmgrößen
- Push Notifications: Tägliche Sudoku-Erinnerungen
💻 Bereit für JavaScript-Sudoku?
JavaScript bietet alle Tools, die Sie für ein professionelles Sudoku-Spiel benötigen. Von einfachen Implementierungen bis zu fortgeschrittenen Features - Ihrer Kreativität sind keine Grenzen gesetzt!
🎯 Entdecke das Komplette Sudoku-Universum
📊 Vollständige Schwierigkeitsprogression
Erkunde unsere wissenschaftlich entwickelte Progression, um deine perfekte Herausforderung zu finden:
🟢 Sudoku Leicht Classic Sudoku
Perfekt zum Aufbau grundlegender logischer Denkfähigkeiten.
🟡 Sudoku Mittel Classic Sudoku ✓
Der nächste Schritt mit ausgewogener Herausforderung und Lösbarkeit.
🔴 Sudoku Schwer Classic Sudoku
Erfordert fortgeschrittene Techniken und strategisches Denken.
🟣 Sudoku Experte Classic Sudoku
Fordert selbst erfahrene Löser mit komplexen Mustern heraus.
🔵 Sudoku Meister Classic Sudoku
Elite-Rätsel, die die Beherrschung aller Techniken erfordern.
⚫ Sudoku Teuflisch Classic Sudoku
Die ultimative Herausforderung für Großmeister des Sudoku.
🎮 Alternative Sudoku-Varianten
Erweitere deine Puzzle-Lösungshorizonte mit diesen aufregenden Variationen, die einzigartige Herausforderungen bieten:
⚔️ Killer Sudoku
Kombiniert Sudoku-Logik mit mathematischen Zellen, die spezifische Summen erfordern.
🔷 Riesen Sudoku 16x16
Massive 256-Zellen-Rätsel mit hexadezimalen Zahlen für maximale Ausdauer.
👶 Kinder Sudoku
Perfekte Einführung für junge Köpfe mit vereinfachten 4x4 und 6x6 Gittern.
📚 Lern-Ressourcen
Umfassende Leitfäden und Strategien zur Verbesserung der Lösungsfähigkeiten.