74 lines
2.5 KiB
Scala
74 lines
2.5 KiB
Scala
package aoc.y2018
|
|
|
|
import aoc.Day
|
|
|
|
object Day03 extends Day {
|
|
|
|
import fastparse._, SingleLineWhitespace._
|
|
|
|
case class Claim(id: Int, pos: (Int, Int), size: (Int, Int))
|
|
|
|
def numParser[_: P]: P[Int] = P(CharIn("0-9").rep(1).!).map(_.toInt)
|
|
def idParser[_: P]: P[Int] = P("#" ~ numParser)
|
|
def coordParser[_: P]: P[(Int, Int)] = P(numParser ~ "," ~ numParser)
|
|
def dimensParser[_: P]: P[(Int, Int)] = P(numParser ~ "x" ~ numParser)
|
|
|
|
def claimParser[_: P]: P[Claim] = P(idParser ~ "@" ~ coordParser ~ ":" ~ dimensParser).map {
|
|
case (id, coords, dimens) => Claim(id, coords, dimens)
|
|
}
|
|
def claimsParser[_: P]: P[List[Claim]] = P(claimParser.rep(1, "\n"./)).map(_.toList)
|
|
|
|
def getClaims(input: String): List[Claim] = {
|
|
val Parsed.Success(claims, _) = parse(input, claimsParser(_))
|
|
claims
|
|
}
|
|
|
|
def insideRange(c: (Int, Int), p: (Int, Int), s: (Int, Int)): Boolean = {
|
|
(c, p, s) match {
|
|
case ((cx, cy), (px, py), (sw, sh)) =>
|
|
cx >= px &&
|
|
cx < px + sw &&
|
|
cy >= py &&
|
|
cy < py + sh
|
|
}
|
|
}
|
|
|
|
def mapSection[A](l: List[List[A]], p: (Int, Int), s: (Int, Int), f: A => A): List[List[A]] = {
|
|
val coordinated = l.zipWithIndex.map { case (n, i) => n.zipWithIndex.map { case (e, y) => (e, y, i) } }
|
|
val mapped = coordinated.map(_.map { case (e, y, x) => if (insideRange((x, y), p, s)) f(e) else e })
|
|
mapped
|
|
}
|
|
|
|
def maxSize(c: List[Claim]): (Int, Int) = {
|
|
(c.map {
|
|
case Claim(_, (x, _), (w, _)) => x + w
|
|
}.max, c.map {
|
|
case Claim(_, (_, y), (_, h)) => y + h
|
|
}.max)
|
|
}
|
|
|
|
override def part1(input: String): String = {
|
|
val claims = getClaims(input)
|
|
val (highestW, highestH) = maxSize(claims)
|
|
val starting: List[List[Int]] = List.fill(highestW)(List.fill(highestH)(0))
|
|
val finished = claims.foldLeft(starting)((acc, cc) => {
|
|
mapSection(acc, cc.pos, cc.size, (i: Int) => i + 1)
|
|
})
|
|
finished.flatten.count(_ > 1).toString
|
|
}
|
|
|
|
override def part2(input: String): String = {
|
|
val claims = getClaims(input)
|
|
val (highestW, highestH) = maxSize(claims)
|
|
val starting: List[List[List[Int]]] = List.fill(highestW)(List.fill(highestH)(List()))
|
|
val finished = claims.foldLeft(starting)((acc, cc) => {
|
|
mapSection(acc, cc.pos, cc.size, (e: List[Int]) => cc.id :: e)
|
|
})
|
|
val all = finished.flatten
|
|
val oneInhabitant = all.filter(_.size == 1).map(_.head).toSet
|
|
val solitary = oneInhabitant.filter(i => all.filter(_.contains(i)).forall(_.size == 1))
|
|
solitary.head.toString
|
|
}
|
|
|
|
}
|