improved (a lot) day 5 puzzle 2
This commit is contained in:
		| @@ -14,10 +14,15 @@ object Puzzle2 { | ||||
|     def backward(dst: Long): Long = startSrc + dst - startDst | ||||
|     override def toString: String = s"[$startSrc;$endSrc[ -> ($dstTable) [$startDst;$endDst[" | ||||
|   } | ||||
|  | ||||
|   class Table(val id: Int) { | ||||
|     var ranges: ArrayBuffer[Range] = new ArrayBuffer() | ||||
|  | ||||
|     def addRange(range: Range): Unit = ranges.addOne(range) | ||||
|  | ||||
|     /** | ||||
|      * Sorts the ranges in ascending order | ||||
|      */ | ||||
|     def sortRanges(): Unit = { | ||||
|       var changed: Boolean = false | ||||
|       do { | ||||
| @@ -33,6 +38,9 @@ object Puzzle2 { | ||||
|       } while (changed) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Fills the gaps between ranges with identity ranges (i.e. which keep values unchanged) | ||||
|      */ | ||||
|     def fillGaps(): Unit = { | ||||
|       var r1: Range = Range(0, 0, 0, id + 1) | ||||
|       var r2: Range = r1 | ||||
| @@ -49,12 +57,23 @@ object Puzzle2 { | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Forwards a value through this table | ||||
|      * @param src The source to forward | ||||
|      * @return A pair containing the destination value and new table id | ||||
|      */ | ||||
|     def forward(src: Long): (Long, Int) = { | ||||
|       for (range: Range <- ranges) { | ||||
|         if (range.containsSrc(src)) return (range.forward(src), range.dstTable) | ||||
|       } | ||||
|       return (src, id+1) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Forwards a value in reverse through this table | ||||
|      * @param dst The destination to "backward" | ||||
|      * @return A pair containing the source value and new table id | ||||
|      */ | ||||
|     def backward(dst: Long): (Long, Int) = { | ||||
|       for (range: Range <- ranges) { | ||||
|         if (range.containsDst(dst)) return (range.backward(dst), id) | ||||
| @@ -67,6 +86,7 @@ object Puzzle2 { | ||||
|  | ||||
|   var forwardingTables: Array[Table] = Array.empty | ||||
|   var seeds: Array[Long] = Array.empty | ||||
|  | ||||
|   def loadInput(path: String): Unit = { | ||||
|     val source: BufferedSource = Source.fromFile(path) | ||||
|  | ||||
| @@ -89,6 +109,9 @@ object Puzzle2 { | ||||
|     source.close() | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Reorganizes all the tables by sorting the ranges and filling the gaps between them | ||||
|    */ | ||||
|   def sortTables(): Unit = { | ||||
|     for (table: Table <- forwardingTables) { | ||||
|       table.sortRanges() | ||||
| @@ -96,50 +119,24 @@ object Puzzle2 { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   def simplifyTables(): Unit = { | ||||
|   /** | ||||
|    * Collapses all forwarding tables into a single one, mapping seeds to locations | ||||
|    */ | ||||
|   def collapseTables(): Unit = { | ||||
|     for (i: Int <- forwardingTables.length - 1 until 0 by -1) { | ||||
|       //simplifyTable(i) | ||||
|       val newTable: Table = collapseTables(forwardingTables(i-1), forwardingTables(i)) | ||||
|       val newTable: Table = collapseTable(forwardingTables(i-1), forwardingTables(i)) | ||||
|       forwardingTables(i-1) = newTable | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   def simplifyTable(tableI: Int): Unit = { | ||||
|     val table1: Table = forwardingTables(tableI) | ||||
|     val table2: Table = forwardingTables(tableI+1) | ||||
|  | ||||
|     val newTable1: Table = new Table(table1.id) | ||||
|     val limits: ArrayBuffer[Long] = new ArrayBuffer() | ||||
|  | ||||
|     for (r1: Range <- table1.ranges) { | ||||
|       val startFrom1 = r1.startSrc | ||||
|       val endFrom1 = startFrom1 + r1.length | ||||
|       val startTo1 = r1.startDst | ||||
|       val endTo1 = startTo1 + r1.length | ||||
|  | ||||
|       limits.addOne(startTo1) | ||||
|       limits.addOne(endTo1) | ||||
|  | ||||
|       for (r2: Range <- table2.ranges) { | ||||
|         val startFrom2 = r2.startSrc | ||||
|         val endFrom2 = startFrom2 + r2.length | ||||
|         val startTo2 = r2.startDst | ||||
|         val endTo2 = startTo2 + r2.length | ||||
|  | ||||
|         limits.addOne(startFrom2) | ||||
|         limits.addOne(endFrom2) | ||||
|  | ||||
|         // If overlap | ||||
|         if (!(endTo1 < startFrom2 || startTo1 > endFrom2)) { | ||||
|            | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     forwardingTables(tableI) = newTable1 | ||||
|   } | ||||
|  | ||||
|   def collapseTables(table1: Table, table2: Table): Table = { | ||||
|   /** | ||||
|    * Collapses a forwarding table with the next tables | ||||
|    * @param table1 The table to collapse | ||||
|    * @param table2 The next table | ||||
|    * @return A new table equivalent to the fusion of both tables | ||||
|    */ | ||||
|   def collapseTable(table1: Table, table2: Table): Table = { | ||||
|     // Find all new range limits | ||||
|     val limitsSet: mutable.Set[Long] = new mutable.HashSet() | ||||
|     limitsSet.addOne(table1.ranges(0).startSrc) | ||||
|     for (range: Range <- table1.ranges) { | ||||
| @@ -152,6 +149,8 @@ object Puzzle2 { | ||||
|  | ||||
|     val newTable: Table = new Table(table1.id) | ||||
|     val limits: Array[Long] = limitsSet.toArray.sorted | ||||
|  | ||||
|     // For each limit, create the corresponding range by forwarding table 1 through table 2 | ||||
|     for (i: Int <- 0 until limits.length - 1) { | ||||
|       val src1: Long = limits(i) | ||||
|       val dst1: (Long, Int) = table1.forward(src1) | ||||
| @@ -162,42 +161,40 @@ object Puzzle2 { | ||||
|     return newTable | ||||
|   } | ||||
|  | ||||
|   def forward(value: Long, tableI: Int): Long = { | ||||
|     for (range: Range <- forwardingTables(tableI).ranges) { | ||||
|       if (value >= range.startSrc) { | ||||
|         if (value < range.startSrc + range.length) { | ||||
|           return value - range.startSrc + range.startDst | ||||
|         } | ||||
|       } else { | ||||
|         return value | ||||
|       } | ||||
|     } | ||||
|     return value | ||||
|   } | ||||
|   def solve(path: String): Long = { | ||||
|     println("Solving puzzle 2") | ||||
|     loadInput(path) | ||||
|     println("Loaded input") | ||||
|     sortTables() | ||||
|     for (table: Table <- forwardingTables) { | ||||
|     /*for (table: Table <- forwardingTables) { | ||||
|       println(table) | ||||
|     } | ||||
|     }*/ | ||||
|     println("Sorted forwarding tables") | ||||
|     simplifyTables() | ||||
|     collapseTables() | ||||
|     println("Simplified forwarding tables") | ||||
|     val table: Table = forwardingTables(0) | ||||
|     println(table) | ||||
|     //println(table) | ||||
|  | ||||
|     var smallest: Long = -1 | ||||
|     for (i: Int <- seeds.indices by 2) { | ||||
|       println(s"Mapping range of seed [${seeds(i)},${seeds(i)+seeds(i+1)}]") | ||||
|       for (seed: Long <- seeds(i) until seeds(i)+seeds(i+1)) { | ||||
|         val location: Long = table.forward(seed)._1 | ||||
|         if (smallest == -1 || location < smallest) { | ||||
|           smallest = location | ||||
|         } | ||||
|       val seedStart: Long = seeds(i) | ||||
|       val seedEnd: Long = seedStart + seeds(i+1) - 1 | ||||
|  | ||||
|       // Find range limits lying inside seed range | ||||
|       val limitsSet: mutable.Set[Long] = new mutable.HashSet() | ||||
|       limitsSet.addOne(seedStart) | ||||
|       limitsSet.addOne(seedEnd) | ||||
|       for (r2: Range <- table.ranges) { | ||||
|         if (r2.startSrc > seedStart && r2.startSrc < seedEnd) limitsSet.add(r2.startSrc) | ||||
|         if (r2.endSrc > seedStart && r2.endSrc < seedEnd) limitsSet.add(r2.startSrc) | ||||
|       } | ||||
|       val limits: Array[Long] = limitsSet.toArray.sorted | ||||
|  | ||||
|       // For each limit, forward its value and compare with current smallest | ||||
|       for (i: Int <- 0 until limits.length - 1) { | ||||
|         val value: Long = table.forward(limits(i))._1 | ||||
|         if (smallest == -1 || value < smallest) smallest = value | ||||
|       } | ||||
|       println(s"New smallest location: $smallest") | ||||
|     } | ||||
|     return smallest | ||||
|   } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user