Day 22
This commit is contained in:
parent
ad6a55720a
commit
6a63f5d32e
82
Day22.scala
Normal file
82
Day22.scala
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
package aoc.day22
|
||||||
|
|
||||||
|
import aoc._
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
|
case class Point3(x: Int, y: Int, z: Int):
|
||||||
|
def min(other: Point3) = Point3(x.min(other.x), y.min(other.y), z.min(other.z))
|
||||||
|
def max(other: Point3) = Point3(x.max(other.x), y.max(other.y), z.max(other.z))
|
||||||
|
|
||||||
|
def to2D = (x, y)
|
||||||
|
|
||||||
|
case class Brick private (index: Int, low: Point3, high: Point3):
|
||||||
|
inline def height = high.z - low.z + 1
|
||||||
|
def to2D = (low.to2D, high.to2D)
|
||||||
|
|
||||||
|
object Brick:
|
||||||
|
private var index = 0
|
||||||
|
def fromPoints(a: Point3, b: Point3) =
|
||||||
|
index += 1
|
||||||
|
Brick(index, a.min(b), a.max(b))
|
||||||
|
|
||||||
|
object Parser extends CommonParser:
|
||||||
|
val point3 = num ~ "," ~ num ~ "," ~ num ^^ { case x ~ _ ~ y ~ _ ~ z => Point3(x, y, z) }
|
||||||
|
val brick = point3 ~ "~" ~ point3 ^^ { case a ~ _ ~ b => Brick.fromPoints(a, b) }
|
||||||
|
|
||||||
|
val bricks =
|
||||||
|
lines
|
||||||
|
.map(Parser.parse(Parser.brick, _).get)
|
||||||
|
.toSeq
|
||||||
|
|
||||||
|
// part 1
|
||||||
|
|
||||||
|
class Space:
|
||||||
|
case class Cell(height: Int, occupied: Int /* index of the occupied brick */ )
|
||||||
|
val space = mutable.Map.empty[(Int, Int), Cell]
|
||||||
|
|
||||||
|
// Override a brick falling and returns the height and unique brick that holds it, if it exists.
|
||||||
|
def overrideBrick(b: Brick): (Int, Option[Int]) =
|
||||||
|
// the space covered is
|
||||||
|
val covered = (b.low.x to b.high.x).flatMap(x => (b.low.y to b.high.y).map((x, _)))
|
||||||
|
// get the maximum height occupied
|
||||||
|
val pastCells = covered.flatMap(space.get(_))
|
||||||
|
val maxHeight = pastCells.map(_.height).maxOption.getOrElse(0)
|
||||||
|
assert(maxHeight <= b.low.z)
|
||||||
|
// update space
|
||||||
|
covered.foreach(space.update(_, Cell(maxHeight + b.height, b.index)))
|
||||||
|
// get the ones held
|
||||||
|
val res = pastCells.filter(_.height == maxHeight).map(_.occupied).toSet.toSeq match
|
||||||
|
case Seq(idx) => Some(idx)
|
||||||
|
case _ => None
|
||||||
|
(maxHeight, res)
|
||||||
|
|
||||||
|
// sort bricks by low z
|
||||||
|
val sortedBricks = bricks.sortBy(_.low.z)
|
||||||
|
|
||||||
|
def part1() =
|
||||||
|
val space = Space()
|
||||||
|
val holdingBricks = sortedBricks.foldLeft(Set.empty[Int])(_ ++ space.overrideBrick(_)._2)
|
||||||
|
println(bricks.size - holdingBricks.size)
|
||||||
|
|
||||||
|
def part2() =
|
||||||
|
extension (bs: Iterator[Brick])
|
||||||
|
def heights =
|
||||||
|
val space = Space()
|
||||||
|
bs.map(b => (b -> space.overrideBrick(b)._1)).toMap
|
||||||
|
extension (bm: Map[Brick, Int])
|
||||||
|
inline def countDifferences(original: Map[Brick, Int]) =
|
||||||
|
bm.count((b, h) => h != original(b))
|
||||||
|
|
||||||
|
val original = sortedBricks.iterator.heights
|
||||||
|
val res = bricks
|
||||||
|
.map: exclude =>
|
||||||
|
sortedBricks.iterator
|
||||||
|
.filter(_ != exclude)
|
||||||
|
.heights
|
||||||
|
.countDifferences(original)
|
||||||
|
.sum
|
||||||
|
println(res)
|
||||||
|
|
||||||
|
@main def Day22(part: Int) = part match
|
||||||
|
case 1 => part1()
|
||||||
|
case 2 => part2()
|
1471
inputs/day22.input
Normal file
1471
inputs/day22.input
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue