go: port foundation — types, RNG, tables, daemon scheduler
Module sneak.berlin/go/rogue, package game: - types.go: all rogue.h constants, flag types, Coord/Stats/Room/ObjInfo - creature.go/object.go: the THING union split into Creature (Player/ Monster) and Object; slices replace the C linked lists - level.go: Place map with the C column-major layout and chat/flat/moat/ winat access methods - tables.go: extern.c + init.c data (bestiary, item tables, name pools) - rng.go: the exact C LCG (seed*11109+13849), golden-tested against a compiled C reference for seed compatibility - init.go: per-game item appearance randomization (init.c) - daemon.go/daemons.go: scheduler with DaemonID replacing function pointers (ids match the C save format's mapping) - game.go: RogueGame holds all former globals; NewGame constructor
This commit is contained in:
86
game/tables_test.go
Normal file
86
game/tables_test.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package game
|
||||
|
||||
import "testing"
|
||||
|
||||
// badcheck from init.c: every probability table must sum to exactly 100.
|
||||
func TestProbabilitiesSumTo100(t *testing.T) {
|
||||
sum := func(info []ObjInfo) int {
|
||||
s := 0
|
||||
for _, oi := range info {
|
||||
s += oi.Prob
|
||||
}
|
||||
return s
|
||||
}
|
||||
tables := map[string][]ObjInfo{
|
||||
"things": baseThings[:],
|
||||
"potions": basePotInfo[:],
|
||||
"scrolls": baseScrInfo[:],
|
||||
"rings": baseRingInfo[:],
|
||||
"sticks": baseWsInfo[:],
|
||||
"weapons": baseWeapInfo[:MaxWeapons], // excludes the flame entry
|
||||
"armor": baseArmInfo[:],
|
||||
}
|
||||
for name, tab := range tables {
|
||||
if s := sum(tab); s != 100 {
|
||||
t.Errorf("bad percentages for %s: sum = %d, want 100", name, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitProbsCumulative(t *testing.T) {
|
||||
g := NewGame(Config{Seed: 1})
|
||||
last := g.Items.Potions[MaxPotions-1].Prob
|
||||
if last != 100 {
|
||||
t.Errorf("cumulative potion probability ends at %d, want 100", last)
|
||||
}
|
||||
for i := 1; i < MaxPotions; i++ {
|
||||
if g.Items.Potions[i].Prob < g.Items.Potions[i-1].Prob {
|
||||
t.Errorf("potion probs not nondecreasing at %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewGameRandomizesAppearances(t *testing.T) {
|
||||
g := NewGame(Config{Seed: 12345})
|
||||
seen := map[string]bool{}
|
||||
for i, c := range g.Items.PotColors {
|
||||
if c == "" {
|
||||
t.Fatalf("potion %d has no color", i)
|
||||
}
|
||||
if seen[c] {
|
||||
t.Errorf("potion color %q assigned twice", c)
|
||||
}
|
||||
seen[c] = true
|
||||
}
|
||||
for i, n := range g.Items.ScrNames {
|
||||
if n == "" {
|
||||
t.Fatalf("scroll %d has no name", i)
|
||||
}
|
||||
if len(n) > MaxNameLen+1 {
|
||||
t.Errorf("scroll name %q longer than C buffer allows", n)
|
||||
}
|
||||
}
|
||||
for i := range g.Items.WandType {
|
||||
if g.Items.WandType[i] != "wand" && g.Items.WandType[i] != "staff" {
|
||||
t.Errorf("stick %d has type %q", i, g.Items.WandType[i])
|
||||
}
|
||||
if g.Items.WandMade[i] == "" {
|
||||
t.Errorf("stick %d has no material", i)
|
||||
}
|
||||
}
|
||||
|
||||
// Determinism: same seed, same appearances.
|
||||
h := NewGame(Config{Seed: 12345})
|
||||
if h.Items != g.Items {
|
||||
t.Error("two games with the same seed produced different item lore")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMonsterTable(t *testing.T) {
|
||||
if monsterTable[0].Name != "aquator" || monsterTable[25].Name != "zombie" {
|
||||
t.Error("monster table order broken")
|
||||
}
|
||||
if monsterTable['D'-'A'].Name != "dragon" {
|
||||
t.Error("letter indexing broken")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user