Mystery Game #21
← Back to Games List
// Grid Movement Puzzle
const levels = [
[
'#######',
'#.....#',
'#.o.*.#',
'#.p...#',
'#.o.*.#',
'#.....#',
'#######'
],
[
'########',
'#......#',
'#.p.o..#',
'#..o.*.#',
'#..*...#',
'#......#',
'########'
]
];
const entity = {
x: 0,
y: 0
};
const objectives = [];
const items = [];
let currentLevel = 0;
let moves = 0;
let isActive = true;
function initializeLevel() {
objectives.length = 0;
items.length = 0;
const level = levels[currentLevel];
for (let y = 0; y < level.length; y++) {
for (let x = 0; x < level[y].length; x++) {
switch(level[y][x]) {
case 'p':
entity.x = x;
entity.y = y;
break;
case 'o':
items.push({x, y});
break;
case '*':
objectives.push({x, y});
break;
}
}
}
}
function isWall(x, y) {
return levels[currentLevel][y][x] === '#';
}
function getItemAt(x, y) {
return items.find(i => i.x === x && i.y === y);
}
function isObjectiveAt(x, y) {
return objectives.some(o => o.x === x && o.y === y);
}
function moveEntity(dx, dy) {
if (!isActive) return;
const newX = entity.x + dx;
const newY = entity.y + dy;
if (isWall(newX, newY)) return;
const item = getItemAt(newX, newY);
if (item) {
const pushX = newX + dx;
const pushY = newY + dy;
if (isWall(pushX, pushY) || getItemAt(pushX, pushY)) return;
item.x = pushX;
item.y = pushY;
}
entity.x = newX;
entity.y = newY;
moves++;
checkWin();
}
function checkWin() {
const allMatched = objectives.every(obj =>
items.some(item => item.x === obj.x && item.y === obj.y)
);
if (allMatched) {
if (currentLevel < levels.length - 1) {
currentLevel++;
initializeLevel();
} else {
isActive = false;
showMessage('Puzzle Complete!');
}
}
}
function render(ctx) {
const tileSize = 40;
const level = levels[currentLevel];
// Draw grid
for (let y = 0; y < level.length; y++) {
for (let x = 0; x < level[y].length; x++) {
const char = level[y][x];
if (char === '#') {
ctx.fillStyle = '#666';
ctx.fillRect(x * tileSize, y * tileSize,
tileSize, tileSize);
}
}
}
// Draw objectives
ctx.fillStyle = '#f00';
objectives.forEach(obj => {
ctx.beginPath();
ctx.arc(obj.x * tileSize + tileSize/2,
obj.y * tileSize + tileSize/2,
5, 0, Math.PI * 2);
ctx.fill();
});
// Draw items
ctx.fillStyle = '#a52';
items.forEach(item => {
ctx.fillRect(item.x * tileSize + 2,
item.y * tileSize + 2,
tileSize - 4, tileSize - 4);
});
// Draw entity
ctx.fillStyle = '#0f0';
ctx.fillRect(entity.x * tileSize + 8,
entity.y * tileSize + 8,
tileSize - 16, tileSize - 16);
// Draw moves
ctx.fillStyle = '#fff';
ctx.font = '20px Arial';
ctx.fillText('Moves: ' + moves, 10, 30);
}
document.addEventListener('keydown', (e) => {
switch(e.key) {
case 'ArrowLeft':
moveEntity(-1, 0);
break;
case 'ArrowRight':
moveEntity(1, 0);
break;
case 'ArrowUp':
moveEntity(0, -1);
break;
case 'ArrowDown':
moveEntity(0, 1);
break;
}
});
# Grid Movement Puzzle Implementation
import pygame
from dataclasses import dataclass
from typing import List, Tuple
@dataclass
class Entity:
x: int
y: int
@dataclass
class Item:
x: int
y: int
@dataclass
class Objective:
x: int
y: int
class PuzzleGame:
def __init__(self):
pygame.init()
# Game settings
self.tile_size = 40
self.levels = [
[
'#######',
'#.....#',
'#.o.*.#',
'#.p...#',
'#.o.*.#',
'#.....#',
'#######'
],
[
'########',
'#......#',
'#.p.o..#',
'#..o.*.#',
'#..*...#',
'#......#',
'########'
]
]
# Calculate window size based on largest level
max_width = max(len(level[0]) for level in self.levels)
max_height = max(len(level) for level in self.levels)
self.width = max_width * self.tile_size
self.height = max_height * self.tile_size
# Initialize display
self.screen = pygame.display.set_mode((self.width, self.height))
pygame.display.set_caption('Grid Puzzle')
self.clock = pygame.time.Clock()
# Game state
self.entity = Entity(0, 0)
self.items: List[Item] = []
self.objectives: List[Objective] = []
self.current_level = 0
self.moves = 0
self.is_active = True
self.initialize_level()
def initialize_level(self):
"""Initialize current level"""
self.items.clear()
self.objectives.clear()
level = self.levels[self.current_level]
for y, row in enumerate(level):
for x, char in enumerate(row):
if char == 'p':
self.entity.x = x
self.entity.y = y
elif char == 'o':
self.items.append(Item(x, y))
elif char == '*':
self.objectives.append(Objective(x, y))
def is_wall(self, x: int, y: int) -> bool:
"""Check if position contains a wall"""
return self.levels[self.current_level][y][x] == '#'
def get_item_at(self, x: int, y: int) -> Item:
"""Get item at position if any"""
for item in self.items:
if item.x == x and item.y == y:
return item
return None
def move_entity(self, dx: int, dy: int):
"""Move entity and handle item pushing"""
if not self.is_active:
return
new_x = self.entity.x + dx
new_y = self.entity.y + dy
if self.is_wall(new_x, new_y):
return
item = self.get_item_at(new_x, new_y)
if item:
push_x = new_x + dx
push_y = new_y + dy
if (self.is_wall(push_x, push_y) or
self.get_item_at(push_x, push_y)):
return
item.x = push_x
item.y = push_y
self.entity.x = new_x
self.entity.y = new_y
self.moves += 1
self.check_win()
def check_win(self):
"""Check if all objectives are covered"""
all_matched = all(
any(item.x == obj.x and item.y == obj.y
for item in self.items)
for obj in self.objectives
)
if all_matched:
if self.current_level < len(self.levels) - 1:
self.current_level += 1
self.initialize_level()
else:
self.is_active = False
def handle_input(self) -> bool:
"""Handle keyboard input"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
self.move_entity(-1, 0)
elif event.key == pygame.K_RIGHT:
self.move_entity(1, 0)
elif event.key == pygame.K_UP:
self.move_entity(0, -1)
elif event.key == pygame.K_DOWN:
self.move_entity(0, 1)
return True
def draw(self):
"""Draw the game state"""
# Clear screen
self.screen.fill((0, 0, 0)) # Black background
level = self.levels[self.current_level]
# Draw grid
for y, row in enumerate(level):
for x, char in enumerate(row):
if char == '#':
pygame.draw.rect(self.screen, (102, 102, 102),
(x * self.tile_size,
y * self.tile_size,
self.tile_size,
self.tile_size))
# Draw objectives
for obj in self.objectives:
pygame.draw.circle(self.screen, (255, 0, 0),
(int(obj.x * self.tile_size + self.tile_size/2),
int(obj.y * self.tile_size + self.tile_size/2)),
5)
# Draw items
for item in self.items:
pygame.draw.rect(self.screen, (170, 85, 34),
(item.x * self.tile_size + 2,
item.y * self.tile_size + 2,
self.tile_size - 4,
self.tile_size - 4))
# Draw entity
pygame.draw.rect(self.screen, (0, 255, 0),
(self.entity.x * self.tile_size + 8,
self.entity.y * self.tile_size + 8,
self.tile_size - 16,
self.tile_size - 16))
# Draw moves
font = pygame.font.Font(None, 36)
moves_text = font.render(f'Moves: {self.moves}',
True, (255, 255, 255))
self.screen.blit(moves_text, (10, 10))
# Draw completion message
if not self.is_active:
font = pygame.font.Font(None, 64)
complete_text = font.render('Puzzle Complete!',
True, (255, 255, 255))
text_rect = complete_text.get_rect(
center=(self.width//2, self.height//2))
self.screen.blit(complete_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 = PuzzleGame()
game.run()
Play Game