advent-of-code/aoc2023/day14/main.go

159 lines
2.5 KiB
Go
Raw Permalink Normal View History

2023-12-15 07:52:37 -07:00
package main
import (
"bufio"
_ "embed"
"fmt"
2024-12-01 11:37:27 -07:00
"slices"
2023-12-15 07:52:37 -07:00
"strings"
2023-12-15 15:13:24 -07:00
aoc "go.sour.is/advent-of-code"
2023-12-15 15:09:59 -07:00
"golang.org/x/exp/maps"
2023-12-15 07:52:37 -07:00
)
// var log = aoc.Log
func main() { aoc.MustResult(aoc.Runner(run)) }
type result struct {
valuePT1 int
valuePT2 int
}
func (r result) String() string { return fmt.Sprintf("%#v", r) }
func run(scan *bufio.Scanner) (*result, error) {
2023-12-15 15:09:59 -07:00
var maplist []Map
2023-12-15 07:52:37 -07:00
var m Map
for scan.Scan() {
text := scan.Text()
if len(text) == 0 {
2023-12-15 15:09:59 -07:00
maplist = append(maplist, m)
2023-12-15 07:52:37 -07:00
m = Map{}
}
m = append(m, []rune(text))
}
2023-12-15 15:09:59 -07:00
maplist = append(maplist, m)
2023-12-15 07:52:37 -07:00
score1 := 0
2023-12-15 15:09:59 -07:00
for _, m := range maplist {
2023-12-15 07:52:37 -07:00
m = aoc.Transpose(reverse(m))
m.Sort()
score1 += m.Score()
}
score2 := 0
2023-12-15 15:09:59 -07:00
type record [5]int
var current record
memo := make(map[record]int)
2023-12-15 07:52:37 -07:00
2023-12-15 15:09:59 -07:00
for _, m := range maplist {
// fmt.Println(m)
2023-12-15 07:52:37 -07:00
2023-12-15 15:09:59 -07:00
m = aoc.Transpose(reverse(m))
2023-12-15 07:52:37 -07:00
2023-12-15 15:09:59 -07:00
for i := 0; i < 1_000_000_000; i++ {
m, current = cycle(m)
2023-12-15 07:52:37 -07:00
2023-12-15 15:09:59 -07:00
v, ok := memo[current]
if ok && v > 1 {
counts := aoc.Reduce(
func(i int, v int, counts [3]int) [3]int {
counts[v]++
return counts
2024-12-01 11:37:27 -07:00
}, [3]int{}, slices.Values(maps.Values(memo)))
2023-12-15 07:52:37 -07:00
2023-12-15 15:09:59 -07:00
// fmt.Println(i, counts)
i = 1_000_000_000 - (1_000_000_000-counts[0]-counts[1])%counts[2]
clear(memo)
}
memo[current] += 1
// fmt.Println(i, current, v)
}
score2 += m.Score()
}
2023-12-15 07:52:37 -07:00
return &result{valuePT1: score1, valuePT2: score2}, nil
}
type Map [][]rune
func (m Map) String() string {
var buf strings.Builder
for _, row := range m {
buf.WriteString(string(row))
buf.WriteRune('\n')
}
buf.WriteRune('\n')
return buf.String()
}
func (m *Map) Sort() {
if m == nil {
return
}
for _, row := range *m {
base := 0
for i, r := range row {
if r == '#' {
base = i + 1
continue
}
if r == 'O' {
if base < i {
row[base], row[i] = row[i], row[base]
}
base++
}
}
}
}
func (m *Map) Score() int {
if m == nil {
return 0
}
sum := 0
max := len(*m)
for _, row := range *m {
for i, r := range row {
if r == 'O' {
sum += max - i
}
}
}
return sum
}
func reverse(m Map) Map {
for _, row := range m {
aoc.Reverse(row)
}
return m
}
2023-12-15 15:09:59 -07:00
func cycle(m Map) (Map, [5]int) {
var current [5]int
m.Sort()
current[0] = m.Score()
m = aoc.Transpose(reverse(m))
m.Sort()
current[1] = m.Score()
m = aoc.Transpose(reverse(m))
m.Sort()
current[2] = m.Score()
m = aoc.Transpose(reverse(m))
m.Sort()
current[3] = m.Score()
m = aoc.Transpose(reverse(m))
current[4] = m.Score()
return m, current
}