game/rings.go had no test coverage at all: not one of the suite's tests touched wearing a ring, taking one off, choosing a hand, or the ring contribution to the hunger clock. New game/rings_test.go covers ringOn, pickRingHand, ringOff, gethand, ringEat and ringNum, plus the ring arm of things.c dropcheck (dropRing), which is what actually removes a worn ring. 17 tests, 44 subtests; package coverage 53.7% -> 56.2%. No game code changes. Every expected value is transcribed from the C reference on origin/c-master (rings.c, rogue.h, things.c) and quoted in the file, rather than from what the port currently returns. No divergence from C was found. ringEat is the reason this matters most: it feeds daemons.c's hunger clock, so a wrong entry is a slow, silent drift in when the hero starves. All fourteen ring kinds are pinned to C's uses[] table, both hands. The three C subtleties are handled explicitly: a negative uses[] entry is a one-in-n chance of a single unit and not a literal cost; R_DIGEST then flips the sign, so slow digestion returns 0 or -1; and ring_num's switch closes with the otherwise macro (rogue.h 53: break;default), so its four labels fall through to one sprintf and every other kind returns "" from a default arm. The chance rings are checked by snapshotting the generator, calling ringEat, and replaying C's own expression from the identical state, which pins the one-in-n denominator, the sign flip and the fact that exactly one rnd call is spent; a frequency check over 4000 trials backs it. The non-negative entries assert the opposite, that the generator is untouched, because C never reaches rnd on that path and a stray call there would desynchronise the game's RNG stream from C's. Scripted hand answers carry an abort tail (a space for the reprompt's --More--, then ESCAPE) so that a port which stopped accepting a key fails on its assertion instead of looping forever on the headless terminal's filler input. The "only one hand free" cases script the wrong hand key on purpose: a port that prompted anyway would consume it and land the ring on the wrong side. Mutation-proved with 23 mutations, each reverted, each failing its own test and only its own. All fourteen kinds are exercised; the eleven with no wear-time effect in C are documented at the foot of the file as deliberately not given a wear/remove test, and ring_off's unreachable "not wearing such a ring" arm is documented as unreachable.
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.