package aoc.day18 import aoc._ import aoc.direction._ import Dir._ import scala.collection.SortedMap import scala.collection.mutable case class Dig(dir: Dir, count: Int, color: String): lazy val part2 = Parser.parse(Parser.digHex, color).get def apply(x: Long, y: Long) = dir.long(x, y, count) object Parser extends CommonParser with DirParser: val dig = dir ~ num ~ "(#" ~ """[0-9a-f]{6}""".r ~ ")" ^^ { case dir ~ num ~ _ ~ color ~ _ => Dig(dir, num, color) } val hexDigit = """[0-9a-f]""".r ^^ { case c if c.charAt(0).isDigit => c.charAt(0) - '0' case c => c.charAt(0) - 'a' + 10 } def hexNum(len: Int) = repN(len, hexDigit).map(_.foldLeft(0)(_ * 16 + _)) val toDir = Array(Right, Down, Left, Up) val digHex = hexNum(5) ~ hexDigit ^^ { case num ~ dig => Dig(toDir(dig), num, "") } def apply(s: String) = parse(dig, s).get def instructions() = lines.map(Parser(_)).toSeq def points(ins: Seq[Dig]) = ins .scanLeft((0L, 0L)) { case ((x, y), in) => in(x, y) } .dropRight(1) extension [T](ss: Seq[T]) def shiftLeft = ss.drop(1) ++ ss.take(1) def area(pts: Seq[(Long, Long)]) = pts .lazyZip(pts.shiftLeft) .map { case ((ax, ay), (bx, by)) => (bx - ax) * (by + ay) } .sum .abs def circum(pts: Seq[(Long, Long)]) = pts .lazyZip(pts.shiftLeft) .map { case ((ax, ay), (bx, by)) => (bx - ax).abs + (by - ay).abs } .sum def areaBlock(pts: Seq[(Long, Long)]) = (area(pts) + circum(pts)) / 2 + 1 def part1 = val ins = instructions() val pts = points(ins) println(areaBlock(pts)) def part2 = val ins = instructions().map(_.part2) val pts = points(ins) println(areaBlock(pts)) @main def Day18(part: Int) = part match case 1 => part1 case 2 => part2