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 }