Commit b85d7457 by Alexander Gehrke

### [day13] solution

```My input actually required BigInt, while other people's inputs worked
with long. That took long to debug...```
parent c2f418f3
 0 17,x,13,19
 0 67,7,59,61
 0 67,x,7,59,61
 0 67,7,x,59,61
 0 1789,37,47,1889
 package aoc2020 import aoc2020.lib._ import cats.implicits.given import scala.math.{min,max} import cats._, cats.implicits.given def day13(input: List[String]): String = input match { case timestamp :: busses :: Nil => val idsWithOffsets = busses.splitNN(",") .zipWithIndex .filter(_._1 != "x") .map { (id, offset) => (id.toLong, offset.toLong) } val (next, wait) = findEarliest(timestamp.toLong, idsWithOffsets.map(_._1)) val contestTimestamp = findContinuousDepartures(idsWithOffsets) s"Next bus: \$next in \$wait minutes (solution: \${next * wait})\nPlanning Contest timestamp: \$contestTimestamp" case _ => "Expected two lines of input" } def findEarliest(timestamp: Long, departures: List[Long]): (Long, Long) = departures.map(id => (id, id - timestamp % id)).minBy(_._2) import scala.math.BigInt def findContinuousDepartures(idsWithOffsets: List[(Long,Long)]): BigInt = // naive apporach, much too slow //val first :: later = idsWithOffsets //LazyList.iterate(0L)(_ + first).find(start => { // later.forall((id, offset) => (start + offset) % id == 0) // }).get /* using https://en.wikipedia.org/wiki/Chinese_remainder_theorem#Generalization_to_non-coprime_moduli * the solution can be found in one iteration */ val mods = idsWithOffsets.map((id, off) => (BigInt(id), BigInt((id - off) % id))) mods.tail.foldLeft(mods.head) { case ((mod, time), (nmod, offset)) => val (_, s, t) = extendedEuclid(mod, nmod) val modprod = mod * nmod val ntime = (time * s * nmod + offset * t * mod).mod(modprod) (modprod, ntime) }._2 /** extended euclidian algorithm * https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm * @return (gcd, Bézout coeffients s, t) */ def extendedEuclid(a: BigInt, b: BigInt): (BigInt,BigInt,BigInt) = @annotation.tailrec def rec(r: BigInt, rp: BigInt, s: BigInt, sp: BigInt, t: BigInt, tp: BigInt): (BigInt, BigInt, BigInt) = val q = rp / r val rn = rp - r * q val sn = sp - s * q val tn = tp - t * q if rn == 0 then (r, s, t) else rec(rn, r, sn, s, tn, t) rec(a, b, 0, 1, 1, 0) def lcm(nums: Vector[Long]): Long = def rec(mi: Vector[Long]): Long = val (m, i) = mi.zipWithIndex.min val miNext = mi.updated(i, m + nums(i)) if miNext.distinct.size == 1 then miNext.head else rec(miNext) rec(nums)
 ... ... @@ -14,6 +14,7 @@ package aoc2020 case 10 => input(_.toInt)(day10) case 11 => inputF(boolChar('L'))(Vector)(day11) case 12 => input()(day12) case 13 => input()(day13) case _ => "No such day implemented" } if (sample.nonEmpty) println("SAMPLE VALUES!") ... ...
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!