|
| 1 | +package main |
| 2 | + |
| 3 | +import "fmt" |
| 4 | + |
| 5 | +func main() { |
| 6 | + m, moves, robot := parseInput() |
| 7 | + m, robot = grow(m, robot) |
| 8 | + for _, move := range moves { |
| 9 | + robot = apply(m, move, robot) |
| 10 | + } |
| 11 | + fmt.Println(gps(m, '[')) |
| 12 | +} |
| 13 | + |
| 14 | +func grow(m map[P]byte, robot P) (map[P]byte, P) { |
| 15 | + newM := make(map[P]byte, len(m)*2) |
| 16 | + for i := 0; i < Height; i++ { |
| 17 | + for j := 0; j < Width; j++ { |
| 18 | + p := P{i, j} |
| 19 | + switch m[p] { |
| 20 | + case '#': |
| 21 | + newM[P{p.x, 2 * p.y}] = '#' |
| 22 | + newM[P{p.x, 2*p.y + 1}] = '#' |
| 23 | + case 'O': |
| 24 | + newM[P{p.x, 2 * p.y}] = '[' |
| 25 | + newM[P{p.x, 2*p.y + 1}] = ']' |
| 26 | + case '.': |
| 27 | + newM[P{p.x, 2 * p.y}] = '.' |
| 28 | + newM[P{p.x, 2*p.y + 1}] = '.' |
| 29 | + case '@': |
| 30 | + newM[P{p.x, 2 * p.y}] = '@' |
| 31 | + newM[P{p.x, 2*p.y + 1}] = '.' |
| 32 | + } |
| 33 | + } |
| 34 | + } |
| 35 | + Width *= 2 |
| 36 | + return newM, P{robot.x, 2 * robot.y} |
| 37 | +} |
| 38 | + |
| 39 | +func apply(m map[P]byte, move byte, robot P) P { |
| 40 | + delta := getDelta(move) |
| 41 | + |
| 42 | + nextEmpty, err := findNextEmpty(m, robot, delta) |
| 43 | + if err != nil { |
| 44 | + return robot |
| 45 | + } |
| 46 | + |
| 47 | + if move == '<' || move == '>' { |
| 48 | + for curr := nextEmpty; curr != robot; { |
| 49 | + closest := P{curr.x, curr.y - delta.y} |
| 50 | + m[curr], m[closest] = m[closest], m[curr] |
| 51 | + curr = closest |
| 52 | + } |
| 53 | + return P{robot.x, robot.y + delta.y} |
| 54 | + } |
| 55 | + |
| 56 | + if move == '^' || move == 'v' { |
| 57 | + affected, maxLevel, err := affectedVertically(m, robot, delta.x) |
| 58 | + if err != nil { |
| 59 | + return robot |
| 60 | + } |
| 61 | + for x := maxLevel; x != robot.x; x -= delta.x { |
| 62 | + for col := range affected[x] { |
| 63 | + m[P{x + delta.x, col}], m[P{x, col}] = m[P{x, col}], m[P{x + delta.x, col}] |
| 64 | + } |
| 65 | + } |
| 66 | + |
| 67 | + return P{robot.x + delta.x, robot.y} |
| 68 | + } |
| 69 | + |
| 70 | + panic("unreachable") |
| 71 | +} |
| 72 | + |
| 73 | +func affectedVertically(m map[P]byte, robot P, deltaX int) (map[int]map[int]struct{}, int, error) { |
| 74 | + affected := map[int]map[int]struct{}{ |
| 75 | + robot.x: {robot.y: {}}, |
| 76 | + } |
| 77 | + |
| 78 | + for currX := robot.x; ; currX += deltaX { |
| 79 | + newCols, err := newColumns(m, currX+deltaX, affected[currX]) |
| 80 | + if err != nil { |
| 81 | + return nil, 0, err |
| 82 | + } |
| 83 | + |
| 84 | + if len(newCols) == 0 { |
| 85 | + return affected, currX, nil |
| 86 | + } |
| 87 | + |
| 88 | + affected[currX+deltaX] = newCols |
| 89 | + } |
| 90 | +} |
| 91 | + |
| 92 | +func newColumns(m map[P]byte, nextX int, columns map[int]struct{}) (map[int]struct{}, error) { |
| 93 | + newCols := map[int]struct{}{} |
| 94 | + for col := range columns { |
| 95 | + switch m[P{nextX, col}] { |
| 96 | + case '#': |
| 97 | + return nil, NotFound |
| 98 | + case '[': |
| 99 | + newCols[col] = struct{}{} |
| 100 | + newCols[col+1] = struct{}{} |
| 101 | + case ']': |
| 102 | + newCols[col] = struct{}{} |
| 103 | + newCols[col-1] = struct{}{} |
| 104 | + } |
| 105 | + } |
| 106 | + return newCols, nil |
| 107 | +} |
0 commit comments