A full terminal Tetris implementation with three modes: play it yourself, watch a heuristic AI play, or train that AI from scratch using a genetic algorithm.
python tetris.py --mode human # Play it yourself
python tetris.py --mode ai-watch --load best_genome.pkl # Watch a trained AI play
python tetris.py --mode train --generations 50 --pop-size 40 # Evolve a new AI from scratchStandard Tetris: 7-bag piece randomization, soft drop, hard drop, rotation with basic wall-aware validity checks, line clearing, and a live score/lines/level HUD — all rendered with curses.
Loads a saved set of heuristic weights (a "genome") and watches the AI play live, one piece at a time.
Runs a genetic algorithm to evolve those weights from nothing:
- Each genome is a set of 6 weights scoring how good a resulting board is: lines cleared, aggregate column height, holes, bumpiness (unevenness between adjacent columns), max height, and a bonus for immediate line clears.
- Each generation, every genome plays several headless games (no rendering, for speed), gets scored by a fitness function (
lines cleared × 10 + score/100 − max height), and the top survivors are kept. - New genomes are produced by crossover (randomly mixing two survivors' weights) plus random mutation, and the cycle repeats for the requested number of generations.
- The best genome found is checkpointed to disk (
best_genome.pklby default) every time it improves, so a training run can be interrupted and its best result still used with--mode ai-watch.
For every possible placement of the current piece — every rotation × every column it could be dropped into — the AI simulates dropping it, evaluates the resulting board with the current weight vector, and picks whichever placement scores highest. This is a classic full-lookahead-one-piece heuristic search: no learning happens during play, all the "intelligence" is in the weights, and the weights are what the genetic algorithm is searching for.
| Flag | Default | Meaning |
|---|---|---|
--mode |
human |
human, ai-watch, or train |
--generations |
30 |
GA generations to run (train mode) |
--pop-size |
30 |
Genomes per generation (train mode) |
--survivors |
6 |
Top genomes kept each generation |
--trials |
3 |
Games played per genome when scoring fitness |
--load |
— | Genome file to load (ai-watch mode) |
--save |
best_genome.pkl |
Where to checkpoint the best genome found |
--watch-speed |
0.08 |
Seconds between AI moves in ai-watch mode |
← / → move · ↑ rotate · ↓ soft drop · Space hard drop · P pause · Q quit
Pure Python standard library — curses, argparse, pickle, random, math. On Windows, install windows-curses first.
I wanted a self-contained example of the classic heuristic-Tetris-AI approach (the same style of hand-crafted board evaluation used in well-known Tetris bots) paired with a genetic algorithm actually discovering good weights instead of hand-tuning them — and doing the whole thing, game engine included, in one dependency-free file.