aboutsummaryrefslogtreecommitdiff
path: root/internal/game
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-07-07 16:46:32 -0400
committerhistoria <[not public]>2026-07-07 16:46:32 -0400
commit726997d799edc388cd448e978d5bb0755aaa551c (patch)
treeb7aa8dc2dc9d2edcad1c0a4012a28d01d348db69 /internal/game
parentab2597b22ccdb71116992aec78080d9858358d04 (diff)
downloadthehouseoficarus-726997d799edc388cd448e978d5bb0755aaa551c.tar.gz
feat: bitpacked and base64 encoded VisitedRooms in player YAML to keep the file human readable
Diffstat (limited to 'internal/game')
-rw-r--r--internal/game/cmd_score.go2
-rw-r--r--internal/game/exit_migrate.go6
-rw-r--r--internal/game/exit_migrate_test.go8
-rw-r--r--internal/game/map_test.go4
-rw-r--r--internal/game/render_map.go16
5 files changed, 19 insertions, 17 deletions
diff --git a/internal/game/cmd_score.go b/internal/game/cmd_score.go
index b493e80..59cedb1 100644
--- a/internal/game/cmd_score.go
+++ b/internal/game/cmd_score.go
@@ -174,7 +174,7 @@ func (g *Game) doScore(sess *net.Session) {
sep()
stats := p.Stats
statsLine := fmt.Sprintf("Rooms Explored: %d Kills: %d Deaths: %d",
- len(stats.RoomsVisited), stats.TotalKills, stats.Deaths)
+ stats.RoomsVisited.Len(), stats.TotalKills, stats.Deaths)
content(statsLine)
content(fmt.Sprintf("APS Nodes Found: %d", len(getKnownApsNodes(p))))
diff --git a/internal/game/exit_migrate.go b/internal/game/exit_migrate.go
index 845a6b2..2872f34 100644
--- a/internal/game/exit_migrate.go
+++ b/internal/game/exit_migrate.go
@@ -10,7 +10,7 @@ import (
// rewritePlayerRoomIDs remaps room-ID-embedded state in a single player per
// idMap (oldID -> newID): discovered-exit player flag keys
// (hidden_exit_<id>_<dir>), current RoomID, EnterSeqRoom, MapSymbols keys, and
-// Stats.RoomsVisited keys. Returns whether any field was changed.
+// Stats.RoomsVisited bitset. Returns whether any field was changed.
//
// idMap is assumed to be a bijection (see Room.RewriteRoomIDs); the flag-key
// and int-map rekeys use delete-all-then-set-all so a swap (A<->B) cannot
@@ -32,7 +32,9 @@ func rewritePlayerRoomIDs(p *player.Player, idMap map[int]int) bool {
if len(p.MapSymbols) > 0 && rekeyIntMap(p.MapSymbols, idMap) {
changed = true
}
- if len(p.Stats.RoomsVisited) > 0 && rekeyIntMap(p.Stats.RoomsVisited, idMap) {
+ next, moved := p.Stats.RoomsVisited.Rekey(idMap)
+ if moved {
+ p.Stats.RoomsVisited = next
changed = true
}
return changed
diff --git a/internal/game/exit_migrate_test.go b/internal/game/exit_migrate_test.go
index 05edea5..f86b85b 100644
--- a/internal/game/exit_migrate_test.go
+++ b/internal/game/exit_migrate_test.go
@@ -21,7 +21,7 @@ func TestRewritePlayerRoomIDsRename(t *testing.T) {
30: {Char: "Y"},
},
}
- p.Stats.RoomsVisited = map[int]bool{10: true, 40: true}
+ p.Stats.RoomsVisited = player.NewRoomSetFrom(10, 40)
idMap := map[int]int{10: 100, 20: 200}
if !rewritePlayerRoomIDs(p, idMap) {
@@ -53,13 +53,13 @@ func TestRewritePlayerRoomIDsRename(t *testing.T) {
if _, ok := p.MapSymbols[10]; ok {
t.Error("MapSymbols should not still have key 10")
}
- if !p.Stats.RoomsVisited[100] {
+ if !p.Stats.RoomsVisited.Has(100) {
t.Error("RoomsVisited missing key 100")
}
- if !p.Stats.RoomsVisited[40] {
+ if !p.Stats.RoomsVisited.Has(40) {
t.Error("RoomsVisited missing unchanged key 40")
}
- if p.Stats.RoomsVisited[10] {
+ if p.Stats.RoomsVisited.Has(10) {
t.Error("RoomsVisited should not still have key 10")
}
}
diff --git a/internal/game/map_test.go b/internal/game/map_test.go
index 2fe9c1e..2975551 100644
--- a/internal/game/map_test.go
+++ b/internal/game/map_test.go
@@ -406,7 +406,7 @@ func TestMap3DDisconnectedComponent(t *testing.T) {
// Player has only visited tower 1. Tower 2 should appear but dimmed (unvisited).
sess := &net.Session{Player: &player.Player{
- Stats: player.PlayerStats{RoomsVisited: map[int]bool{1: true}},
+ Stats: player.PlayerStats{RoomsVisited: player.NewRoomSetFrom(1)},
Flags: map[string]any{},
}}
@@ -429,7 +429,7 @@ func TestMap3DDifferentZExcluded(t *testing.T) {
g := &Game{Deps: Deps{World: world.New(dir)}, GlobalFlags: NewGlobalFlagStore()}
mg := mapGlyphsForPlayer(false)
sess := &net.Session{Player: &player.Player{
- Stats: player.PlayerStats{RoomsVisited: map[int]bool{1: true, 2: true}},
+ Stats: player.PlayerStats{RoomsVisited: player.NewRoomSetFrom(1, 2)},
Flags: map[string]any{},
}}
diff --git a/internal/game/render_map.go b/internal/game/render_map.go
index 0177595..3f9c4da 100644
--- a/internal/game/render_map.go
+++ b/internal/game/render_map.go
@@ -131,7 +131,7 @@ func buildTinyMap(g *Game, sess *net.Session, roomID int, mg mapGlyphs) []string
if rid == roomID {
grid[gr][gc] = mapCell{char: '@', spec: atSpec}
} else {
- unvisited := visited != nil && !visited[rid]
+ unvisited := visited != nil && !visited.Has(rid)
ch, spec := roomMapSymbol(g, sess, rid, unvisited)
if unvisited {
spec = dimSpec
@@ -307,7 +307,7 @@ func buildFullMap(g *Game, sess *net.Session, roomID, mapWidth, mapHeight int, m
if rid == roomID {
grid[gr][gc] = mapCell{char: '@', spec: atSpec}
} else {
- unvisited := visited != nil && !visited[rid]
+ unvisited := visited != nil && !visited.Has(rid)
ch, spec := roomMapSymbol(g, sess, rid, unvisited)
if unvisited {
spec = dimSpec
@@ -409,9 +409,9 @@ func buildFullMap(g *Game, sess *net.Session, roomID, mapWidth, mapHeight int, m
return renderMapCells(grid, colorMode, 0, mapHeight, 0)
}
-func roomsVisited(sess *net.Session) map[int]bool {
+func roomsVisited(sess *net.Session) *player.RoomSet {
if sess != nil && sess.Player != nil {
- return sess.Player.Stats.RoomsVisited
+ return &sess.Player.Stats.RoomsVisited
}
return nil
}
@@ -457,7 +457,7 @@ type mapRenderCtx struct {
g *Game
sess *net.Session
bg *mapGraph
- visited map[int]bool
+ visited *player.RoomSet
currentRoom int
atSpec color.ColorSpec
dimSpec color.ColorSpec
@@ -473,7 +473,7 @@ func (c *mapRenderCtx) nodeSpec(roomID int) color.ColorSpec {
if roomID == c.currentRoom {
return c.atSpec
}
- if c.visited != nil && !c.visited[roomID] {
+ if c.visited != nil && !c.visited.Has(roomID) {
return c.dimSpec
}
_, spec := roomMapSymbol(c.g, c.sess, roomID, false)
@@ -548,7 +548,7 @@ func (c *mapRenderCtx) isCourseLink(roomA, roomB int) bool {
// courseColoredCell draws a one-way course arrow using the map_course color
// (dimmed if either endpoint is unvisited).
func (c *mapRenderCtx) courseColoredCell(roomA, roomB int, glyph rune) (mapCell, bool) {
- if c.visited != nil && (!c.visited[roomA] || !c.visited[roomB]) {
+ if c.visited != nil && (!c.visited.Has(roomA) || !c.visited.Has(roomB)) {
return mapCell{char: glyph, spec: c.dimSpec}, true
}
return mapCell{char: glyph, spec: c.courseSpec}, true
@@ -557,7 +557,7 @@ func (c *mapRenderCtx) courseColoredCell(roomA, roomB int, glyph rune) (mapCell,
// coloredCell applies the shared link coloring logic for bar/arrow glyphs
// (dim if either endpoint is unvisited, otherwise the gradient average).
func (c *mapRenderCtx) coloredCell(roomA, roomB int, glyph rune) (mapCell, bool) {
- if c.visited != nil && (!c.visited[roomA] || !c.visited[roomB]) {
+ if c.visited != nil && (!c.visited.Has(roomA) || !c.visited.Has(roomB)) {
return mapCell{char: glyph, spec: c.dimSpec}, true
}
return mapCell{char: glyph, spec: color.Average(c.nodeSpec(roomA), c.nodeSpec(roomB))}, true