package world import "testing" // insertSentinel is the hypothetical new-room ID passed to InsertGridConflicts // during tests. It must be a positive value not used by any real room in the // fixture (BuildGrid skips exits whose target <= 0). const insertSentinel = 9999 func TestInsertGridConflictsCleanNSEW(t *testing.T) { dir := t.TempDir() writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n") writeGridTestRoom(t, dir, 2, "exits:\n west: {room: 1}\n") w := New(dir) if c := InsertGridConflicts(1, East, 2, insertSentinel, loadGridRoom(w)); len(c) != 0 { t.Errorf("clean east insert: expected no conflicts, got %+v", c) } } func TestInsertGridConflictsCleanDiagonal(t *testing.T) { dir := t.TempDir() writeGridTestRoom(t, dir, 1, "exits:\n northeast: {room: 2}\n") writeGridTestRoom(t, dir, 2, "exits:\n southwest: {room: 1}\n") w := New(dir) if c := InsertGridConflicts(1, Northeast, 2, insertSentinel, loadGridRoom(w)); len(c) != 0 { t.Errorf("clean NE insert: expected no conflicts, got %+v", c) } } func TestInsertGridConflictsCleanUpDown(t *testing.T) { dir := t.TempDir() writeGridTestRoom(t, dir, 1, "exits:\n up: {room: 2}\n") writeGridTestRoom(t, dir, 2, "exits:\n down: {room: 1}\n") w := New(dir) if c := InsertGridConflicts(1, Up, 2, insertSentinel, loadGridRoom(w)); len(c) != 0 { t.Errorf("clean up insert: expected no conflicts, got %+v", c) } } // TestInsertGridConflictsOverlap: inserting on 1→east→2 would push room 3 // (beyond 2 to the east) from (2,0,0) to (3,0,0); a separate room 4 already at // (3,0,0) via 1→north→5→east→4 collides with the pushed 3. // // 1 east→2 east→3 (3 at (2,0,0), pushed to (3,0,0)) // 1 north→5 east→4 (4 at (1,-1,0)? no: 5 at (0,-1,0), 4 at (1,-1,0)) // // To land 4 at (3,0,0) we use 1→east is the insert axis, so place the blocker // via a longer chain that resolves to (3,0,0): 1→north→5→east→6→east→7 lands // 7 at (2,-1,0), not (3,0,0). Instead use a clean ring: 1→east→2 is the axis, // and put 4 at (2,0,0) (3's current spot) — no, 3 is there. // // Simplest reliable overlap: 1→east→2→east→3 and 1→south→6→east→7→north→3 is // a twist (3 reachable two ways). For an *overlap* on push, the pushed 3 must // collide with a room NOT in the beyond-set. Place room 8 at (3,0,0) via a // path that does not pass through 2: 1→north→5→north→8? that is (0,-2,0). // // Correct geometry for an overlap: 1 east→2 east→3 (3 at (2,0,0)). Insert on // 1→east pushes 2→(2,0,0)? No — insert pushes the *beyond* set (rooms beyond // the inserted room), i.e. 2 and everything reachable from 2 without going // back through 1. Inserting between 1 and 2 pushes 2 (and 3) east by one: // 2→(2,0,0), 3→(3,0,0). So we need a room already at (3,0,0) reachable from 1 // without using 1→east. 1→south→4→east→5→east→6 lands 6 at (2,1,0). Not it. // 1→south→4→east→5→north→6 lands 6 at (1,0,0)? 4 at (0,1,0), 5 at (1,1,0), // 6 at (1,0,0) — that's where 2 currently is → overlap with 2 after push? 2 // pushes to (2,0,0), 6 stays at (1,0,0): no collision. We need (3,0,0). // 1→south→4→east→5→north→6→east→7: 4(0,1,0) 5(1,1,0) 6(1,0,0) 7(2,0,0) = // collides with 3's *current* (2,0,0) → that's a pre-existing overlap (invalid // world), not what we want. // // Use a longer chain to (3,0,0): 1→south→4(0,1,0)→east→5(1,1,0)→east→6(2,1,0) // →north→7(2,0,0) collides with 3. So reach (3,0,0): 1→s→4→e→5→e→6→e→7(3,1,0) // →n→8(3,0,0). Then pushing 3 to (3,0,0) collides with 8. 8 is not in the // beyond-set (reachable from 1 via south, not via east/2), so it's an overlap. func TestInsertGridConflictsOverlap(t *testing.T) { dir := t.TempDir() writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n south: {room: 4}\n") writeGridTestRoom(t, dir, 2, "exits:\n east: {room: 3}\n west: {room: 1}\n") writeGridTestRoom(t, dir, 3, "exits:\n west: {room: 2}\n") writeGridTestRoom(t, dir, 4, "exits:\n east: {room: 5}\n north: {room: 1}\n") writeGridTestRoom(t, dir, 5, "exits:\n east: {room: 6}\n west: {room: 4}\n") writeGridTestRoom(t, dir, 6, "exits:\n east: {room: 7}\n west: {room: 5}\n") writeGridTestRoom(t, dir, 7, "exits:\n north: {room: 8}\n west: {room: 6}\n") writeGridTestRoom(t, dir, 8, "exits:\n south: {room: 7}\n") w := New(dir) // Sanity: the pre-edit world must be clean. if c := BuildGridConflicts(1, loadGridRoom(w)); len(c) != 0 { t.Fatalf("precondition: world should be clean, got %+v", c) } c := InsertGridConflicts(1, East, 2, insertSentinel, loadGridRoom(w)) if !hasConflictKind(c, "overlap") { t.Errorf("expected overlap from pushing 3 onto 8's cell, got %+v", c) } } // TestInsertGridConflictsTwist: room 3 beyond 2 is also reachable from 1 via a // separate path, so after the push 3 would have two candidate positions. // // 1 east→2 east→3 (3 at (2,0,0), pushed to (3,0,0)) // 1 south→4 east→5 north→3 (3 at (1,0,0)) // // 3 is reachable two ways already → the pre-edit world is itself a twist. The // insert helper must surface a twist conflict. func TestInsertGridConflictsTwist(t *testing.T) { dir := t.TempDir() writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n south: {room: 4}\n") writeGridTestRoom(t, dir, 2, "exits:\n east: {room: 3}\n west: {room: 1}\n") writeGridTestRoom(t, dir, 3, "exits:\n west: {room: 2}\n south: {room: 5}\n") writeGridTestRoom(t, dir, 4, "exits:\n east: {room: 5}\n north: {room: 1}\n") writeGridTestRoom(t, dir, 5, "exits:\n north: {room: 3}\n west: {room: 4}\n") w := New(dir) c := InsertGridConflicts(1, East, 2, insertSentinel, loadGridRoom(w)) if !hasConflictKind(c, "twist") { t.Errorf("expected a twist conflict, got %+v", c) } } // TestInsertGridConflictsOneWayFarReciprocal: when the far room's opposite // exit does NOT point back at the source, insert performs a one-way insertion // (only the near side is rewired). The helper must model that and still allow a // geometrically clean insert. func TestInsertGridConflictsOneWayFarReciprocal(t *testing.T) { dir := t.TempDir() writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n") writeGridTestRoom(t, dir, 2, "exits:\n") // no west exit back to 1 w := New(dir) if c := InsertGridConflicts(1, East, 2, insertSentinel, loadGridRoom(w)); len(c) != 0 { t.Errorf("one-way insert should be clean, got %+v", c) } } func TestRemoveGridConflictsCleanPull(t *testing.T) { dir := t.TempDir() // 1 east→2 east→3, with reciprocals. Removing 2 pulls 3 to (1,0,0). Clean. writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n") writeGridTestRoom(t, dir, 2, "exits:\n east: {room: 3}\n west: {room: 1}\n") writeGridTestRoom(t, dir, 3, "exits:\n west: {room: 2}\n") w := New(dir) if c := RemoveGridConflicts(1, East, loadGridRoom(w)); len(c) != 0 { t.Errorf("clean pull should produce no conflicts, got %+v", c) } } func TestRemoveGridConflictsDiagonalPull(t *testing.T) { dir := t.TempDir() writeGridTestRoom(t, dir, 1, "exits:\n northeast: {room: 2}\n") writeGridTestRoom(t, dir, 2, "exits:\n northeast: {room: 3}\n southwest: {room: 1}\n") writeGridTestRoom(t, dir, 3, "exits:\n southwest: {room: 2}\n") w := New(dir) if c := RemoveGridConflicts(1, Northeast, loadGridRoom(w)); len(c) != 0 { t.Errorf("clean diagonal pull should produce no conflicts, got %+v", c) } } // TestRemoveGridConflictsOverlap mirrors TestBuildGridConflictsHypotheticalRemoveOverlap: // removing 2 pulls 6 onto 5's cell. func TestRemoveGridConflictsOverlap(t *testing.T) { dir := t.TempDir() writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n south: {room: 4}\n") writeGridTestRoom(t, dir, 2, "exits:\n east: {room: 3}\n west: {room: 1}\n") writeGridTestRoom(t, dir, 3, "exits:\n south: {room: 6}\n west: {room: 2}\n") writeGridTestRoom(t, dir, 4, "exits:\n east: {room: 5}\n north: {room: 1}\n") writeGridTestRoom(t, dir, 5, "exits:\n west: {room: 4}\n") writeGridTestRoom(t, dir, 6, "exits:\n north: {room: 3}\n") w := New(dir) if c := BuildGridConflicts(1, loadGridRoom(w)); len(c) != 0 { t.Fatalf("precondition: world should be clean, got %+v", c) } c := RemoveGridConflicts(1, East, loadGridRoom(w)) if !hasConflictKind(c, "overlap") { t.Errorf("expected overlap from pulling 6 onto 5's cell, got %+v", c) } } // TestRemoveGridConflictsDeadEnd: when the room being removed has no forward // exit, the helper models a plain deletion (A's dir exit removed). In a clean // world this cannot introduce a conflict. func TestRemoveGridConflictsDeadEnd(t *testing.T) { dir := t.TempDir() writeGridTestRoom(t, dir, 1, "exits:\n east: {room: 2}\n") writeGridTestRoom(t, dir, 2, "exits:\n west: {room: 1}\n") w := New(dir) if c := RemoveGridConflicts(1, East, loadGridRoom(w)); len(c) != 0 { t.Errorf("dead-end removal should produce no conflicts, got %+v", c) } }