This commit is contained in:
Paul-Henri Froidmont 2023-12-06 05:28:28 +01:00
parent bfb8326f1d
commit 6565c94961
Signed by: phfroidmont
GPG key ID: BE948AFD7E7873BE
2 changed files with 331 additions and 0 deletions

105
src/day05.scala Normal file
View 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