122 lines
2.8 KiB
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
|
|
}
|