-
-
Save waynejo/f8f48edc834302682e63da00f55926bb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.FileInputStream | |
import scala.annotation.tailrec | |
import scala.io.StdIn | |
case class Input(seedInput: Vector[BigInt], mapping: Vector[MappingGroup]) | |
case class Range(start: BigInt, length: BigInt) | |
case class Mapping(source: Range, destination: Range) | |
case class MappingGroup(mappings: Vector[Mapping]): | |
@tailrec | |
private def _applyMapping(remain: Vector[Range], remainMappings: Vector[Mapping], acc: Vector[Range]): Vector[Range] = | |
(remain, remainMappings) match | |
case (Vector(), _) => acc | |
case (_, Vector()) => acc ++ remain | |
case (v +: vs, m +: ms) => | |
if v.start < m.source.start then | |
val newMapped = Range(v.start, (m.source.start - v.start) min v.length) | |
val newValue = Range(m.source.start, v.start + v.length - m.source.start) | |
_applyMapping((newValue +: vs).filter(0 < _.length), remainMappings, acc :+ newMapped) | |
else if v.start >= m.source.start + m.source.length then | |
_applyMapping(v +: vs, ms, acc) | |
else | |
val newMappedSrc = Range(v.start, (m.source.start + m.source.length) - v.start min v.length) | |
val newMapped = Range(newMappedSrc.start + (m.destination.start - m.source.start), newMappedSrc.length) | |
val newValue = Range(m.source.start + m.source.length, (v.start + v.length) - (m.source.start + m.source.length) min v.length) | |
_applyMapping((newValue +: vs).filter(0 < _.length), remainMappings, (acc :+ newMapped).filter(0 < _.length)) | |
def applyMapping(v: Vector[Range]): Vector[Range] = | |
_applyMapping(v.sortBy(_.start), mappings, Vector.empty).sortBy(_.start) | |
object MappingGroup: | |
def apply(mappings: Vector[Mapping]): MappingGroup = | |
new MappingGroup(mappings.sortBy(_.source.start)) | |
def parseInput(inputs: Vector[String]): Input = | |
val seeds = inputs.head.split(" ").tail.map(BigInt.apply).toVector | |
def _parseGroupStart(inputs: Vector[String], acc: Input): Input = | |
_parseGroupBody(inputs.tail, acc, Vector.empty) | |
@tailrec | |
def _parseGroupBody(inputs: Vector[String], acc: Input, mappings: Vector[Mapping]): Input = | |
inputs.headOption.map(_.trim) match | |
case None => acc.copy(mapping = acc.mapping :+ MappingGroup(mappings)) | |
case Some("") => _parseGroupStart(inputs.tail, acc.copy(mapping = acc.mapping :+ MappingGroup(mappings))) | |
case _ => | |
val Array(destination, source, length) = inputs.head.split(" ").map(BigInt.apply) | |
_parseGroupBody(inputs.tail, acc, mappings :+ Mapping(Range(source, length), Range(destination, length))) | |
_parseGroupStart(inputs.drop(2), Input(seeds, Vector.empty)) | |
def solve5_1(input: Input): BigInt = | |
val seeds = input.seedInput.map(Range(_, 1)) | |
input.mapping.foldLeft(seeds) { (seeds, group) => | |
group.applyMapping(seeds) | |
}.head.start | |
def solve5_2(input: Input): BigInt = | |
val seeds = input.seedInput.grouped(2).map(v => Range(v.head, v.last)).toVector | |
input.mapping.foldLeft(seeds) { (seeds, group) => | |
group.applyMapping(seeds) | |
}.head.start | |
@main def solve5(): Unit = | |
val in = new FileInputStream("example5-2.in") | |
System.setIn(in) | |
val inputs = Iterator.continually(StdIn.readLine()) | |
.takeWhile(line => null != line) | |
.toVector | |
println(solve5_1(parseInput(inputs))) | |
println(solve5_2(parseInput(inputs))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment