@@ -4,6 +4,8 @@ import eu.sim642.adventofcodelib.OrderedSearch
4
4
import eu .sim642 .adventofcodelib .graph .{BFS , GraphSearch , TargetNode , UnitNeighbors }
5
5
import eu .sim642 .adventofcodelib .pos .Pos
6
6
7
+ import scala .annotation .tailrec
8
+
7
9
object Day18 {
8
10
9
11
def bytesGraphSearch (bytes : Seq [Pos ], max : Pos = Pos (70 , 70 ), after : Int = 1024 ): GraphSearch [Pos ] & UnitNeighbors [Pos ] & TargetNode [Pos ] = {
@@ -30,16 +32,51 @@ object Day18 {
30
32
BFS .search(graphSearch).target.get._2
31
33
}
32
34
33
- def exitReachable (bytes : Seq [Pos ], max : Pos , after : Int ): Boolean = {
34
- val graphSearch = bytesGraphSearch(bytes, max, after)
35
- BFS .search(graphSearch).target.isDefined
35
+ trait Part2Solution {
36
+ def findBlockingByte (bytes : Seq [Pos ], max : Pos = Pos (70 , 70 )): Pos
37
+
38
+ def findBlockingByteString (bytes : Seq [Pos ], max : Pos = Pos (70 , 70 )): String = {
39
+ val blockingByte = findBlockingByte(bytes, max)
40
+ s " ${blockingByte.x}, ${blockingByte.y}"
41
+ }
36
42
}
37
43
38
- def findBlockingByte (bytes : Seq [Pos ], max : Pos = Pos (70 , 70 )): String = {
39
- def f (after : Int ): Boolean = ! exitReachable(bytes, max, after)
40
- val blockingAfter = OrderedSearch .binaryLower(f, 0 , bytes.size + 1 )(true )
41
- val blockingByte = bytes(blockingAfter - 1 )
42
- s " ${blockingByte.x}, ${blockingByte.y}"
44
+ object BinarySearchPart2Solution extends Part2Solution {
45
+ def exitReachable (bytes : Seq [Pos ], max : Pos , after : Int ): Boolean = {
46
+ val graphSearch = bytesGraphSearch(bytes, max, after)
47
+ BFS .search(graphSearch).target.isDefined
48
+ }
49
+
50
+ override def findBlockingByte (bytes : Seq [Pos ], max : Pos = Pos (70 , 70 )): Pos = {
51
+ def f (after : Int ): Boolean = ! exitReachable(bytes, max, after)
52
+ val blockingAfter = OrderedSearch .binaryLower(f, 0 , bytes.size + 1 )(true )
53
+ bytes(blockingAfter - 1 )
54
+ }
55
+ }
56
+
57
+ object LinearOnPathPart2Solution extends Part2Solution {
58
+ def exitPath (bytes : Seq [Pos ], max : Pos , after : Int ): Option [Seq [Pos ]] = {
59
+ val graphSearch = bytesGraphSearch(bytes, max, after + 1 )
60
+ BFS .searchPaths(graphSearch).paths.get(graphSearch.targetNode) // TODO: optimize paths to not compute everything
61
+ }
62
+
63
+ override def findBlockingByte (bytes : Seq [Pos ], max : Pos = Pos (70 , 70 )): Pos = {
64
+
65
+ @ tailrec
66
+ def helper (after : Int , path : Set [Pos ]): Int = {
67
+ if (path(bytes(after))) {
68
+ exitPath(bytes, max, after + 1 ) match {
69
+ case Some (newPath) => helper(after + 1 , newPath.toSet)
70
+ case None => after + 1
71
+ }
72
+ }
73
+ else
74
+ helper(after + 1 , path)
75
+ }
76
+
77
+ val blockingAfter = helper(0 , exitPath(bytes, max, 0 ).get.toSet)
78
+ bytes(blockingAfter - 1 )
79
+ }
43
80
}
44
81
45
82
def parseByte (s : String ): Pos = s match {
@@ -51,7 +88,8 @@ object Day18 {
51
88
lazy val input : String = scala.io.Source .fromInputStream(getClass.getResourceAsStream(" day18.txt" )).mkString.trim
52
89
53
90
def main (args : Array [String ]): Unit = {
91
+ import BinarySearchPart2Solution ._
54
92
println(exitSteps(parseBytes(input)))
55
- println(findBlockingByte (parseBytes(input)))
93
+ println(findBlockingByteString (parseBytes(input)))
56
94
}
57
95
}
0 commit comments