sneak ba444a2002 Unit-test the eight trap effects against the C reference (closes #14)
`trapHandlers` had eight entries and zero direct tests, on the one
subsystem besides combat that can kill the hero outright. New
`game/traps_test.go` covers all eight arms of `move.c be_trapped`, the
prologue every trap runs through, and the `rust_armor` tail `T_RUST`
calls. Test-only: no game code changes.

Every expected value is transcribed from `origin/c-master` (`move.c`,
`misc.c`, `fight.c`, `monsters.c`, `rogue.h`) and quoted in the file. No
divergence from C was found.

The trap set is `rogue.h` 192-200: there is no separate "poison dart"
kind — `T_DART` is the poisoned dart — and `T_MYST`, the eleven-way
`rnd(11)` message switch, is the eighth. Details the tests are built
around: `BEARTIME`/`SLEEPTIME` are `spread(3)`/`spread(5)`, both of which
reduce to `rnd(0)` and so cost no random number, which is asserted as
well as their values; `T_ARROW` swings at `s_lvl - 1` and `T_DART` at
`s_lvl + 1`; and the strength loss is gated on `!ISWEARING(R_SUSTSTR) &&
!save(VS_POISON)`, whose short circuit means the ring saves a random draw
as well as the strength.

Damage dice and swing arguments are checked by sweeps rather than single
shots: `rnd(n)` is "raw value % n", so one draw cannot separate a d6 from
a d5, and a forced hit or miss cannot see a wrong `at_lvl`. Both shapes
were forced by mutation runs that the single-shot versions survived.

`be_trapped` takes a coordinate, and which coordinate decides whether
`T_TELEP`'s `mvaddch(tc, TRAP)` does anything. Sprung under the hero
(`move.go` 105-108, `case Floor`) the line is redundant: `tc` is the
hero's square, already stamped `TRAP` by the prologue and redrawn by
`teleport()`'s opening `mvaddch(hero, floor_at())`. Walked onto
(`move.go` 94-98, `case Trap`) it is the only writer: `tc` is the square
being stepped onto while the hero still stands on the previous one,
`leave_room` writes blanks and never `TRAP`, and the arm returns before
`finishMove` so no `look()` follows. Both shapes are tested.

The two death messages are deliberately uncovered: each is printed
immediately before `death()`, which reaches `myExit` and `os.Exit`, so
provoking either would kill the test binary. The hero is pinned with
`fortify()` and the damage is checked by replaying C's arithmetic. They
are the only two: `rust_armor`'s `|| ISWEARING(R_SUSTARM)` operand and
its `if (!to_death)` message suppression are covered as well.
2026-08-09 16:01:19 +00:00
2016-07-23 03:24:54 +01:00
2016-07-23 03:24:54 +01:00
2016-07-23 03:24:54 +01:00

Rogue: Exploring the Dungeons of Doom (Go port)

License

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 (19801983, 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, s search for hidden doors and traps
  • i inventory, , pick up, d drop
  • q quaff potion, r read scroll, e eat food
  • w wield weapon, W wear armor, P/R put on / remove ring
  • t throw, z zap a wand, f/F fight
  • >/< take the stairs
  • S save, Q quit

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.

Description
No description provided
Readme 3.4 MiB
Languages
Go 99.3%
Makefile 0.5%
Shell 0.2%