adventofcode/2022/day24/main.go

122 lines
2.8 KiB
Go

package main
import (
"fmt"
"strings"
h "git.bullercodeworks.com/brian/adventofcode/helpers"
)
func main() {
input := h.StdinToStringSlice()
part1(input)
part2(input)
}
func part1(input []string) {
field, blizzards, start, target := parseInput(input)
fmt.Println("# Part 1")
fmt.Println(run(field, blizzards, start, target))
}
func part2(input []string) {
field, blizzards, start, target := parseInput(input)
fmt.Println("# Part 2")
fmt.Println(run(field, blizzards, start, target) +
run(field, blizzards, target, start) +
run(field, blizzards, start, target))
}
type Blizzard struct {
pos, dir, wrap h.Coordinate
}
var (
U = h.Coordinate{X: 0, Y: -1}
D = h.Coordinate{X: 0, Y: 1}
L = h.Coordinate{X: -1, Y: 0}
R = h.Coordinate{X: 1, Y: 0}
)
var directions []h.Coordinate = []h.Coordinate{U, D, L, R}
func parseInput(lines []string) (field [][]rune, blizzards []Blizzard, start, target h.Coordinate) {
start.X = strings.Index(lines[0], "E")
if start.X == -1 {
start.X = strings.Index(lines[0], ".")
}
target.Y = len(lines) - 1
target.X = strings.Index(lines[target.Y], ".")
for _, line := range lines {
line = strings.TrimSpace(line)
field = append(field, []rune(line))
}
for y, row := range field {
for x, c := range row {
switch c {
case '^':
blizzards = append(blizzards, Blizzard{
h.Coordinate{X: x, Y: y}, U, h.Coordinate{X: x, Y: len(field) - 2},
})
case 'v':
blizzards = append(blizzards, Blizzard{
h.Coordinate{X: x, Y: y}, D, h.Coordinate{X: x, Y: 1},
})
case '<':
blizzards = append(blizzards, Blizzard{
h.Coordinate{X: x, Y: y}, L, h.Coordinate{X: len(field[0]) - 2, Y: y},
})
case '>':
blizzards = append(blizzards, Blizzard{
h.Coordinate{X: x, Y: y}, R, h.Coordinate{X: 1, Y: y},
})
}
}
}
return
}
func valid(field [][]rune, pos h.Coordinate) bool {
return pos.X >= 0 && pos.X < len(field[0]) && pos.Y >= 0 && pos.Y < len(field)
}
func run(field [][]rune, blizzards []Blizzard, start, target h.Coordinate) int {
minutes := 0
currentStep := make(map[h.Coordinate]bool)
currentStep[start] = true
for !currentStep[target] {
//update blizzards
whereBlizzards := make(map[h.Coordinate]bool)
for i, b := range blizzards {
bb := b.pos.Add(b.dir)
if valid(field, bb) {
if field[bb.Y][bb.X] == '#' {
blizzards[i].pos = b.wrap
} else {
blizzards[i].pos = bb
}
}
whereBlizzards[blizzards[i].pos] = true
}
//find new steps
newStep := make(map[h.Coordinate]bool)
for pos := range currentStep {
if !(whereBlizzards[pos]) {
newStep[pos] = true
}
for _, d := range directions {
n := pos.Add(d)
if valid(field, n) && field[n.Y][n.X] != '#' && !whereBlizzards[n] {
newStep[n] = true
}
}
}
currentStep = newStep
minutes++
}
return minutes
}