adventofcode/2023/day14/main.go

129 lines
2.5 KiB
Go

package main
import (
"fmt"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
func main() {
inp := h.StdinToStringSlice()
part1(inp)
fmt.Println()
part2(inp)
}
func part1(input []string) {
m := h.StringSliceToCoordByteMap(input)
fmt.Println("# Part 1")
tiltNorth(&m)
fmt.Println(calcLoad(&m))
}
func part2(input []string) {
target := 1_000_000_000
mapCache := make(map[string]int)
m := h.StringSliceToCoordByteMap(input)
var i = 0
var ignoreCache bool
for ; i <= target; i++ {
tiltNorth(&m)
tiltWest(&m)
tiltSouth(&m)
tiltEast(&m)
if !ignoreCache {
if v, ok := mapCache[m.String()]; ok && i > 200 {
target = i + (target-v)%(i-v) - 1
ignoreCache = true
}
mapCache[m.String()] = i
}
}
fmt.Println("# Part 2")
fmt.Println(calcLoad(&m))
}
func c(x, y int) h.Coordinate { return h.Coordinate{X: x, Y: y} }
// m.FindAll returns a slice sorted Left->Right, Top->Bottom
func tiltNorth(m *h.CoordByteMap) {
rocks := m.FindAll('O')
for i := range rocks {
if rocks[i].Y == m.TLY {
continue
}
mv := h.Coordinate{X: rocks[i].X, Y: rocks[i].Y}
for m.Get(mv.North()) == '.' {
mv.MoveNorth()
}
if !mv.Equals(rocks[i]) {
m.Put(rocks[i], '.')
m.Put(mv, 'O')
}
}
}
func tiltEast(m *h.CoordByteMap) {
rocks := m.FindAll('O')
for i, j := 0, len(rocks)-1; i < j; i, j = i+1, j-1 {
rocks[i], rocks[j] = rocks[j], rocks[i]
}
for i := range rocks {
if rocks[i].X == m.BRX {
continue
}
mv := h.Coordinate{X: rocks[i].X, Y: rocks[i].Y}
for m.Get(mv.East()) == '.' {
mv.MoveEast()
}
if !mv.Equals(rocks[i]) {
m.Put(rocks[i], '.')
m.Put(mv, 'O')
}
}
}
func tiltSouth(m *h.CoordByteMap) {
rocks := m.FindAll('O')
for i, j := 0, len(rocks)-1; i < j; i, j = i+1, j-1 {
rocks[i], rocks[j] = rocks[j], rocks[i]
}
for i := range rocks {
if rocks[i].Y == m.BRY {
continue
}
mv := h.Coordinate{X: rocks[i].X, Y: rocks[i].Y}
for m.Get(mv.South()) == '.' {
mv.MoveSouth()
}
if !mv.Equals(rocks[i]) {
m.Put(rocks[i], '.')
m.Put(mv, 'O')
}
}
}
func tiltWest(m *h.CoordByteMap) {
rocks := m.FindAll('O')
for i := range rocks {
if rocks[i].X == m.TLX {
continue
}
mv := h.Coordinate{X: rocks[i].X, Y: rocks[i].Y}
for m.Get(mv.West()) == '.' {
mv.MoveWest()
}
if !mv.Equals(rocks[i]) {
m.Put(rocks[i], '.')
m.Put(mv, 'O')
}
}
}
func calcLoad(m *h.CoordByteMap) int {
var res int
bot := m.BRY
rocks := m.FindAll('O')
for i := range rocks {
res += (bot - rocks[i].Y) + 1
}
return res
}