pac-man
Python project · featured · game, pygame, duo
Pac-Man in Python, built as a duo with sylvzzz: a new maze every level and four ghosts that each hunt you differently.



- 4ghosts, each with its own target
- 10levels, a new maze each
- 0pygame imports in the game rules
The problem
Rebuild the 1980 arcade game in Python as a duo with sylvzzz, with a twist: every level is a fresh maze from an assigned maze package, so nothing about the board can be hard-coded. The game rules also had to stay independent from the graphics.
What I built
- My half was
pacman.core, the game itself with no pygame anywhere: maze loading, levels, the player, the ghosts, scoring and the config parser. sylvzzz builtpacman.ui(rendering, scenes, input). "core never imports pygame" was our contract from day one, and it lets every rule be tested headless on CI. - A loader that expands the package's per-cell wall bitmasks into a (2w+1) x (2h+1) tile grid. It starts from solid walls and carves, so a tile it misses is a harmless wall, never a hole in the border.
- Ghost AI on corridor distances, not straight lines: cached BFS maps per target, and each ghost aims differently (one chases, one ambushes four tiles ahead, a shy one backs off when close, a whimsical one turns at random) so the pack surrounds you instead of queueing behind you.
- Scatter and chase phases for the first minute, frightened ghosts that flee along the BFS gradient, eaten ghosts whose eyes walk home, and ghosts 4% faster each level, capped at +40%.
- A config parser that never crashes on a bad value: missing keys take their default, out-of-range ones are clamped with a warning, and only an unreadable file or broken JSON stops the game, with one readable line instead of a traceback.
- Separate branches merged through pull requests, with CI (flake8, mypy, tests) and an automated AI review on every push.
The hard part
Making a random maze always playable. The package's closed "42" cells can wall off a pocket of corridor, and a pacgum in there can never be eaten, so the level never ends. Unreachable tiles are now sealed before anything is placed, and since tile (1, 1) may well be a wall in the next maze, nothing uses fixed coordinates: every spawn searches for the nearest open tile.
Built with
- Python 3.10+
- pygame-ce
- pytest
- flake8 + mypy
- GitHub Actions
- PyInstaller
More projects
- metro · Lisbon metro sim in pixel art: watch the four lines run, step into any station, board a train and ride it.
- call_me_maybe · Turns a sentence into a JSON function call with a 0.6B model using constrained decoding — parseable by construction, not by luck.
- codexion · Multithreaded twist on the Dining Philosophers: coders compete for shared dongles, with FIFO/EDF scheduling.
- fly-in · Drone fleet routing: Dijkstra pathfinding, turn-based scheduling and a pygame replay.
- a-maze-ing · Maze generator with multiple algorithms, pathfinding solvers and terminal visualization.
- push_swap · Highly optimized sorting with two stacks and a tiny set of allowed operations.
- ft_printf · printf rebuilt from scratch: chars, strings, pointers, decimals, unsigned and hex.
- get_next_line · Reads a file descriptor one line at a time with careful dynamic memory handling.
- Libft · My own C standard library — the foundation every later 42 project is built on.