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