improved (a lot) day 5 puzzle 2
This commit is contained in:
parent
123d0db8b2
commit
4e1cd00e53
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user