From f8c30a229d3da1e998fe0a0b552093f07adda3b1 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Mon, 16 Feb 2026 14:04:16 -0800 Subject: [PATCH] Fix solver nondeterminism from map iteration order --- solver/solver.go | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/solver/solver.go b/solver/solver.go index b372ec3..026b79c 100644 --- a/solver/solver.go +++ b/solver/solver.go @@ -141,7 +141,12 @@ func newSolverState(n int, roomSizes []int, pnMultiple, npCost int, constraints for _, members := range s.groups { s.groupList = append(s.groupList, members) } - slices.SortFunc(s.groupList, func(a, b []int) int { return len(b) - len(a) }) + slices.SortFunc(s.groupList, func(a, b []int) int { + if len(b) != len(a) { + return len(b) - len(a) + } + return a[0] - b[0] + }) s.uniqueGroups = make([]int, 0, len(s.groups)) for root := range s.groups { @@ -165,6 +170,9 @@ func newSolverState(n int, roomSizes []int, pnMultiple, npCost int, constraints s.mustApartFor[p[0]] = append(s.mustApartFor[p[0]], p[1]) s.mustApartFor[p[1]] = append(s.mustApartFor[p[1]], p[0]) } + for i := range s.mustApartFor { + slices.Sort(s.mustApartFor[i]) + } return s } @@ -469,15 +477,8 @@ func (s *solverState) initialPlacement(assignment []int) bool { } ok := true for _, member := range grp { - for p := range s.mustApart { - partner := -1 - if p[0] == member { - partner = p[1] - } - if p[1] == member { - partner = p[0] - } - if partner >= 0 && assignment[partner] == room { + for _, partner := range s.mustApartFor[member] { + if assignment[partner] == room { alreadyPlaced := false for gj := range gi { if slices.Contains(s.groupList[gj], partner) { @@ -526,15 +527,8 @@ func (s *solverState) randomPlacement(assignment []int, rng *rand.Rand) bool { } valid := true for _, member := range grp { - for p := range s.mustApart { - partner := -1 - if p[0] == member { - partner = p[1] - } - if p[1] == member { - partner = p[0] - } - if partner >= 0 && assignment[partner] == room { + for _, partner := range s.mustApartFor[member] { + if assignment[partner] == room { valid = false break }