Rename constructor to game.New(game.Params) per styleguide
NewGame(Config) becomes New(Params), and Restore takes Params too, so the package's primary type gets the canonical New() constructor with a named-field Params struct (styleguide points 139, 159). cmd/rogue and all tests updated; ARCHITECTURE.md constructor references corrected. Pure rename, suite green.
This commit is contained in:
@@ -1076,7 +1076,7 @@ that `game` itself has no third-party imports:
|
|||||||
go.mod module git.eeqj.de/sneak/rgoue
|
go.mod module git.eeqj.de/sneak/rgoue
|
||||||
cmd/rogue/main.go package main — flag parsing, constructs RogueGame, calls Run
|
cmd/rogue/main.go package main — flag parsing, constructs RogueGame, calls Run
|
||||||
game/ package game — the port, one .go file per .c file
|
game/ package game — the port, one .go file per .c file
|
||||||
game.go RogueGame struct, NewGame, Run (main.c)
|
game.go RogueGame struct, New, Run (main.c)
|
||||||
rng.go seeded LCG (main.c: rnd/roll + RN macro)
|
rng.go seeded LCG (main.c: rnd/roll + RN macro)
|
||||||
types.go Coord, Stats, flags, constants (rogue.h)
|
types.go Coord, Stats, flags, constants (rogue.h)
|
||||||
object.go Object type (rogue.h THING _o arm)
|
object.go Object type (rogue.h THING _o arm)
|
||||||
@@ -1120,7 +1120,7 @@ coherent, but everything is reachable from `g`.
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
// RogueGame is one complete game of Rogue: all state that was global in the
|
// RogueGame is one complete game of Rogue: all state that was global in the
|
||||||
// C implementation, plus the terminal it plays on. Construct with NewGame,
|
// C implementation, plus the terminal it plays on. Construct with New,
|
||||||
// then call Run.
|
// then call Run.
|
||||||
type RogueGame struct {
|
type RogueGame struct {
|
||||||
// --- identity / RNG ---
|
// --- identity / RNG ---
|
||||||
@@ -1193,15 +1193,15 @@ The command.c/io.c/things.c file-statics become lowercase fields of `RogueGame`,
|
|||||||
### Entrypoints
|
### Entrypoints
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func NewGame(opts Config) *RogueGame // Config: seed, name, ROGUEOPTS string, score path, wizard
|
func New(params Params) *RogueGame // Params: seed, name, ROGUEOPTS string, score path, wizard
|
||||||
func (g *RogueGame) Run() error // main.c main()+playit(): init tables, first level, daemons, loop
|
func (g *RogueGame) Run() error // main.c main()+playit(): init tables, first level, daemons, loop
|
||||||
func (g *RogueGame) command() // one turn (command.c)
|
func (g *RogueGame) command() // one turn (command.c)
|
||||||
func Restore(path string, opts Config) (*RogueGame, error) // save.c restore()
|
func Restore(path string, params Params) (*RogueGame, error) // save.c restore()
|
||||||
```
|
```
|
||||||
|
|
||||||
`cmd/rogue/main.go` is a thin shell: flags (`-s` scores, `-d` death demo,
|
`cmd/rogue/main.go` is a thin shell: flags (`-s` scores, `-d` death demo,
|
||||||
save-file arg, `SEED`/`ROGUEOPTS` env), `NewGame(...)` or `Restore(...)`,
|
save-file arg, `SEED`/`ROGUEOPTS` env), `New(...)` or `Restore(...)`, `Run()`,
|
||||||
`Run()`, exit code.
|
exit code.
|
||||||
|
|
||||||
## 4. Core types
|
## 4. Core types
|
||||||
|
|
||||||
@@ -1366,7 +1366,7 @@ type Room struct {
|
|||||||
tables that are never written after init** (the only permitted package-level
|
tables that are never written after init** (the only permitted package-level
|
||||||
data — they are ROM, not state): `monsterTable [26]MonsterKind` (name, carry %,
|
data — they are ROM, not state): `monsterTable [26]MonsterKind` (name, carry %,
|
||||||
flags, stats), `initDam` weapon table, base `objInfo` tables (copied into
|
flags, stats), `initDam` weapon table, base `objInfo` tables (copied into
|
||||||
`RogueGame.Items` at NewGame so per-game mutation — probability resumming,
|
`RogueGame.Items` at New so per-game mutation — probability resumming,
|
||||||
`oi_know`, `oi_guess` — stays instance-local), `eLevels`, `rainbow`, `stones`,
|
`oi_know`, `oi_guess` — stays instance-local), `eLevels`, `rainbow`, `stones`,
|
||||||
`woods`, `metals`, `sylls`, trap names, help text, `lvlMons`/`wandMons` spawn
|
`woods`, `metals`, `sylls`, trap names, help text, `lvlMons`/`wandMons` spawn
|
||||||
strings, `hNames`/`mNames` combat messages.
|
strings, `hNames`/`mNames` combat messages.
|
||||||
@@ -1634,6 +1634,6 @@ defers.
|
|||||||
- **Determinism test:** scripted input sequence against a fixed seed must
|
- **Determinism test:** scripted input sequence against a fixed seed must
|
||||||
produce identical final state across runs (guards hidden nondeterminism — map
|
produce identical final state across runs (guards hidden nondeterminism — map
|
||||||
iteration, time dependence).
|
iteration, time dependence).
|
||||||
- **Save round-trip:** NewGame → play N scripted turns → save → restore →
|
- **Save round-trip:** New → play N scripted turns → save → restore → compare
|
||||||
compare full state.
|
full state.
|
||||||
- `go vet` + `gofmt` clean at every commit.
|
- `go vet` + `gofmt` clean at every commit.
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ func run() int {
|
|||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
cfg := loadConfig()
|
params := loadParams()
|
||||||
|
|
||||||
if *scores {
|
if *scores {
|
||||||
game.NewGame(cfg).ShowScores()
|
game.New(params).ShowScores()
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -45,13 +45,13 @@ func run() int {
|
|||||||
}
|
}
|
||||||
defer t.Fini()
|
defer t.Fini()
|
||||||
|
|
||||||
cfg.Term = t
|
params.Term = t
|
||||||
|
|
||||||
var g *game.RogueGame
|
var g *game.RogueGame
|
||||||
|
|
||||||
if args := flag.Args(); len(args) == 1 && !*deathDemo {
|
if args := flag.Args(); len(args) == 1 && !*deathDemo {
|
||||||
// restore a saved game
|
// restore a saved game
|
||||||
g, err = game.Restore(args[0], cfg)
|
g, err = game.Restore(args[0], params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fini()
|
t.Fini()
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
@@ -59,7 +59,7 @@ func run() int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
g = game.NewGame(cfg)
|
g = game.New(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
if *deathDemo {
|
if *deathDemo {
|
||||||
@@ -81,10 +81,10 @@ func run() int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadConfig gathers the game configuration from the environment: home
|
// loadParams gathers the game parameters from the environment: home
|
||||||
// directory, ROGUEOPTS, user name, wizard mode, and the dungeon seed
|
// directory, ROGUEOPTS, user name, wizard mode, and the dungeon seed
|
||||||
// (main.c's startup).
|
// (main.c's startup).
|
||||||
func loadConfig() game.Config {
|
func loadParams() game.Params {
|
||||||
home, _ := os.UserHomeDir()
|
home, _ := os.UserHomeDir()
|
||||||
|
|
||||||
name := ""
|
name := ""
|
||||||
@@ -96,7 +96,7 @@ func loadConfig() game.Config {
|
|||||||
|
|
||||||
wizard := os.Getenv("ROGUE_WIZARD") != ""
|
wizard := os.Getenv("ROGUE_WIZARD") != ""
|
||||||
|
|
||||||
return game.Config{
|
return game.Params{
|
||||||
Seed: chooseSeed(wizard),
|
Seed: chooseSeed(wizard),
|
||||||
Name: name,
|
Name: name,
|
||||||
RogueOpts: os.Getenv("ROGUEOPTS"),
|
RogueOpts: os.Getenv("ROGUEOPTS"),
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import "testing"
|
|||||||
func mkGameInput(t *testing.T) *RogueGame {
|
func mkGameInput(t *testing.T) *RogueGame {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
g := NewGame(Config{Seed: 5, Term: &testTerm{}})
|
g := New(Params{Seed: 5, Term: &testTerm{}})
|
||||||
g.NewLevel()
|
g.NewLevel()
|
||||||
g.Oldpos = g.Player.Pos
|
g.Oldpos = g.Player.Pos
|
||||||
g.Oldrp = g.roomIn(g.Player.Pos)
|
g.Oldrp = g.roomIn(g.Player.Pos)
|
||||||
@@ -183,7 +183,7 @@ func TestZapSlowMonster(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestParseOpts(t *testing.T) {
|
func TestParseOpts(t *testing.T) {
|
||||||
g := NewGame(Config{Seed: 1})
|
g := New(Params{Seed: 1})
|
||||||
g.ParseOpts("terse,nojump,name=Conan,fruit=mango,inven=slow")
|
g.ParseOpts("terse,nojump,name=Conan,fruit=mango,inven=slow")
|
||||||
|
|
||||||
if !g.Options.Terse {
|
if !g.Options.Terse {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import "testing"
|
|||||||
func mkGame(t *testing.T, seed int32) *RogueGame {
|
func mkGame(t *testing.T, seed int32) *RogueGame {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
g := NewGame(Config{Seed: seed, Term: &testTerm{}})
|
g := New(Params{Seed: seed, Term: &testTerm{}})
|
||||||
g.NewLevel()
|
g.NewLevel()
|
||||||
g.Oldpos = g.Player.Pos
|
g.Oldpos = g.Player.Pos
|
||||||
g.Oldrp = g.roomIn(g.Player.Pos)
|
g.Oldrp = g.roomIn(g.Player.Pos)
|
||||||
|
|||||||
38
game/game.go
38
game/game.go
@@ -31,9 +31,9 @@ type Options struct {
|
|||||||
InvType int // inven: inventory style (InvOver/InvSlow/InvClear)
|
InvType int // inven: inventory style (InvOver/InvSlow/InvClear)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config carries everything needed to construct a game.
|
// Params carries everything needed to construct a game.
|
||||||
type Config struct {
|
type Params struct {
|
||||||
Seed int32 // dungeon number; the caller derives it (time+pid or SEED env)
|
Seed int32 // dungeon number; caller derives it (time+pid or SEED)
|
||||||
Name string // player name (overridden by ROGUEOPTS name=)
|
Name string // player name (overridden by ROGUEOPTS name=)
|
||||||
RogueOpts string // the ROGUEOPTS environment string
|
RogueOpts string // the ROGUEOPTS environment string
|
||||||
Home string // home directory (save file default location)
|
Home string // home directory (save file default location)
|
||||||
@@ -44,7 +44,7 @@ type Config struct {
|
|||||||
|
|
||||||
// RogueGame is one complete game of Rogue: every piece of state that was a
|
// RogueGame is one complete game of Rogue: every piece of state that was a
|
||||||
// global (or file-scope static) in the C sources, plus the terminal it is
|
// global (or file-scope static) in the C sources, plus the terminal it is
|
||||||
// played on. Construct with NewGame, then call Run.
|
// played on. Construct with New, then call Run.
|
||||||
//
|
//
|
||||||
// The struct grows with the port; fields appear in the phase that ports the
|
// The struct grows with the port; fields appear in the phase that ports the
|
||||||
// code owning them.
|
// code owning them.
|
||||||
@@ -143,22 +143,22 @@ type RogueGame struct {
|
|||||||
data *gameData
|
data *gameData
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGame builds a game from cfg, seeds the RNG, and randomizes the item
|
// New builds a game from params, seeds the RNG, and randomizes the item
|
||||||
// appearance tables (the front half of main.c main(); the player roll-up
|
// appearance tables (the front half of main.c main(); the player roll-up
|
||||||
// and first level arrive with later porting phases).
|
// and first level arrive with later porting phases).
|
||||||
func NewGame(cfg Config) *RogueGame {
|
func New(params Params) *RogueGame {
|
||||||
g := &RogueGame{
|
g := &RogueGame{
|
||||||
data: newGameData(),
|
data: newGameData(),
|
||||||
Rng: &Rng{Seed: cfg.Seed},
|
Rng: &Rng{Seed: params.Seed},
|
||||||
Dnum: int(cfg.Seed),
|
Dnum: int(params.Seed),
|
||||||
Whoami: cfg.Name,
|
Whoami: params.Name,
|
||||||
Fruit: "slime-mold",
|
Fruit: "slime-mold",
|
||||||
Home: cfg.Home,
|
Home: params.Home,
|
||||||
Wizard: cfg.Wizard,
|
Wizard: params.Wizard,
|
||||||
NoScore: cfg.Wizard,
|
NoScore: params.Wizard,
|
||||||
Playing: true,
|
Playing: true,
|
||||||
Depth: 1,
|
Depth: 1,
|
||||||
ScorePath: cfg.ScorePath,
|
ScorePath: params.ScorePath,
|
||||||
LastScore: -1,
|
LastScore: -1,
|
||||||
}
|
}
|
||||||
g.Options = Options{
|
g.Options = Options{
|
||||||
@@ -168,17 +168,17 @@ func NewGame(cfg Config) *RogueGame {
|
|||||||
}
|
}
|
||||||
g.InvDescribe = true
|
g.InvDescribe = true
|
||||||
g.Msgs.SaveMsg = true
|
g.Msgs.SaveMsg = true
|
||||||
g.scr = NewScreen(cfg.Term)
|
g.scr = NewScreen(params.Term)
|
||||||
g.Msgs.attach(g.scr, g.look, g.readchar)
|
g.Msgs.attach(g.scr, g.look, g.readchar)
|
||||||
g.FileName = cfg.Home + "/rogue.save"
|
g.FileName = params.Home + "/rogue.save"
|
||||||
|
|
||||||
g.rogueOpts = cfg.RogueOpts
|
g.rogueOpts = params.RogueOpts
|
||||||
if cfg.Wizard {
|
if params.Wizard {
|
||||||
g.Player.Flags.Set(SenseMonsters)
|
g.Player.Flags.Set(SenseMonsters)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.RogueOpts != "" {
|
if params.RogueOpts != "" {
|
||||||
g.ParseOpts(cfg.RogueOpts)
|
g.ParseOpts(params.RogueOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Monsters = g.data.monsterTable
|
g.Monsters = g.data.monsterTable
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
func genLevel(t *testing.T, seed int32) *RogueGame {
|
func genLevel(t *testing.T, seed int32) *RogueGame {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
g := NewGame(Config{Seed: seed})
|
g := New(Params{Seed: seed})
|
||||||
g.NewLevel()
|
g.NewLevel()
|
||||||
|
|
||||||
return g
|
return g
|
||||||
@@ -159,7 +159,7 @@ func TestNewLevelDeterministic(t *testing.T) {
|
|||||||
// mazes, dark rooms, traps, treasure rooms — as a crash/invariant sweep.
|
// mazes, dark rooms, traps, treasure rooms — as a crash/invariant sweep.
|
||||||
func TestDeeperLevels(t *testing.T) {
|
func TestDeeperLevels(t *testing.T) {
|
||||||
for _, seed := range []int32{7, 42, 1000, 31337} {
|
for _, seed := range []int32{7, 42, 1000, 31337} {
|
||||||
g := NewGame(Config{Seed: seed})
|
g := New(Params{Seed: seed})
|
||||||
for depth := 1; depth <= 30; depth++ {
|
for depth := 1; depth <= 30; depth++ {
|
||||||
g.Depth = depth
|
g.Depth = depth
|
||||||
g.NewLevel()
|
g.NewLevel()
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
func TestRunScriptedSession(t *testing.T) {
|
func TestRunScriptedSession(t *testing.T) {
|
||||||
tt := &testTerm{input: []byte("hjkl.i Qy")}
|
tt := &testTerm{input: []byte("hjkl.i Qy")}
|
||||||
|
|
||||||
g := NewGame(Config{Seed: 99, Term: tt})
|
g := New(Params{Seed: 99, Term: tt})
|
||||||
|
|
||||||
err := g.Run()
|
err := g.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -52,7 +52,7 @@ func TestRunManyTurns(t *testing.T) {
|
|||||||
script = append(script, " Q y Qy"...)
|
script = append(script, " Q y Qy"...)
|
||||||
tt := &testTerm{input: script}
|
tt := &testTerm{input: script}
|
||||||
|
|
||||||
g := NewGame(Config{Seed: 31337, Term: tt})
|
g := New(Params{Seed: 31337, Term: tt})
|
||||||
|
|
||||||
err := g.Run()
|
err := g.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -68,7 +68,7 @@ func TestRunManyTurns(t *testing.T) {
|
|||||||
// wizard style, then descends and keeps playing.
|
// wizard style, then descends and keeps playing.
|
||||||
func TestRunDownStairs(t *testing.T) {
|
func TestRunDownStairs(t *testing.T) {
|
||||||
tt := &testTerm{input: []byte(">..Qy")}
|
tt := &testTerm{input: []byte(">..Qy")}
|
||||||
g := NewGame(Config{Seed: 7, Term: tt})
|
g := New(Params{Seed: 7, Term: tt})
|
||||||
g.NewLevel()
|
g.NewLevel()
|
||||||
g.Player.Pos = g.Level.Stairs // stand on the stairs
|
g.Player.Pos = g.Level.Stairs // stand on the stairs
|
||||||
g.restored = true // keep Run from regenerating the level
|
g.restored = true // keep Run from regenerating the level
|
||||||
@@ -99,7 +99,7 @@ func TestSaveCommandRoundTrip(t *testing.T) {
|
|||||||
// 'S' with no default file name goes straight to the name prompt.
|
// 'S' with no default file name goes straight to the name prompt.
|
||||||
script := "S" + path + "\n"
|
script := "S" + path + "\n"
|
||||||
tt := &testTerm{input: []byte(script)}
|
tt := &testTerm{input: []byte(script)}
|
||||||
g := NewGame(Config{Seed: 55, Term: tt})
|
g := New(Params{Seed: 55, Term: tt})
|
||||||
|
|
||||||
g.FileName = "" // force the name prompt
|
g.FileName = "" // force the name prompt
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ func TestSaveCommandRoundTrip(t *testing.T) {
|
|||||||
t.Fatalf("Run: %v", runErr)
|
t.Fatalf("Run: %v", runErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
h, err := Restore(path, Config{Term: &testTerm{}})
|
h, err := Restore(path, Params{Term: &testTerm{}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Restore: %v", err)
|
t.Fatalf("Restore: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -681,7 +681,7 @@ var ErrSaveOutOfDate = errors.New("sorry, saved game is out of date")
|
|||||||
|
|
||||||
// Restore restores a saved game from a file (save.c restore). The file is
|
// Restore restores a saved game from a file (save.c restore). The file is
|
||||||
// deleted, as in C, to defeat restarting from the same save.
|
// deleted, as in C, to defeat restarting from the same save.
|
||||||
func Restore(path string, cfg Config) (*RogueGame, error) {
|
func Restore(path string, params Params) (*RogueGame, error) {
|
||||||
f, err := os.Open(path) //nolint:gosec // G304: the save path is user-chosen by design
|
f, err := os.Open(path) //nolint:gosec // G304: the save path is user-chosen by design
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -704,12 +704,12 @@ func Restore(path string, cfg Config) (*RogueGame, error) {
|
|||||||
data: newGameData(),
|
data: newGameData(),
|
||||||
Rng: &Rng{},
|
Rng: &Rng{},
|
||||||
Playing: true,
|
Playing: true,
|
||||||
ScorePath: cfg.ScorePath,
|
ScorePath: params.ScorePath,
|
||||||
FileName: path,
|
FileName: path,
|
||||||
rogueOpts: cfg.RogueOpts,
|
rogueOpts: params.RogueOpts,
|
||||||
restored: true,
|
restored: true,
|
||||||
}
|
}
|
||||||
g.scr = NewScreen(cfg.Term)
|
g.scr = NewScreen(params.Term)
|
||||||
g.Msgs.attach(g.scr, g.look, g.readchar)
|
g.Msgs.attach(g.scr, g.look, g.readchar)
|
||||||
g.applySnapshot(&st)
|
g.applySnapshot(&st)
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func TestSaveRestoreRoundTrip(t *testing.T) {
|
|||||||
t.Fatalf("saveFile: %v", saveErr)
|
t.Fatalf("saveFile: %v", saveErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
h, err := Restore(path, Config{Term: &testTerm{}})
|
h, err := Restore(path, Params{Term: &testTerm{}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Restore: %v", err)
|
t.Fatalf("Restore: %v", err)
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,7 @@ func TestRestoreRejectsWrongVersion(t *testing.T) {
|
|||||||
t.Fatal(closeErr)
|
t.Fatal(closeErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, restoreErr := Restore(path, Config{})
|
_, restoreErr := Restore(path, Params{})
|
||||||
if restoreErr == nil {
|
if restoreErr == nil {
|
||||||
t.Error("restore accepted an out-of-date save")
|
t.Error("restore accepted an out-of-date save")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func TestProbabilitiesSumTo100(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestInitProbsCumulative(t *testing.T) {
|
func TestInitProbsCumulative(t *testing.T) {
|
||||||
g := NewGame(Config{Seed: 1})
|
g := New(Params{Seed: 1})
|
||||||
|
|
||||||
last := g.Items.Potions[NumPotionTypes-1].Prob
|
last := g.Items.Potions[NumPotionTypes-1].Prob
|
||||||
if last != 100 {
|
if last != 100 {
|
||||||
@@ -47,14 +47,14 @@ func TestInitProbsCumulative(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestNewGameRandomizesAppearances(t *testing.T) {
|
func TestNewGameRandomizesAppearances(t *testing.T) {
|
||||||
g := NewGame(Config{Seed: 12345})
|
g := New(Params{Seed: 12345})
|
||||||
|
|
||||||
checkPotionColors(t, g)
|
checkPotionColors(t, g)
|
||||||
checkScrollNames(t, g)
|
checkScrollNames(t, g)
|
||||||
checkWandMaterials(t, g)
|
checkWandMaterials(t, g)
|
||||||
|
|
||||||
// Determinism: same seed, same appearances.
|
// Determinism: same seed, same appearances.
|
||||||
h := NewGame(Config{Seed: 12345})
|
h := New(Params{Seed: 12345})
|
||||||
if h.Items != g.Items {
|
if h.Items != g.Items {
|
||||||
t.Error("two games with the same seed produced different item lore")
|
t.Error("two games with the same seed produced different item lore")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user