@@ -4,6 +4,8 @@ import eu.sim642.adventofcodelib.OrderedSearch
44import eu .sim642 .adventofcodelib .graph .{BFS , GraphSearch , TargetNode , UnitNeighbors }
55import eu .sim642 .adventofcodelib .pos .Pos
66
7+ import scala .annotation .tailrec
8+
79object Day18 {
810
911 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 {
3032 BFS .search(graphSearch).target.get._2
3133 }
3234
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+ }
3642 }
3743
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+ }
4380 }
4481
4582 def parseByte (s : String ): Pos = s match {
@@ -51,7 +88,8 @@ object Day18 {
5188 lazy val input : String = scala.io.Source .fromInputStream(getClass.getResourceAsStream(" day18.txt" )).mkString.trim
5289
5390 def main (args : Array [String ]): Unit = {
91+ import BinarySearchPart2Solution ._
5492 println(exitSteps(parseBytes(input)))
55- println(findBlockingByte (parseBytes(input)))
93+ println(findBlockingByteString (parseBytes(input)))
5694 }
5795}
0 commit comments