package aoc.day6 import aoc._ case class Race(time: Long, distance: Long): def waysToWin = val minTime = search(0, (time - 1) / 2) val midOk = if time % 2 == 0 && withHold(time / 2) > distance then 1L else 0 2 * (minTime to (time - 1) / 2).length + midOk @scala.annotation.tailrec private final def search(min: Long, max: Long): Long = if min >= max then min else val mid = (max + min) / 2 if withHold(mid) <= distance then search(mid + 1, max) else search(min, mid) def withHold(k: Long) = k * (time - k) object Parser extends CommonParser: val nums = rep1(num) def time[T](nums: Parser[T]) = "Time:" ~> nums def distance[T](nums: Parser[T]) = "Distance:" ~> nums val bigNum = rep1("""\d+""".r) ^^ (_.mkString.toLong) def races(ss: Seq[String]) = ss match { case Seq(t, d) => parse(time(nums), t).get.zip(parse(distance(nums), d).get).map(Race(_, _)) } def bigRace(ss: Seq[String]) = ss match { case Seq(t, d) => Race(parse(time(bigNum), t).get, parse(distance(bigNum), d).get) } def part1 = val races = Parser.races(lines.toSeq) val res = races.map(_.waysToWin).product println(res) def part2 = val race = Parser.bigRace(lines.toSeq) val res = race.waysToWin println(res) @main def Day6(part: Int) = part match case 1 => part1 case 2 => part2