NetHack Full Logic Port to JS/TS — Checklist

NetHack Full Logic Port to JS/TS — Checklist

NetHack Full Logic Port to JS/TS — Checklist (English)

0. Core Choices

  • Target Version: NetHack 3.7 (trunk) — fewer legacy #ifdefs and the latest fixes.
  • Language: TypeScript (strict) — maps C structs to interfaces with strong typing and IDE support.
  • License: Keep the NetHack General Public License (NGPL); include LICENSE and source when publishing.

1. Repository Skeleton

/core         ← TypeScript game engine
  /dungeon    ← generation & topology
  /actors     ← monsters, player
  /items      ← objects & inventory rules
  /rules      ← combat, magic, conducts
/tests        ← Jest golden-file tests
/ui-c         ← original C "window port" or BrowserHack WASM
/scripts      ← build helpers & code-gen scripts

Keep the original C sources under /ui-c/; remove a C file only after its TS equivalent passes tests.

2. Automated Safety Net

  1. Deterministic RNG: Make C/WASM read RNG_SEED so both engines reproduce the same sequence.
  2. Per-turn state dump: Serialize dungeon map, hero stats, monster list, etc., to JSON.
  3. Golden-file tests (Jest): Feed identical key sequences to both engines and assert deep equality of the JSON dumps.

3. Translation Guidelines

  • C structs → TS: Use interface (or class if methods are needed).
  • Bit-field flags: Keep numeric mask values; expose them via a TS enum for readability.
  • Global arrays: Export const arrays; generate contents from .h tables with a small script.
  • Function-like macros: Rewrite as plain TS functions to remove hidden indirection.
  • goto error paths: Replace with try…finally or early return for clarity.

4. Recommended Port Order (Easy → Hard)

  1. Utility libraries (e.g., hacklib.c): RNG and string helpers.
  2. Data types: coord, obj, monst, level, and all enums.
  3. Save/Load: JSON first; binary compatibility later if desired.
  4. Dungeon generation: dungeon.c, mklev.c, sp_lev.c.
  5. Turn loop & timing: moveloop.c, energy accounting, hunger clock.
  6. Combat mechanics: uhitm.c, mhitu.c, throwing and hit logic.
  7. Inventory & items: stacking, weight, erosion, polymorph.
  8. Magic & prayers: spell.c, pray.c, zap.c.
  9. Edge cases: extinction, genocide, vault guard, demon gating, and other rarities.
  10. Conducts & scoring: ascend checks, death handling, conduct penalties.

5. Helpful Tooling

  • tree-sitter-c → TS stub generator: Parse the C AST and auto-generate TS function signatures.
  • clang-format: Normalize indentation in the original C to clarify block structure.
  • // @ts-expect-error: Temporarily mute errors for not-yet-ported modules.

6. Incremental Hand-Off Pattern

export function mhitm(mon: Monster, target: Monster | Player): AttackResult {
  if (!ported) {
    // Fallback to the original C/WASM implementation
    return cBindings.mhitm(mon.id, target.id);
  }
  // Translated TypeScript logic goes here…
}

7. Performance Notes

  • Modern JS engines comfortably handle NetHack-scale logic (millions of ops per turn).
  • Offload hotspots (e.g., line-of-sight, pathfinding) to small WASM modules if needed.

8. Reference Code

  • BrowserHack / NetHackJS: concrete examples of JS shims for the NetHack window interface.
  • Hacker News rewrite discussions: practical pitfalls and lessons from earlier attempts.

9. Estimated Effort

  • Minimal playable demo: 3–4 months (one developer × 20 h/week).
  • Full 3.7 parity: 1–2 years, including edge cases and wizard-mode tools.

10. Next Steps

  1. Fork NetHack 3.7; add deterministic RNG and per-turn JSON state dumps to the C build.
  2. Generate TypeScript interfaces from all C structs using a small script.
  3. Port hacklib.c; write the first golden-file test and make it pass.

Comments

Popular posts from this blog

Japan Jazz Anthology Select: Jazz of the SP Era

In practice, the most workable approach is to measure a composite “civility score” built from multiple indicators.