py_maze py_maze
Source

Cheat sheet

The options, the keys, the markers, the codes and the public names, dense and without explanation. For a reader who has already read the rest.

Options

Option Short Default Takes
--width -w preset cells, minimum 2
--height -H preset cells, minimum 2
--difficulty -d normal easy, normal, hard
--algorithm -A backtracker backtracker, prim, division
--braid -b 0 0 to 1, bare flag means 1
--seed -s random a number or a word
--collectibles -c 0 a count
--mode -m plain plain, chase, quest
--chase-point   55 20 to 90, chase mode only
--chase-speed   2 0 to 5, chase mode only
--quest-stages   3 1 to 9, quest mode only
--save -o   a file, or - for standard output
--load -l   a file, or - for standard input
--wall-char   * one character, headerless files only
--open-char   space one character, headerless files only
--format -f text text, json
--solve -S off flag
--animate -a off flag
--stats   off flag
--quiet -q off flag
--version -V   flag
--help -h   flag

Capital -H is height, -S solves, -A is the algorithm, -o saves, -m is the mode. Lowercase -h is the help and -s is the seed. --stats has no short flag, both s letters being taken.

--stats prints under the maze and leaves the picture alone. A quiet run reports the measurements, having been asked for them; a --format json run prints the document alone and carries the same numbers under its stats key. A braided run tallies how many dead ends were opened as well. Reading a maze explains each of them.

Both chase options round a decimal to the nearest whole number, resolve a number outside their range to the nearer end of it, and answer anything that is not a number at all with a notice on standard error before carrying on without it. --quest-stages is refused rather than settled, shaping the maze rather than tuning a chase already under way.

Sizes

Preset Cells Characters
easy 6 by 6 13 by 13
normal 9 by 11 19 by 23
hard 16 by 20 33 by 41

W by H cells renders as W * 2 + 1 by H * 2 + 1 characters. Sizes are capped to the terminal unless the output is piped or redirected.

Commands worth keeping

py_maze -d hard --seed winter            # a repeatable hard maze
py_maze -A prim -b 0.25 --solve          # open carving, a quarter braided
py_maze -c 6 --save maze.txt             # six pickups, kept in a file
py_maze --load maze.txt --solve          # play back and print the route
py_maze --load maze.txt --animate        # watch the search instead
py_maze -q -f json                       # a document, nothing else
py_maze --seed 2024 --save - | py_maze --load - --solve
py_maze --load drawn.txt --wall-char '#' --open-char '.' --quiet
py_maze --mode chase                     # something follows you halfway in
py_maze -m chase --chase-point 20 --chase-speed 5
py_maze --mode quest                     # doors, boxes and a guide
py_maze -m quest --quest-stages 5 -f json --save quest.json
py_maze -d hard --stats                  # what the maze measures, under it
py_maze -q --stats                       # the maze and the measurements

Modes

Mode Is Options of its own
plain The walk from the entrance to the exit  
chase The same walk, with something following you --chase-point, --chase-speed
quest The way on is shut until you find what opens it --quest-stages

--chase-point is a share of the maze, read off the solution measured as the straight runs it is made of. --chase-speed is a preset: the moves the chaser makes in a second, 0 for one a second rising to 5 for six. Being caught ends the run the way the exit does, with an Outcome line on the summary naming which of the two happened.

--quest-stages is how many doors shut the route, each opened by the item in a box hidden before it. Only the JSON document carries a quest; a picture is the plain maze under it. Game modes has all three.

Keys, in play

Key Does
Arrows, W A S D Move up, left, down, right
h Light the next step for a moment
n Ask the guide what the next errand is, in quest mode
q Quit, with the summary so far
Ctrl+C Interrupt, restoring the terminal
y / n The “would you like to play” prompt, one keypress

Markers

Drawn Is Constant
* Wall WALL_MARKER
space Open cell OPEN_MARKER
o The player PLAYER_MARKER
. Solution SOLUTION_MARKER
~ Explored, under --animate VISITED_MARKER
? Frontier, and a hint FRONTIER_MARKER, HINT_MARKER
$ Collectible COLLECTIBLE_MARKER
X The chaser, in chase mode CHASER_MARKER
# A door you cannot pass yet, in quest mode DOOR_MARKER
& A box with an item in it, in quest mode BOX_MARKER
@ The guide, in quest mode GUIDE_MARKER

Status codes

Code Means
0 Finished
2 An option the command line will not take
3 Not a maze this build can read, or fewer than 3 characters wide
4 A file that could not be read, or written
5 No way from the entrance to the exit, when one was asked for

On the package as EXIT_OK, EXIT_USAGE, EXIT_SAVE_FILE, EXIT_FILE_ERROR, EXIT_NO_WAY_THROUGH.

Save file

# py_maze save 1
# seed: 2024
* ***********
* *     *   *
...

Header first, comments start with #, the maze is drawn with *, the space and $. --format json writes the same maze as a document keyed py_maze, seed, entrance, exit, collectibles, solution, grid. Specified in full on the save file format.

The package, in one screen

import py_maze

grid = py_maze.MazeGenerator(width=6, height=6, seed=2024,
                             algorithm='prim').generate()
py_maze.braid_maze(grid, 0.25, py_maze.MazeGenerator(2, 2).random)

entrance = py_maze.find_entrance(grid)     # (x, y) in the top row
exit_cell = py_maze.find_exit(grid)        # (x, y) in the bottom row
path = py_maze.solve_maze(grid)            # a list of cells, or None

for line in py_maze.maze_lines(grid, py_maze.solution_overlay(path)):
    print(line)

py_maze.write_save('maze.txt', grid, seed=2024)
grid, collectibles, seed = py_maze.read_save('maze.txt')

A maze is a grid: rows of booleans, True for a wall, addressed grid[y][x], a cell always written (x, y). Every public name is tabled on the library page.

Want Call
Carve MazeGenerator(...).generate(), or carve_prim(w, h, rng)
Open the dead ends braid_maze(grid, share, rng)
Scatter pickups place_collectibles(grid, count, rng)
Solve solve_maze(grid, start, end)
Watch it solve search_frames(grid, start, end)
Measure a route solution_runs(path), maze_progress(grid, cell, path)
Measure a maze maze_stats(grid, path, dead_ends_before)
Read how hard it is difficulty_score(open_count, junctions_count, path)
Say a search found nothing pass None; UNSEARCHED asks for the search
Read its parts dead_ends(grid), junctions(grid), longest_corridor(grid)
Read a route’s share solution_share(path, open_count)
Play a mode game_mode(name), plain_game(...), chase_game(...)
Draw maze_lines(grid, overlays), print_maze(...)
Write, read write_save(...), read_save(...), save_json(...)
Parse text in hand parse_save(text, source, chars)
Play it MazeGame(grid, ...)