129 lines
2.5 KiB
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
|
||
|
}
|