adventofcode/2022/day23/main.go

202 lines
4.2 KiB
Go

package main
import (
"fmt"
"math"
"sort"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
func main() {
inp := h.StdinToStringSlice()
part1(inp)
part2(inp)
}
func part1(inp []string) {
field := plotElves(inp)
for i := 0; i < 10; i++ {
proposals := buildProposals(field, i)
for k, v := range proposals {
delete(field, v)
field[k] = true
}
}
fmt.Println("# Part 1")
fmt.Println("Empty Tiles:", countEmpties(field))
}
func part2(inp []string) {
field := plotElves(inp)
var lastHash string
for i := 0; i < 100000000; i++ {
proposals := buildProposals(field, i)
for k, v := range proposals {
delete(field, v)
field[k] = true
}
currHash := fieldHash(field)
if currHash == lastHash {
fmt.Println("# Part 2")
fmt.Println("Stable on round", i+1)
return
}
lastHash = currHash
}
fmt.Println("# Part 2")
fmt.Println("No solution found.")
}
func fieldHash(field map[h.Coordinate]bool) string {
var sorted []h.Coordinate
for k := range field {
sorted = append(sorted, k)
}
sort.Slice(sorted, func(i, j int) bool {
if sorted[i].X == sorted[j].X {
return sorted[i].Y > sorted[j].Y
}
return sorted[i].X > sorted[j].X
})
return fmt.Sprintf("%v", sorted)
}
func countEmpties(field map[h.Coordinate]bool) int {
maxX, minX := math.MinInt, math.MaxInt
maxY, minY := math.MinInt, math.MaxInt
for k := range field {
maxX = h.Max(maxX, k.X)
minX = h.Min(minX, k.X)
maxY = h.Max(maxY, k.Y)
minY = h.Min(minY, k.Y)
}
var ret int
for y := minY; y <= maxY; y++ {
for x := minX; x <= maxX; x++ {
if _, ok := field[h.Coordinate{X: x, Y: y}]; !ok {
ret++
}
}
}
return ret
}
func printField(field map[h.Coordinate]bool) {
maxX, minX := math.MinInt, 0
maxY, minY := math.MinInt, 0
for k := range field {
maxX = h.Max(maxX, k.X)
minX = h.Min(minX, k.X)
maxY = h.Max(maxY, k.Y)
minY = h.Min(minY, k.Y)
}
maxX = maxX + 2
maxY = maxY + 2
for y := minY; y <= maxY; y++ {
for x := minX; x <= maxX; x++ {
if _, ok := field[h.Coordinate{X: x, Y: y}]; ok {
fmt.Print("#")
} else {
fmt.Print(".")
}
}
fmt.Println()
}
}
func plotElves(inp []string) map[h.Coordinate]bool {
field := make(map[h.Coordinate]bool)
for y := range inp {
for x := range inp[y] {
if inp[y][x] == '#' {
field[h.Coordinate{X: x, Y: y}] = true
}
}
}
return field
}
func buildProposals(field map[h.Coordinate]bool, round int) map[h.Coordinate]h.Coordinate {
props := make(map[h.Coordinate]h.Coordinate)
var errProps []h.Coordinate
for k := range field {
var neighbors []h.Coordinate
for _, n := range k.GetAllNeighbors() {
if _, ok := field[n]; ok {
neighbors = append(neighbors, n)
}
}
if len(neighbors) == 0 {
continue
}
var hasNorth, hasEast, hasSouth, hasWest bool
for _, n := range neighbors {
if n.Y < k.Y {
hasNorth = true
}
if n.Y > k.Y {
hasSouth = true
}
if n.X < k.X {
hasWest = true
}
if n.X > k.X {
hasEast = true
}
}
addProp := func(c h.Coordinate) {
if _, ok := props[c]; ok {
errProps = append(errProps, c)
} else {
props[c] = k
}
}
testNorth := func(c h.Coordinate) bool {
if !hasNorth {
addProp(k.North())
return true
}
return false
}
testSouth := func(c h.Coordinate) bool {
if !hasSouth {
addProp(k.South())
return true
}
return false
}
testWest := func(c h.Coordinate) bool {
if !hasWest {
addProp(k.West())
return true
}
return false
}
testEast := func(c h.Coordinate) bool {
if !hasEast {
addProp(k.East())
return true
}
return false
}
findProposal := func(c h.Coordinate, tests ...func(h.Coordinate) bool) {
for i := range tests {
if tests[i](c) == true {
return
}
}
}
switch round % 4 {
case 0: // North First
findProposal(k, testNorth, testSouth, testWest, testEast)
case 1: // South First
findProposal(k, testSouth, testWest, testEast, testNorth)
case 2: // West First
findProposal(k, testWest, testEast, testNorth, testSouth)
case 3: // East First
findProposal(k, testEast, testNorth, testSouth, testWest)
}
}
// Now remove all conflicts
for i := range errProps {
delete(props, errProps[i])
}
return props
}