@@ -7,33 +7,66 @@ class Day18(input: String, private val size: Int = 70) {
7
7
x to y
8
8
}.toList()
9
9
10
- private fun findPath ( obstacles : Iterable < IntPair > ): Set < IntPair > ? {
11
- val visited = obstacles. toMutableSet()
12
- val queue = ArrayDeque <Node >()
13
- queue.add(Node (0 , 0 ))
10
+ fun part1 ( limit : Int = 1024 ): Int ? {
11
+ val visited = coords.subList( 0 , limit). toMutableSet(). apply { add( 0 to 0 ) }
12
+ val queue = ArrayDeque <IndexedValue < IntPair > >()
13
+ queue.add(IndexedValue (0 , 0 to 0 ))
14
14
while (queue.isNotEmpty()) {
15
- val node = queue.removeFirst()
16
- val (x, y) = node
17
- if (x == size && y == size) return generateSequence(node) { it.next }.map { it.x to it.y }.toSet()
18
- if (! visited.add(x to y)) continue
19
- if (x > 0 ) queue.addLast(Node (x - 1 , y, node))
20
- if (y > 0 ) queue.addLast(Node (x, y - 1 , node))
21
- if (y < size) queue.addLast(Node (x, y + 1 , node))
22
- if (x < size) queue.addLast(Node (x + 1 , y, node))
15
+ val (t, pos) = queue.removeFirst()
16
+ val (x, y) = pos
17
+ if (x == size && y == size) return t
18
+ if (x > 0 ) (x - 1 to y).let { if (visited.add(it)) queue.addLast(IndexedValue (t + 1 , it)) }
19
+ if (y > 0 ) (x to y - 1 ).let { if (visited.add(it)) queue.addLast(IndexedValue (t + 1 , it)) }
20
+ if (y < size) (x to y + 1 ).let { if (visited.add(it)) queue.addLast(IndexedValue (t + 1 , it)) }
21
+ if (x < size) (x + 1 to y).let { if (visited.add(it)) queue.addLast(IndexedValue (t + 1 , it)) }
23
22
}
24
23
return null
25
24
}
26
25
27
- fun part1 (limit : Int = 1024): Int? = findPath(coords.subList(0 , limit))?.size?.minus(1 )
28
-
29
26
fun part2 (): String? {
30
- var i = 0
31
- while (i < coords.size) {
32
- val path = findPath(coords.subList(0 , i + 1 )) ? : return coords[i].let { (x, y) -> " $x ,$y " }
33
- do i++ while (i < coords.size && coords[i] !in path)
27
+ val coords = coords.toMutableSet()
28
+ val sets = UnionFind <IntPair >()
29
+ for (x in 0 .. size) {
30
+ for (y in 0 .. size) {
31
+ val pos = x to y
32
+ if (pos in coords) continue
33
+ sets[pos]
34
+ if (x < size) (x + 1 to y).takeIf { it !in coords }?.let { sets[pos] = it }
35
+ if (y < size) (x to y + 1 ).takeIf { it !in coords }?.let { sets[pos] = it }
36
+ }
34
37
}
35
- return null
38
+ val src = 0 to 0
39
+ val dst = size to size
40
+ val (x, y) = coords.toList().asReversed().firstOrNull { pos ->
41
+ coords.remove(pos)
42
+ sets[pos]
43
+ val (x, y) = pos
44
+ if (x > 0 ) (x - 1 to y).takeIf { it !in coords }?.let { sets[pos] = it }
45
+ if (y > 0 ) (x to y - 1 ).takeIf { it !in coords }?.let { sets[pos] = it }
46
+ if (y < size) (x to y + 1 ).takeIf { it !in coords }?.let { sets[pos] = it }
47
+ if (x < size) (x + 1 to y).takeIf { it !in coords }?.let { sets[pos] = it }
48
+ sets[src] == sets[dst]
49
+ } ? : return null
50
+ return " $x ,$y "
36
51
}
37
52
38
- private data class Node (val x : Int , val y : Int , val next : Node ? = null )
53
+ private class UnionFind <T > {
54
+ private val sets = mutableMapOf<T , T >()
55
+
56
+ operator fun get (key : T ): T {
57
+ var key = key
58
+ var value = sets.getOrPut(key) { key }
59
+ while (key != value) {
60
+ val next = sets.getOrPut(value) { value }
61
+ sets[key] = next
62
+ key = value
63
+ value = next
64
+ }
65
+ return value
66
+ }
67
+
68
+ operator fun set (key : T , value : T ) {
69
+ sets[get(key)] = get(value)
70
+ }
71
+ }
39
72
}
0 commit comments