Mystery Game #13
← Back to Games List
// Mastermind Game Implementation
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// Game settings
const rows = 10; // Number of guesses
const cols = 4; // Code length
const colors = ['red', 'blue', 'green', 'yellow', 'purple', 'orange'];
const cellSize = 40;
const pegSize = 10;
const padding = 10;
canvas.width = (cols * cellSize + padding * 4 + pegSize * 2) * 2;
canvas.height = rows * (cellSize + padding) + padding * 2;
// Game state
let secretCode = [];
let guesses = Array(rows).fill().map(() => Array(cols).fill(-1));
let feedback = Array(rows).fill().map(() => Array(cols).fill(-1));
let currentRow = 0;
let selectedColor = 0;
let gameOver = false;
let won = false;
// Generate secret code
function generateCode() {
secretCode = Array(cols).fill().map(() => Math.floor(Math.random() * colors.length));
}
// Check guess against secret code
function checkGuess(row) {
const guess = guesses[row];
const code = [...secretCode];
const result = Array(cols).fill(-1);
// First check for exact matches (black pegs)
for (let i = 0; i < cols; i++) {
if (guess[i] === code[i]) {
result[i] = 1; // Black peg
code[i] = -1;
guess[i] = -2;
}
}
// Then check for color matches (white pegs)
for (let i = 0; i < cols; i++) {
if (guess[i] === -2) continue;
const colorIndex = code.indexOf(guess[i]);
if (colorIndex !== -1) {
result[i] = 0; // White peg
code[colorIndex] = -1;
}
}
feedback[row] = result;
// Check for win
if (result.every(peg => peg === 1)) {
won = true;
gameOver = true;
}
// Check for game over
if (currentRow === rows - 1 && !won) {
gameOver = true;
}
}
// Handle mouse click
canvas.addEventListener('click', (e) => {
if (gameOver) {
if (e.offsetY > canvas.height - 50) {
// Reset game
initGame();
return;
}
}
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// Color palette click
if (x > canvas.width / 2) {
const colorX = Math.floor((x - canvas.width / 2) / cellSize);
const colorY = Math.floor(y / cellSize);
const index = colorY * 2 + colorX;
if (index >= 0 && index < colors.length) {
selectedColor = index;
}
return;
}
// Board click
if (!gameOver) {
const col = Math.floor(x / cellSize);
const row = Math.floor(y / (cellSize + padding));
if (row === currentRow && col < cols) {
guesses[row][col] = selectedColor;
}
// Check button click
if (col === cols + 1 && row === currentRow) {
if (!guesses[currentRow].includes(-1)) {
checkGuess(currentRow);
if (!gameOver) {
currentRow++;
}
}
}
}
});
function draw() {
// Clear canvas
ctx.fillStyle = '#333';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw board
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
const x = col * cellSize + padding;
const y = row * (cellSize + padding) + padding;
// Draw cell
ctx.fillStyle = guesses[row][col] === -1 ? '#666' : colors[guesses[row][col]];
ctx.fillRect(x, y, cellSize - padding, cellSize - padding);
}
// Draw check button
if (row === currentRow && !gameOver) {
const x = cols * cellSize + padding * 2;
const y = row * (cellSize + padding) + padding;
ctx.fillStyle = '#0f0';
ctx.fillRect(x, y, cellSize - padding, cellSize - padding);
}
// Draw feedback pegs
if (feedback[row][0] !== -1) {
const startX = (cols + 2) * cellSize;
const startY = row * (cellSize + padding) + padding;
feedback[row].forEach((peg, i) => {
if (peg !== -1) {
ctx.fillStyle = peg === 1 ? 'black' : 'white';
ctx.beginPath();
ctx.arc(
startX + (i % 2) * pegSize * 2,
startY + Math.floor(i / 2) * pegSize * 2,
pegSize/2,
0,
Math.PI * 2
);
ctx.fill();
}
});
}
}
// Draw color palette
for (let i = 0; i < colors.length; i++) {
const x = canvas.width/2 + (i % 2) * cellSize + padding;
const y = Math.floor(i / 2) * cellSize + padding;
ctx.fillStyle = colors[i];
ctx.fillRect(x, y, cellSize - padding, cellSize - padding);
if (i === selectedColor) {
ctx.strokeStyle = 'white';
ctx.lineWidth = 3;
ctx.strokeRect(x, y, cellSize - padding, cellSize - padding);
}
}
// Draw game over
if (gameOver) {
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.font = '40px Arial';
ctx.textAlign = 'center';
ctx.fillText(won ? 'You Win!' : 'Game Over!', canvas.width/2, canvas.height/2 - 50);
// Show secret code
ctx.font = '20px Arial';
ctx.fillText('Secret Code:', canvas.width/2, canvas.height/2);
secretCode.forEach((color, i) => {
const x = canvas.width/2 - (cols * cellSize)/2 + i * cellSize + padding;
const y = canvas.height/2 + 20;
ctx.fillStyle = colors[color];
ctx.fillRect(x, y, cellSize - padding, cellSize - padding);
});
// Draw play again button
ctx.fillStyle = '#0f0';
ctx.fillRect(canvas.width/2 - 100, canvas.height - 50, 200, 40);
ctx.fillStyle = 'black';
ctx.font = '20px Arial';
ctx.fillText('Play Again', canvas.width/2, canvas.height - 25);
}
}
function initGame() {
secretCode = [];
guesses = Array(rows).fill().map(() => Array(cols).fill(-1));
feedback = Array(rows).fill().map(() => Array(cols).fill(-1));
currentRow = 0;
selectedColor = 0;
gameOver = false;
won = false;
generateCode();
}
// Game loop
function gameLoop() {
draw();
requestAnimationFrame(gameLoop);
}
// Start game
initGame();
gameLoop();
# Mastermind Game Implementation
import pygame
import random
from dataclasses import dataclass
from typing import List, Tuple
import numpy as np
@dataclass
class Colors:
RED: Tuple[int, int, int] = (255, 0, 0)
BLUE: Tuple[int, int, int] = (0, 0, 255)
GREEN: Tuple[int, int, int] = (0, 255, 0)
YELLOW: Tuple[int, int, int] = (255, 255, 0)
PURPLE: Tuple[int, int, int] = (160, 0, 160)
ORANGE: Tuple[int, int, int] = (255, 160, 0)
@property
def palette(self) -> List[Tuple[int, int, int]]:
return [self.RED, self.BLUE, self.GREEN, self.YELLOW,
self.PURPLE, self.ORANGE]
class MastermindGame:
def __init__(self):
pygame.init()
# Game settings
self.rows = 10 # Number of guesses
self.cols = 4 # Code length
self.cell_size = 40
self.peg_size = 10
self.padding = 10
# Calculate window size
self.width = (self.cols * self.cell_size + self.padding * 4 +
self.peg_size * 2) * 2
self.height = self.rows * (self.cell_size + self.padding) + self.padding * 2
# Initialize display
self.screen = pygame.display.set_mode((self.width, self.height))
pygame.display.set_caption('Mastermind')
self.clock = pygame.time.Clock()
# Colors
self.colors = Colors()
# Game state
self.init_game()
def init_game(self):
"""Initialize or reset game state"""
self.secret_code = self.generate_code()
self.guesses = np.full((self.rows, self.cols), -1, dtype=int)
self.feedback = np.full((self.rows, self.cols), -1, dtype=int)
self.current_row = 0
self.selected_color = 0
self.game_over = False
self.won = False
def generate_code(self) -> List[int]:
"""Generate random secret code"""
return [random.randint(0, len(self.colors.palette) - 1)
for _ in range(self.cols)]
def check_guess(self, row: int):
"""Check guess against secret code"""
guess = self.guesses[row].copy()
code = self.secret_code.copy()
result = [-1] * self.cols
# Check for exact matches (black pegs)
for i in range(self.cols):
if guess[i] == code[i]:
result[i] = 1 # Black peg
code[i] = -1
guess[i] = -2
# Check for color matches (white pegs)
for i in range(self.cols):
if guess[i] == -2:
continue
try:
color_index = code.index(guess[i])
result[i] = 0 # White peg
code[color_index] = -1
except ValueError:
pass
self.feedback[row] = result
# Check for win
if all(peg == 1 for peg in result):
self.won = True
self.game_over = True
# Check for game over
if self.current_row == self.rows - 1 and not self.won:
self.game_over = True
def handle_input(self) -> bool:
"""Handle mouse input"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = event.pos
if self.game_over:
# Check for play again button
if mouse_y > self.height - 50:
self.init_game()
return True
# Color palette click
if mouse_x > self.width / 2:
color_x = (mouse_x - self.width / 2) // self.cell_size
color_y = mouse_y // self.cell_size
index = color_y * 2 + color_x
if 0 <= index < len(self.colors.palette):
self.selected_color = index
return True
# Board click
col = mouse_x // self.cell_size
row = mouse_y // (self.cell_size + self.padding)
if row == self.current_row and col < self.cols:
self.guesses[row][col] = self.selected_color
# Check button click
if (col == self.cols + 1 and row == self.current_row and
-1 not in self.guesses[self.current_row]):
self.check_guess(self.current_row)
if not self.game_over:
self.current_row += 1
return True
def draw(self):
"""Draw the game state"""
# Clear screen
self.screen.fill((51, 51, 51)) # Dark gray background
# Draw board
for row in range(self.rows):
for col in range(self.cols):
x = col * self.cell_size + self.padding
y = row * (self.cell_size + self.padding) + self.padding
# Draw cell
color = ((102, 102, 102) if self.guesses[row][col] == -1
else self.colors.palette[self.guesses[row][col]])
pygame.draw.rect(self.screen, color,
(x, y,
self.cell_size - self.padding,
self.cell_size - self.padding))
# Draw check button
if row == self.current_row and not self.game_over:
x = self.cols * self.cell_size + self.padding * 2
y = row * (self.cell_size + self.padding) + self.padding
pygame.draw.rect(self.screen, (0, 255, 0),
(x, y,
self.cell_size - self.padding,
self.cell_size - self.padding))
# Draw feedback pegs
if self.feedback[row][0] != -1:
start_x = (self.cols + 2) * self.cell_size
start_y = row * (self.cell_size + self.padding) + self.padding
for i, peg in enumerate(self.feedback[row]):
if peg != -1:
color = (0, 0, 0) if peg == 1 else (255, 255, 255)
pygame.draw.circle(self.screen, color,
(start_x + (i % 2) * self.peg_size * 2,
start_y + (i // 2) * self.peg_size * 2),
self.peg_size // 2)
# Draw color palette
for i, color in enumerate(self.colors.palette):
x = self.width/2 + (i % 2) * self.cell_size + self.padding
y = (i // 2) * self.cell_size + self.padding
pygame.draw.rect(self.screen, color,
(x, y,
self.cell_size - self.padding,
self.cell_size - self.padding))
if i == self.selected_color:
pygame.draw.rect(self.screen, (255, 255, 255),
(x, y,
self.cell_size - self.padding,
self.cell_size - self.padding), 3)
# Draw game over
if self.game_over:
overlay = pygame.Surface((self.width, self.height))
overlay.fill((0, 0, 0))
overlay.set_alpha(178) # 70% opacity
self.screen.blit(overlay, (0, 0))
# Draw game over message
font = pygame.font.Font(None, 64)
text = font.render('You Win!' if self.won else 'Game Over!',
True, (255, 255, 255))
text_rect = text.get_rect(
center=(self.width/2, self.height/2 - 50))
self.screen.blit(text, text_rect)
# Show secret code
font = pygame.font.Font(None, 36)
text = font.render('Secret Code:', True, (255, 255, 255))
text_rect = text.get_rect(center=(self.width/2, self.height/2))
self.screen.blit(text, text_rect)
for i, color_index in enumerate(self.secret_code):
x = (self.width/2 - (self.cols * self.cell_size)/2 +
i * self.cell_size + self.padding)
y = self.height/2 + 20
pygame.draw.rect(self.screen,
self.colors.palette[color_index],
(x, y,
self.cell_size - self.padding,
self.cell_size - self.padding))
# Draw play again button
pygame.draw.rect(self.screen, (0, 255, 0),
(self.width/2 - 100, self.height - 50, 200, 40))
font = pygame.font.Font(None, 36)
text = font.render('Play Again', True, (0, 0, 0))
text_rect = text.get_rect(
center=(self.width/2, self.height - 30))
self.screen.blit(text, text_rect)
pygame.display.flip()
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 = MastermindGame()
game.run()
Play Game