202 lines
4.2 KiB
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
|
|
}
|