game/sticks.go was the largest under-tested file in the repo: 534 lines, 23 functions and a single test. It now has two test files, both written against the C reference (git show origin/c-master:sticks.c) rather than against the current Go code, so they can catch divergence instead of recording it. game/sticks_test.go covers every zap handler that had none — light in a room and in a corridor, drain-life's too-weak refusal (which returns before o_charges--), drain's hit-point split and its kill arm, drainReaches for all three of C's clauses, invisibility and the flytrap release, polymorph's detach/re-attach dance with the pack, under- character and delta-clobbering it does on the way, cancellation, both teleport wands, magic missile, haste/slow in both directions, fix_stick's damage and charge formulas, and charge_str. game/bolt_test.go covers fire_bolt: dirch for all eight directions, boltBounces including the door the hero stands on, an end-to-end flight asserting the path and resting square, bounces off both wall orientations, off a corner and diagonally off a wall (which pins C's rule that a bounce negates both components rather than reflecting), a bounced bolt striking the hero who fired it, the strike and miss arms, and the dragon that shrugs off a flame but not a lightning bolt. The tests read the flight path off the screen: fire_bolt paints its trail and then paints chat() back over every square it recorded, so on an otherwise blank screen the non-blank cells are exactly the squares the bolt occupied, and the walls it bounced off are absent because C undoes the record before the mvaddch. Determinism comes from a pinRng helper that searches for a seed whose next draw is the wanted value, and from a level the tests carve themselves with the generator's own drawRoom. The hero is fortified wherever a bolt can reach him, since death exits the process. No divergence from C was found. Two notes are recorded in the test comments: fire_bolt's "ch != 'M'" guard is a tautology, because winat is t_disguise whenever a monster stands there, and the door-under-hero exception can only be tested by the fact that the run terminates.
Rogue: Exploring the Dungeons of Doom (Go port)
Rogue is the original dungeon-crawling adventure game that spawned an entire genre. This branch is a faithful Go port of Rogue 5.4.4: explore procedurally generated dungeons, fight monsters, collect treasure, and attempt to retrieve the Amulet of Yendor.
Original authors: Michael Toy, Ken Arnold, and Glenn Wichman (1980–1983, 1985, 1999).
The port is function-by-function faithful to the classic C sources — same
dungeon generation (seed-compatible RNG), same combat math, same item tables,
same messages. The C reference implementation lives on the master and
modern-rogue branches; ARCHITECTURE.md documents both the
original program structure and the design of this port.
Building and running
Requires Go 1.25 or later and a terminal at least 80x24.
go build ./cmd/rogue
./rogue
# Restore a saved game
./rogue ~/rogue.save
# View high scores
./rogue -s
# Test the death screen (demo mode)
./rogue -d
In-game commands
Press ? in game for the full list.
- arrows or h/j/k/l/y/u/b/n — move (shift to run, ctrl to run until adjacent)
.rest,ssearch for hidden doors and trapsiinventory,,pick up,ddropqquaff potion,rread scroll,eeat foodwwield weapon,Wwear armor,P/Rput on / remove ringtthrow,zzap a wand,f/Ffight>/<take the stairsSsave,Qquit
Environment
# Game options, as in the original
export ROGUEOPTS="name=YourName,terse,jump,fruit=mango"
# Wizard (debug) mode, with a reproducible dungeon
ROGUE_WIZARD=1 SEED=12345 ./rogue
The scoreboard is kept in ~/.rogue.scores. Save files are Go gob snapshots
and, as in the original, are deleted when restored.
Code layout
game/ the game engine: one Go file per original C file,
function-by-function (see ARCHITECTURE.md for the mapping)
term/ tcell-backed terminal, replacing curses
cmd/rogue/ the executable
The engine package is fully headless-testable: make test runs scripted command
sequences, dungeon-generation golden checks, and an RNG compatibility test
against the original C generator.
For development, the Makefile wraps the toolchain: make fmt (gofmt +
prettier), make lint (golangci-lint), make test (the suite, under the race
detector with coverage and a timeout), and make check (all three). Use the
targets rather than invoking go test directly — they carry the flags the
project relies on.
License
BSD-style; see LICENSE.TXT.
Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman. All rights reserved.