@@ -3,6 +3,9 @@ while let line = readLine() {
3
3
grid. append ( items ( line) )
4
4
}
5
5
6
+ let ny = grid. count
7
+ let nx = grid. first? . count ?? 0
8
+
6
9
var f = energized ( by: Beam ( x: 0 , y: 0 , d: . r) )
7
10
var m = edges ( ) . map ( { energized ( by: $0) } ) . max ( ) ?? 0
8
11
print ( f, m)
@@ -14,7 +17,7 @@ enum Item: Character {
14
17
func items( _ s: String ) -> [ Item ] { s. compactMap { Item ( rawValue: $0) } }
15
18
func item( at beam: Beam ) -> Item { grid [ beam. y] [ beam. x] }
16
19
17
- enum Direction { case l, r, u, d }
20
+ enum Direction : Int { case l, r, u, d }
18
21
19
22
struct Beam : Hashable {
20
23
let x , y : Int
@@ -46,20 +49,40 @@ struct Beam: Hashable {
46
49
var reflectD : Beam { Beam ( x: x, y: y + 1 , d: . d) }
47
50
}
48
51
52
+ typealias Visited = [ [ Bool ] ]
53
+
49
54
func energized( by beam: Beam ) -> Int {
50
- var visited = Set < Beam > ( )
55
+ // It is much faster to use 4 arrays (one for each direction) to keep track
56
+ // of visited beams instead of a Set<Beam>().
57
+ var visited : [ Visited ] = Array (
58
+ repeating: Array ( repeating: Array ( repeating: false , count: nx) , count: ny) ,
59
+ count: 4 )
60
+
51
61
trace ( beam: beam, visited: & visited)
52
- return Set ( visited. map ( { [ $0. x, $0. y] } ) ) . count
62
+
63
+ var count = 0
64
+ for y in 0 ..< ny {
65
+ for x in 0 ..< nx {
66
+ for d in 0 ..< 4 {
67
+ if visited [ d] [ y] [ x] {
68
+ count += 1
69
+ break
70
+ }
71
+ }
72
+ }
73
+ }
74
+ return count
53
75
}
54
76
55
- func trace( beam: Beam , visited: inout Set < Beam > ) {
77
+ func trace( beam: Beam , visited: inout [ Visited ] ) {
56
78
var ( beam, bt) = ( beam, beam)
57
79
var next : [ Beam ] = [ ]
58
80
59
81
while isInBounds ( beam) {
60
- if ! visited. insert ( beam) . inserted {
82
+ if visited [ beam . d . rawValue ] [ beam. y ] [ beam . x ] {
61
83
break
62
84
}
85
+ visited [ beam. d. rawValue] [ beam. y] [ beam. x] = true
63
86
64
87
switch item ( at: beam) {
65
88
case . vbar where beam. isHorizontal:
@@ -93,13 +116,10 @@ func trace(beam: Beam, visited: inout Set<Beam>) {
93
116
func isInBounds( _ beam: Beam ) -> Bool {
94
117
let x = beam. x
95
118
let y = beam. y
96
- return x >= 0 && x < grid [ 0 ] . count && y >= 0 && y < grid . count
119
+ return x >= 0 && x < nx && y >= 0 && y < ny
97
120
}
98
121
99
122
func edges( ) -> [ Beam ] {
100
- let ny = grid. count
101
- let nx = grid. first? . count ?? 0
102
-
103
123
var result : [ Beam ] = [ ]
104
124
for y in 0 ..< ny {
105
125
result. append ( Beam ( x: 0 , y: y, d: . r) )
0 commit comments