github.com/mnlphlp/aoc22@v0.0.0-20230330151331-c1dc4bff1b9b/day23/day23.go (about) 1 package day23 2 3 import ( 4 "fmt" 5 "strconv" 6 7 "github.com/mnlphlp/aoc22/day23/grid" 8 "github.com/mnlphlp/aoc22/util" 9 ) 10 11 const ( 12 // weird order copied from task 13 North = iota 14 South 15 West 16 East 17 ) 18 19 func move(elves grid.Grid, rounds int, startDir int, debug bool) (grid.Grid, int) { 20 if debug { 21 fmt.Println(elves) 22 } 23 lastHash := elves.Hash() 24 for i := 0; i < rounds || rounds == 0; i++ { 25 proposed := make(map[util.Pos2]util.Pos2) 26 conflicts := make([]util.Pos2, 0) 27 elves.ForEach(func(p util.Pos2) { 28 if !elves.HasNeighbor(p) { 29 return 30 } 31 next, nextFound := elves.NextPos(p, startDir) 32 if nextFound { 33 if _, conflict := proposed[next]; conflict { 34 // do not move and mark other move for deletion 35 conflicts = append(conflicts, next) 36 } else { 37 proposed[next] = p 38 } 39 } 40 }) 41 for _, conflict := range conflicts { 42 delete(proposed, conflict) 43 } 44 for _, old := range proposed { 45 elves = elves.Remove(old) 46 } 47 for new := range proposed { 48 elves = elves.Insert(new) 49 } 50 if debug { 51 fmt.Printf("Round %d: %d\n", i+1, countEmpty(elves)) 52 fmt.Println(elves) 53 } 54 startDir = (startDir + 1) % 4 55 hash := elves.Hash() 56 if hash.Equals(lastHash) && rounds == 0 { 57 return elves, i + 1 58 } 59 lastHash = hash 60 } 61 return elves, rounds 62 } 63 64 func countEmpty(g grid.Grid) int { 65 min, max := util.Pos2{X: 1 << 62, Y: 1 << 62}, util.Pos2{X: -(1 << 62), Y: -(1 << 62)} 66 count := 0 67 g.ForEach(func(p util.Pos2) { 68 min = util.Pos2{X: util.Min(min.X, p.X), Y: util.Min(min.Y, p.Y)} 69 max = util.Pos2{X: util.Max(max.X, p.X), Y: util.Max(max.Y, p.Y)} 70 count++ 71 }) 72 return ((max.X - min.X + 1) * (max.Y - min.Y + 1)) - count 73 } 74 75 func part1(grid grid.Grid, debug bool) int { 76 grid, _ = move(grid, 10, North, debug) 77 return countEmpty(grid) 78 } 79 80 func part2(grid grid.Grid, startDir int, debug bool) int { 81 _, lastMove := move(grid, 0, startDir, debug) 82 return lastMove 83 } 84 85 func Solve(input string, debug bool, task int) (string, string) { 86 res1, res2 := 0, 0 87 g := grid.ParseInput(input) 88 if task != 2 { 89 res1 = part1(g, debug) 90 } 91 if task != 1 { 92 // if part one already ran continue from that state 93 startDir := North 94 if task == 0 { 95 startDir = (startDir + 10) % 4 96 res2 = 10 97 } 98 res2 += part2(g, startDir, debug) 99 } 100 if grid.TIMING_ACTIVE { 101 fmt.Println("canMove: ", grid.Timing.CanMove) 102 fmt.Println("contains: ", grid.Timing.Contains) 103 fmt.Println("hash: ", grid.Timing.Hash) 104 fmt.Println("insert: ", grid.Timing.Insert) 105 fmt.Println("nextMove: ", grid.Timing.NextMove) 106 fmt.Println("remove: ", grid.Timing.Remove) 107 } 108 109 return strconv.Itoa(res1), strconv.Itoa(res2) 110 }