Day 5
This commit is contained in:
parent
bfb8326f1d
commit
6565c94961
2 changed files with 331 additions and 0 deletions
105
src/day05.scala
Normal file
105
src/day05.scala
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
package aoc
|
||||
package day05
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
import util.chaining.*
|
||||
|
||||
val dayNumber = "05"
|
||||
|
||||
@main def part1: Unit =
|
||||
println(part1(loadInput(dayNumber)))
|
||||
|
||||
@main def part2: Unit =
|
||||
println(part2(loadInput(dayNumber)))
|
||||
|
||||
def part1(input: String): String =
|
||||
|
||||
final case class Category(ranges: List[Range]):
|
||||
def get(x: Long) = ranges.find(_.contains(x)).map(_.get(x)).getOrElse(x)
|
||||
|
||||
final case class Range(dest: Long, source: Long, length: Long):
|
||||
def contains(x: Long) = x >= source && x <= source + length
|
||||
def get(x: Long) = x + dest - source
|
||||
|
||||
val s"seeds: $seedsI" :: mapsI = input.split("\n\n").toList: @unchecked
|
||||
val seeds = seedsI.split(" ").map(_.toLong).toSet
|
||||
val categories = mapsI
|
||||
.map(
|
||||
_.split("\n")
|
||||
.drop(1)
|
||||
.map { case s"$dest $source $length" =>
|
||||
Range(dest.toLong, source.toLong, length.toLong)
|
||||
}
|
||||
.toList
|
||||
)
|
||||
.map(Category(_))
|
||||
seeds
|
||||
.map(s => categories.foldLeft(s)((n, c) => c.get(n)))
|
||||
.min
|
||||
.toString
|
||||
|
||||
def part2(input: String): String =
|
||||
final case class Category(incompleteRanges: List[Range]):
|
||||
val ranges = incompleteRanges
|
||||
.sortBy(_.source)
|
||||
.foldLeft((0L, List.empty[Range])) { case ((pos, ranges), range) =>
|
||||
if range.source > pos then
|
||||
(
|
||||
range.source + range.length,
|
||||
ranges.appendedAll(List(Range(pos, pos, range.source - pos), range))
|
||||
)
|
||||
else (range.source + range.length, ranges.appended(range))
|
||||
}
|
||||
._2
|
||||
def project2(s: SeedRange): List[SeedRange] =
|
||||
val seedRanges = mutable.ArrayBuffer.empty[SeedRange]
|
||||
var start = s.from
|
||||
var remaining = s.length
|
||||
while remaining > 0 do
|
||||
ranges.find(_.contains(start)) match
|
||||
case Some(range) =>
|
||||
val rangeOffset = start - range.source
|
||||
val length = Math.min(remaining, range.length - rangeOffset)
|
||||
val newRange = SeedRange(range.dest + rangeOffset, length)
|
||||
start += length + 1
|
||||
remaining -= length
|
||||
seedRanges.addOne(newRange)
|
||||
case None =>
|
||||
seedRanges.addOne(SeedRange(start, remaining))
|
||||
remaining = 0
|
||||
seedRanges.toList
|
||||
|
||||
final case class Range(dest: Long, source: Long, length: Long):
|
||||
def contains(value: Long): Boolean =
|
||||
source <= value && value < source + length
|
||||
|
||||
final case class SeedRange(from: Long, length: Long)
|
||||
|
||||
val s"seeds: $seedsI" :: mapsI = input.split("\n\n").toList: @unchecked
|
||||
val seedRanges = seedsI
|
||||
.split(" ")
|
||||
.map(_.toLong)
|
||||
.grouped(2)
|
||||
.map { case Array(from, to) => (from, to) }
|
||||
.toList
|
||||
val categories = mapsI
|
||||
.map(
|
||||
_.split("\n")
|
||||
.drop(1)
|
||||
.map { case s"$dest $source $length" =>
|
||||
Range(dest.toLong, source.toLong, length.toLong)
|
||||
}
|
||||
.toList
|
||||
)
|
||||
.map(Category(_))
|
||||
|
||||
seedRanges
|
||||
.map((from, length) => SeedRange(from, length))
|
||||
.flatMap(s =>
|
||||
categories.foldLeft(List(s))((acc, c) => acc.flatMap(c.project2))
|
||||
)
|
||||
.map(_.from)
|
||||
.min
|
||||
.pipe(_ - 1)
|
||||
.toString
|
||||
Loading…
Add table
Add a link
Reference in a new issue