Files
advent-of-gode/2023/14/code.go
2023-12-14 08:33:30 +02:00

186 lines
3.7 KiB
Go

package main
import (
"strings"
"github.com/jpillora/puzzler/harness/aoc"
)
func main() {
aoc.Harness(run)
}
// on code change, run will be executed 4 times:
// 1. with: false (part1), and example input
// 2. with: true (part2), and example input
// 3. with: false (part1), and user input
// 4. with: true (part2), and user input
// the return value of each run is printed to stdout
func run(part2 bool, input string) any {
// when you're ready to do part 2, remove this "not implemented" block
grid := make([][]rune, 0)
for _, l := range strings.Split(input, "\n") {
if l == "" {
continue
}
gridLine := make([]rune, 0)
for _, r := range strings.Split(l, "") {
gridLine = append(gridLine, rune(r[0]))
}
grid = append(grid, gridLine)
}
if part2 {
matchMap := make(map[string]int)
cycleVal := make(map[int]int)
cycleStart := -1
cycleEnd := -1
for i := 1; i <= 1000000000; i++ {
grid = spin(grid)
gridStr := gridString(grid)
if at, ok := matchMap[gridStr]; ok {
cycleVal[at] = northLoad(grid)
if cycleStart == -1 {
cycleStart = at
} else if at > cycleStart {
cycleEnd = at
} else {
// Found our full cycle, break
break
}
} else {
matchMap[gridStr] = i
}
}
cycleLen := cycleEnd - cycleStart + 1
// calculate which cycle will be the 1000000000th
cycle := cycleStart + (1000000000-cycleStart)%cycleLen
return cycleVal[cycle]
}
grid = tilt(grid, 'N')
return northLoad(grid)
}
func northLoad(grid [][]rune) int {
load := 0
distToS := len(grid)
for v := 0; v < len(grid); v++ {
for h := 0; h < len(grid[v]); h++ {
if grid[v][h] == 'O' {
load += (distToS - v)
}
}
}
return load
}
func gridString(grid [][]rune) string {
s := ""
for v := 0; v < len(grid); v++ {
for h := 0; h < len(grid[v]); h++ {
s += string(grid[v][h])
}
}
return s
}
func spin(grid [][]rune) [][]rune {
grid = tilt(grid, 'N')
grid = tilt(grid, 'W')
grid = tilt(grid, 'S')
grid = tilt(grid, 'E')
return grid
}
func tilt(grid [][]rune, dir rune) [][]rune {
if dir == 'N' {
for v := 0; v < len(grid); v++ {
for h := 0; h < len(grid[v]); h++ {
if grid[v][h] == 'O' {
// Move up as far as possible:
rollingN:
for mv := v - 1; mv >= 0; mv-- {
if grid[mv][h] == '.' {
// swap and continue
grid[mv][h] = 'O'
grid[mv+1][h] = '.'
} else {
break rollingN
}
}
}
}
}
return grid
} else if dir == 'S' {
for v := len(grid) - 1; v >= 0; v-- {
for h := 0; h < len(grid[v]); h++ {
if grid[v][h] == 'O' {
// Move down as far as possible:
rollingS:
for mv := v + 1; mv < len(grid); mv++ {
if grid[mv][h] == '.' {
// swap and continue
grid[mv][h] = 'O'
grid[mv-1][h] = '.'
} else {
break rollingS
}
}
}
}
}
return grid
} else if dir == 'E' {
for h := len(grid[0]) - 1; h >= 0; h-- {
for v := 0; v < len(grid); v++ {
if grid[v][h] == 'O' {
// Move right as far as possible:
rollingE:
for mh := h + 1; mh < len(grid); mh++ {
if grid[v][mh] == '.' {
// swap and continue
grid[v][mh] = 'O'
grid[v][mh-1] = '.'
} else {
break rollingE
}
}
}
}
}
return grid
} else if dir == 'W' {
for h := 0; h < len(grid[0]); h++ {
for v := 0; v < len(grid); v++ {
if grid[v][h] == 'O' {
// Move right as far as possible:
rollingW:
for mh := h - 1; mh >= 0; mh-- {
if grid[v][mh] == '.' {
// swap and continue
grid[v][mh] = 'O'
grid[v][mh+1] = '.'
} else {
break rollingW
}
}
}
}
}
return grid
}
panic("Bad direction")
}