Mystery Game #14

← Back to Games List
// Sudoku Game Implementation const canvas = document.getElementById('gameCanvas'); const ctx = canvas.getContext('2d'); // Game settings const gridSize = 9; const cellSize = 50; const padding = 2; const thickLine = 4; canvas.width = gridSize * cellSize + padding * 2; canvas.height = canvas.width; // Game state let board = Array(gridSize).fill().map(() => Array(gridSize).fill(0)); let initialBoard = Array(gridSize).fill().map(() => Array(gridSize).fill(0)); let selectedCell = null; let gameOver = false; // Generate a valid Sudoku board function generateBoard() { // Clear board board = Array(gridSize).fill().map(() => Array(gridSize).fill(0)); // Fill diagonal 3x3 boxes first (they're independent) for (let box = 0; box < 3; box++) { const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9]; for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { const num = nums.splice(Math.floor(Math.random() * nums.length), 1)[0]; board[box * 3 + i][box * 3 + j] = num; } } } // Fill rest of the board solveBoard(); // Remove numbers to create puzzle const cellsToRemove = 45; // Adjust difficulty here for (let i = 0; i < cellsToRemove; i++) { let row, col; do { row = Math.floor(Math.random() * gridSize); col = Math.floor(Math.random() * gridSize); } while (board[row][col] === 0); board[row][col] = 0; } // Save initial board state initialBoard = board.map(row => [...row]); } // Solve the board using backtracking function solveBoard() { const emptyCell = findEmptyCell(); if (!emptyCell) return true; const [row, col] = emptyCell; const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9]; shuffle(nums); for (const num of nums) { if (isValidMove(row, col, num)) { board[row][col] = num; if (solveBoard()) return true; board[row][col] = 0; } } return false; } // Find an empty cell function findEmptyCell() { for (let row = 0; row < gridSize; row++) { for (let col = 0; col < gridSize; col++) { if (board[row][col] === 0) { return [row, col]; } } } return null; } // Check if a move is valid function isValidMove(row, col, num) { // Check row for (let x = 0; x < gridSize; x++) { if (board[row][x] === num) return false; } // Check column for (let y = 0; y < gridSize; y++) { if (board[y][col] === num) return false; } // Check 3x3 box const boxRow = Math.floor(row / 3) * 3; const boxCol = Math.floor(col / 3) * 3; for (let y = 0; y < 3; y++) { for (let x = 0; x < 3; x++) { if (board[boxRow + y][boxCol + x] === num) return false; } } return true; } // Shuffle array function shuffle(array) { for (let i = array.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } } // Handle mouse click canvas.addEventListener('click', (e) => { if (gameOver) { initGame(); return; } const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; const col = Math.floor(x / cellSize); const row = Math.floor(y / cellSize); if (row >= 0 && row < gridSize && col >= 0 && col < gridSize) { if (initialBoard[row][col] === 0) { selectedCell = [row, col]; } } }); // Handle keyboard input document.addEventListener('keydown', (e) => { if (!selectedCell || gameOver) return; const [row, col] = selectedCell; if (initialBoard[row][col] !== 0) return; if (e.key >= '1' && e.key <= '9') { const num = parseInt(e.key); if (isValidMove(row, col, num)) { board[row][col] = num; // Check if board is complete if (!findEmptyCell()) { gameOver = true; } } } else if (e.key === 'Backspace' || e.key === 'Delete') { board[row][col] = 0; } }); function draw() { // Clear canvas ctx.fillStyle = 'white'; ctx.fillRect(0, 0, canvas.width, canvas.height); // Draw grid ctx.strokeStyle = 'black'; // Draw thin lines ctx.lineWidth = 1; for (let i = 0; i <= gridSize; i++) { ctx.beginPath(); ctx.moveTo(i * cellSize, 0); ctx.lineTo(i * cellSize, canvas.height); ctx.stroke(); ctx.beginPath(); ctx.moveTo(0, i * cellSize); ctx.lineTo(canvas.width, i * cellSize); ctx.stroke(); } // Draw thick lines ctx.lineWidth = thickLine; for (let i = 0; i <= gridSize; i += 3) { ctx.beginPath(); ctx.moveTo(i * cellSize, 0); ctx.lineTo(i * cellSize, canvas.height); ctx.stroke(); ctx.beginPath(); ctx.moveTo(0, i * cellSize); ctx.lineTo(canvas.width, i * cellSize); ctx.stroke(); } // Draw numbers ctx.font = '24px Arial'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; for (let row = 0; row < gridSize; row++) { for (let col = 0; col < gridSize; col++) { if (board[row][col] !== 0) { // Different colors for initial and player numbers ctx.fillStyle = initialBoard[row][col] !== 0 ? 'black' : 'blue'; ctx.fillText( board[row][col], col * cellSize + cellSize/2, row * cellSize + cellSize/2 ); } } } // Draw selected cell if (selectedCell) { const [row, col] = selectedCell; ctx.strokeStyle = 'red'; ctx.lineWidth = 2; ctx.strokeRect( col * cellSize + 1, row * cellSize + 1, cellSize - 2, cellSize - 2 ); } // Draw game over if (gameOver) { ctx.fillStyle = 'rgba(0, 255, 0, 0.3)'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = 'black'; ctx.font = '40px Arial'; ctx.fillText('Solved!', canvas.width/2, canvas.height/2); ctx.font = '20px Arial'; ctx.fillText('Click to Play Again', canvas.width/2, canvas.height/2 + 40); } } function initGame() { generateBoard(); selectedCell = null; gameOver = false; } // Game loop function gameLoop() { draw(); requestAnimationFrame(gameLoop); } // Start game initGame(); gameLoop();
# Sudoku Game Implementation import pygame import random from dataclasses import dataclass from typing import List, Tuple, Optional import numpy as np @dataclass class Cell: row: int col: int class SudokuGame: def __init__(self): pygame.init() # Game settings self.grid_size = 9 self.cell_size = 50 self.padding = 2 self.thick_line = 4 self.width = self.grid_size * self.cell_size + self.padding * 2 self.height = self.width # Initialize display self.screen = pygame.display.set_mode((self.width, self.height)) pygame.display.set_caption('Sudoku') self.clock = pygame.time.Clock() # Game state self.board = np.zeros((self.grid_size, self.grid_size), dtype=int) self.initial_board = np.zeros((self.grid_size, self.grid_size), dtype=int) self.selected_cell: Optional[Cell] = None self.game_over = False self.init_game() def generate_board(self): """Generate a valid Sudoku board""" # Clear board self.board.fill(0) # Fill diagonal 3x3 boxes first (they're independent) for box in range(3): nums = list(range(1, 10)) random.shuffle(nums) for i in range(3): for j in range(3): self.board[box * 3 + i][box * 3 + j] = nums.pop() # Fill rest of the board self.solve_board() # Remove numbers to create puzzle cells_to_remove = 45 # Adjust difficulty here for _ in range(cells_to_remove): while True: row = random.randrange(self.grid_size) col = random.randrange(self.grid_size) if self.board[row][col] != 0: self.board[row][col] = 0 break # Save initial board state self.initial_board = self.board.copy() def solve_board(self) -> bool: """Solve the board using backtracking""" empty_cell = self.find_empty_cell() if not empty_cell: return True row, col = empty_cell nums = list(range(1, 10)) random.shuffle(nums) for num in nums: if self.is_valid_move(row, col, num): self.board[row][col] = num if self.solve_board(): return True self.board[row][col] = 0 return False def find_empty_cell(self) -> Optional[Tuple[int, int]]: """Find an empty cell""" for row in range(self.grid_size): for col in range(self.grid_size): if self.board[row][col] == 0: return (row, col) return None def is_valid_move(self, row: int, col: int, num: int) -> bool: """Check if a move is valid""" # Check row if num in self.board[row]: return False # Check column if num in self.board[:, col]: return False # Check 3x3 box box_row = (row // 3) * 3 box_col = (col // 3) * 3 box = self.board[box_row:box_row+3, box_col:box_col+3] if num in box: return False return True def handle_input(self) -> bool: """Handle mouse and keyboard input""" for event in pygame.event.get(): if event.type == pygame.QUIT: return False if event.type == pygame.MOUSEBUTTONDOWN: if self.game_over: self.init_game() else: mouse_x, mouse_y = event.pos col = mouse_x // self.cell_size row = mouse_y // self.cell_size if (0 <= row < self.grid_size and 0 <= col < self.grid_size and self.initial_board[row][col] == 0): self.selected_cell = Cell(row, col) if event.type == pygame.KEYDOWN: if not self.selected_cell or self.game_over: continue row, col = self.selected_cell.row, self.selected_cell.col if self.initial_board[row][col] != 0: continue if event.unicode.isdigit() and event.unicode != '0': num = int(event.unicode) if self.is_valid_move(row, col, num): self.board[row][col] = num if not self.find_empty_cell(): self.game_over = True elif event.key in (pygame.K_BACKSPACE, pygame.K_DELETE): self.board[row][col] = 0 return True def draw(self): """Draw the game state""" # Clear screen self.screen.fill((255, 255, 255)) # White background # Draw grid # Thin lines for i in range(self.grid_size + 1): pygame.draw.line(self.screen, (0, 0, 0), (i * self.cell_size, 0), (i * self.cell_size, self.height)) pygame.draw.line(self.screen, (0, 0, 0), (0, i * self.cell_size), (self.width, i * self.cell_size)) # Thick lines for i in range(0, self.grid_size + 1, 3): pygame.draw.line(self.screen, (0, 0, 0), (i * self.cell_size, 0), (i * self.cell_size, self.height), self.thick_line) pygame.draw.line(self.screen, (0, 0, 0), (0, i * self.cell_size), (self.width, i * self.cell_size), self.thick_line) # Draw numbers font = pygame.font.Font(None, 36) for row in range(self.grid_size): for col in range(self.grid_size): if self.board[row][col] != 0: color = (0, 0, 0) if self.initial_board[row][col] != 0 else (0, 0, 255) text = font.render(str(self.board[row][col]), True, color) text_rect = text.get_rect( center=(col * self.cell_size + self.cell_size//2, row * self.cell_size + self.cell_size//2)) self.screen.blit(text, text_rect) # Draw selected cell if self.selected_cell: pygame.draw.rect(self.screen, (255, 0, 0), (self.selected_cell.col * self.cell_size + 1, self.selected_cell.row * self.cell_size + 1, self.cell_size - 2, self.cell_size - 2), 2) # Draw game over if self.game_over: overlay = pygame.Surface((self.width, self.height)) overlay.fill((0, 255, 0)) overlay.set_alpha(76) # 30% opacity self.screen.blit(overlay, (0, 0)) font = pygame.font.Font(None, 64) text = font.render('Solved!', True, (0, 0, 0)) text_rect = text.get_rect(center=(self.width//2, self.height//2)) self.screen.blit(text, text_rect) font = pygame.font.Font(None, 36) text = font.render('Click to Play Again', True, (0, 0, 0)) text_rect = text.get_rect( center=(self.width//2, self.height//2 + 40)) self.screen.blit(text, text_rect) pygame.display.flip() def init_game(self): """Initialize or reset game state""" self.generate_board() self.selected_cell = None self.game_over = False def run(self): """Main game loop""" running = True while running: running = self.handle_input() self.draw() self.clock.tick(60) pygame.quit() if __name__ == '__main__': game = SudokuGame() game.run()
Play Game