From cc3e84d95eddb0fca9822cdc59bfe29e361b4f42 Mon Sep 17 00:00:00 2001 From: Natsu Kagami Date: Thu, 21 Dec 2023 18:21:38 +0100 Subject: [PATCH] Day 21 --- Day21.scala | 194 +++++++++++++++++++++++++++++++++++++++++++++ Direction.scala | 2 + inputs/day21.input | 131 ++++++++++++++++++++++++++++++ 3 files changed, 327 insertions(+) create mode 100644 Day21.scala create mode 100644 inputs/day21.input diff --git a/Day21.scala b/Day21.scala new file mode 100644 index 0000000..43a7798 --- /dev/null +++ b/Day21.scala @@ -0,0 +1,194 @@ +package aoc.day21 + +import aoc._ +import aoc.direction._ +import scala.collection.mutable + +val board = + lines + .map(_.toArray) + .toArray + +val startPoint = + board.toSeq.zipWithIndex.findMap { (row, idx) => + row.toSeq.zipWithIndex.findMap: (cell, col) => + if cell == 'S' then Some((idx, col)) else None + }.get + +def inside(x: Int, y: Int) = + x >= 0 && x < board.length && y >= 0 && y < board(0).length + +def walkable(x: Int, y: Int) = inside(x, y) && board(x)(y) != '#' + +def getInf(x: Int, y: Int) = + def mod(x: Int, m: Int): Int = if x < 0 then mod(x % m + m, m) else x % m + board(mod(x, board.size))(mod(y, board(0).size)) +def walkableInf(x: Int, y: Int) = getInf(x, y) != '#' + +// part 1 + +def walk(steps: Int, starting: Set[(Int, Int)]): Set[(Int, Int)] = + if steps == 0 then starting + else + // println(s"$steps => ${starting.size}") + val ns = + starting + .flatMap((a, b) => Dir.all.map(_(a, b))) + .filter(walkableInf(_, _)) + walk(steps - 1, ns) + +def part1 = + val possible = walk(300, Set(startPoint)) + println(possible.size) + +// part 2 + +object shortestPathsFrom: + val cache = mutable.Map.empty[(Int, Int), Array[Array[Int]]] + + def apply(x: Int, y: Int) = + cache.getOrElseUpdate( + (x, y), { + val mp = mutable.Map((x, y) -> 0) + val queue = mutable.Queue((x, y)) + while !queue.isEmpty do + val (x, y) = queue.dequeue() + val dist = mp((x, y)) + Dir.all + .map(_(x, y)) + .filter(walkable(_, _)) + .foreach { pt => + if !mp.contains(pt) then + mp += pt -> (dist + 1) + queue += pt + } + val (a, b) = mp.toMap.partition((_, dist) => dist % 2 == 0) + Iterator(a, b) + .map(v => v.values.toSeq.sorted.toArray) + .toArray + } + ) + +// input is funni + +val _ = + assert(board.head.forall(_ == '.')) + assert(board.last.forall(_ == '.')) + assert(board.forall(_.head == '.')) + assert(board.forall(_.last == '.')) + + val (x, y) = startPoint + assert((0 until board.length).forall(board(_)(y) != '#')) + assert((0 until board(0).length).forall(board(x)(_) != '#')) + +def pointsReachable(steps: Int): Long = + val (sx, sy) = startPoint + def distToRow(delta: Int) = + if delta == 0 then 0L + else if delta < 0 then + // go up + 1L + sx + (delta + 1L).abs * board.size + else 0L + (board.size - sx) + (delta - 1L) * board.size + def distToCol(delta: Int) = + if delta == 0 then 0L + else if delta < 0 then + // go left + 1L + sy + (delta + 1L).abs * board(0).size + else 0L + (board(0).size - sy) + (delta - 1L) * board(0).size + + def startWhere(dx: Int, dy: Int) = + val x = if dx == 0 then sx else if dx < 0 then board.size - 1 else 0 + val y = if dy == 0 then sy else if dy < 0 then board(0).size - 1 else 0 + (x, y) + + def countWhere(steps: Int, dx: Int, dy: Int) = + val dToBoard = distToRow(dx) + distToCol(dy) + if dToBoard > steps then 0L + else + val (stx, sty) = startWhere(dx, dy) + val dists = shortestPathsFrom(stx, sty)((steps - dToBoard).toInt % 2) + val res = dists.sortedCountUntil(steps - dToBoard.toInt).toLong + // println(s"got $dx $dy $dToBoard $stx $sty => $res ${shortestPathsFrom(stx, sty).map(_.size).toSeq}") + res + + (-1 to 1).zip((-1 to 1)).foreach { (dx, dy) => + val (stx, sty) = startWhere(dx, dy) + // println(s"$dx $dy ${shortestPathsFrom(stx, sty).map(_.size).toSeq}") + } + + extension (arr: Array[Int]) + def sortedCountUntil(max: Int) = + var low = 0 + var hi = arr.size + while low < hi do + val mid = (low + hi) / 2 + // println(s"$mid => ${arr(mid)} ~ $max") + if arr(mid) <= max then low = mid + 1 else hi = mid + // println(s"found $low => ${arr(low - 1)}") + low + + ((0 to steps).toIterator + .takeWhile(distToRow(_) <= steps) + ++ (-1 to -steps by -1).toIterator.takeWhile(distToRow(_) <= steps)) + .map(dx => + val dRow = distToRow(dx) + val zero = countWhere(steps, dx, 0) + val right = + val (stx, sty) = startWhere(dx, 1) + val baseDistance = dRow + distToCol(1) // dToBoard = baseDistance + (delta-1) * board.size + if baseDistance > steps then 0L + else + val maxRightAllBoard = + ((steps - baseDistance - shortestPathsFrom(stx, sty).map(_.last).max) / board.size).toInt.max(0) + 1 + val odd = ((steps - baseDistance) % 2).toInt + val a = (1L until maxRightAllBoard by 2).size * shortestPathsFrom(stx, sty)(odd).size + val b = (2L until maxRightAllBoard by 2).size * shortestPathsFrom(stx, sty)((board.size + odd) % 2).size + // println( + // s"$dx => $maxRightAllBoard [${distToRow(dx) + distToCol(maxRightAllBoard)} ${shortestPathsFrom(stx, sty) + // .map(_.last) + // .max}] ${a + b}" + // ) + val rest = (maxRightAllBoard to steps).toIterator + .takeWhile(dRow + distToCol(_) <= steps) + .map(countWhere(steps, dx, _)) + .sum + a + b + rest + val left = + val (stx, sty) = startWhere(dx, -1) + val baseDistance = dRow + distToCol(-1) // dToBoard = baseDistance + (delta-1) * board.size + if baseDistance > steps then 0L + else + val maxLeftAllBoard = + ((steps - baseDistance - shortestPathsFrom(stx, sty).map(_.last).max) / board.size).toInt.max(0) + 1 + // println(s"$dx => -$maxLeftAllBoard") + val odd = ((steps - baseDistance) % 2).toInt + val a = (-1L until -maxLeftAllBoard by -2).size * shortestPathsFrom(stx, sty)(odd).size + val b = (-2L until -maxLeftAllBoard by -2).size * shortestPathsFrom(stx, sty)((board.size + odd) % 2).size + // println(s"$dx => -$maxLeftAllBoard [${distToRow(dx) + distToCol(-maxLeftAllBoard)}] ${a + b}") + val rest = (-maxLeftAllBoard to -steps by -1).toIterator + .takeWhile(dRow + distToCol(_) <= steps) + .map(countWhere(steps, dx, _)) + .sum + a + b + rest + zero + right + left + ) + .sum + +def part2 = + val inputs = Seq(26501365) + // val inputs = Seq(1, 131) + println(inputs.map(pointsReachable)) + // val s = walk(200, Set(startPoint)) + // // divide by quadrant + // val quads = s.toSeq + // .groupBy((x, y) => + // val qx = if x < 0 then -(-x + board.size - 1) / board.size else x / board.size + // val qy = if y < 0 then -(-y + board(0).size - 1) / board(0).size else y / board(0).size + // (qx, qy) + // ) + // .mapValues(_.size) + // println((quads.toSeq, quads.values.sum)) + +@main def Day21(part: Int) = part match + case 1 => part1 + case 2 => part2 diff --git a/Direction.scala b/Direction.scala index cf89159..68c00bd 100644 --- a/Direction.scala +++ b/Direction.scala @@ -5,6 +5,8 @@ import aoc._ object Dir: val dx = Array(-1, 0, 1, 0) val dy = Array(0, 1, 0, -1) + + val all = Array(Up, Right, Down, Left) import Dir._ enum Dir: case Up, Right, Down, Left diff --git a/inputs/day21.input b/inputs/day21.input new file mode 100644 index 0000000..035fd83 --- /dev/null +++ b/inputs/day21.input @@ -0,0 +1,131 @@ +................................................................................................................................... +.#.........#......#................#...#.......#.....##............................##..#........#.#.#.#......#......#...#........#. +..............#..#.....#.....##....................#....................................#....##.#.......#.......#...#...........#.. +.#..#..#.#...#.....#.......#......#..#..#.............#.#..................#.......#.............#..#.......#.......#.............. +.....................#.............#............#.#................................#.......#........#...............#....#..#...... +.....#...........#.......#..................................................#..............#.##.....#.............................. +...#.........................##...#.#................#.....................................#.......#.#........#....#.......#....#.. +.#....####..........#......................#........#..................................#...........#..#..#....#......#............. +...#.....................#........................#...............................#.......................#....#......#............ +....#......#....#......#....#....##..........................#.....#................#.....#........#.....##........................ +................#.#....#.#..#....................#..............#........................#...#.......#.#..........#.......#.#...... +.........#.#.......#............#.............#...........................................#...#.....#.......................#...... +.....#.................#.........#.#.....................#............#..........#.#.#......#...........#.#..............#...#..... +..............................#......#.......#..#..............#....................#...#.##..##..........#...............#...##... +.....#........#.#............#.......#.....###...........................#.....................#................................#.. +..##..........#......#...#..............#.....#................#.........#.#...............#...............#....................... +............................#...#.#..................#....................#.......................#.......#........#..#....#....#.. +...#............#..#......#...........#................#.....#............................##...##........#..............##......... +..#...#............................#...#...............................#..#..............................#.............#..#....#... +.#.............#...#.....#.#..........#.............#......#..........#....#.#.................#.................#..#......##..#... +.......#........#..................#.....#........#.#.........#........##....#..............#.......#...#....#.............#....... +.........#.........#......#.#..#....#............##......#...........#.....................#.....#.#.....#.................#....... +..............................#.#......#............#..#....#....................##.............#...##....#.................###.... +......#...##...#....#.##...........#.#...........#...##..............#.#.....##....#..........#..#.........#.....#................. +....##...###.........................#............#............#.............#.##...............#..............##.....#............ +.....#..#......##.#.........#.....##............#.....#.........#...................#......................#........#..........###. +............#.............#........#.......#...###......#...#.#......##.#...........#..#......................#................#... +..........................................................#........................#..........................#....#....##.....#... +....#...#........#.......................#..........#.............#..#.#...............................#.......##.#...##........... +...#........#..........#........................#...........#.............#.#.....................#...#.#.##.#..................#.. +.......................#....#..............#..####......##.#.............#...........#...##............#..#..........##...#.....#.. +..#.................#.#..................#.#.....#...#.#..##...#.........#.................#.............#....#..#.......#......... +..#............#..#.....................#.................#............#.....##.#..#.#................#....................#...#... +..#.###.##.......................................##.............#..#...#...........#...#....#...........###......#............#.... +........#....#.......#.....................#...................................#...#.#.....#..............................#....#... +.#..#........#...#.....#.............##..#....#................#................................#.........#....#..............#.... +............#..........#............#...#.......#..#.#.#.......#....#...........#...#....#............................#.#.......... +............................................................#..................#..............#...............................#.... +.........#.....#......##........#......#.##..##............##.......................#.........................#....#............... +.#...#...#.#..#...#..............................#...................#..#....................##..........................#.##...... +.............#...#...........#......#..#..##...#......#....##.....#................##.........#...........................#........ +.................#..................#.........#....#...#..................##............#..#...#.................#..#...........#.. +...#...#..........#.........#.....#.........................#.#................#......##...............#............#......#....##. +.............#.................#.............#..#...#.............#.........#..#.#..#............##.............#...#.............. +......#.#........#........#...........#..##...................##....#.....................#..#.........#..........#.....##.....#.#. +...........#.#.............#.......#....#..........#.#...............#.#...##.............................................#........ +...............#........................#.....#.......#................#........#.......#.....#.......................##........... +......................................#...............................#..........#................#........#....................... +.............................#....#.....##.....#....#...#...........#....#.......##..#.................................#........... +............#.............#......#..#.#.##............#.............#.......#....................#....##........................... +..........#...........#..#.......#.........#.............#...................#.#..#..#....#........#...#........................... +.....................#........#............#.........#.........#..................#...#.........#..............#........#......#... +.................#.............#.#.#.#....#...#..#...................................................#......#...................... +........#........#....................#...##....#.#...#..#..#.......#.....#.....#....#............................................. +...#...................#.....#...................#......................#............#......#....#.#.........#.#................... +.#.......................#...#.....#.#....................#.......#............#............#........#............................. +...............#..#..#..............#...#..#...............#.##..................#.......#...........#....#....#...#..........#.... +...............#................................#..#............#....#....#.............#...............##..#......#............#.. +.........................#..............#.#..#....................#.#.#.....#...............#........#.##.#.......#................ +.#...........#.##..#...#.#...........#.......#...............................####....................##....#.........#.#........... +...................#...........#........#..#.........#............#..........#.........#...#....................................... +..............#..#...#..#..#.##............#..#..#.............##.##.#..#.......................#..........#..........#..#......... +........##...............##..#..#...........#.............#.#.................#..........#........................#.#...#.......... +..............#......#........#........#.#.........#..#.....#.....#..#...##...................#..........#.............#........... +.................#.......#....#.....................#....##...............##....................#......#....#..........#..#.#...... +.................................................................S................................................................. +.........#..##...#..#.........#.................................#.........#....#.#............#..#........#.......#.......#........ +...................#....#..#....#...#......#....#......#...........................#.............###...............#......#........ +...........#...............#........................#.#......#.#............#...#.#.................#....#...#...#................. +..................#...................#..#.........#...##..#...#...................#...#.....#.....#....#.......#.#................ +...............#..............#........#................................................#...#.#......#.#.........#....#............ +...............##.........#.....#....#................#.....#.#................#.......#................#.......................... +...........#.............#...#...................##................#.......#....#...#...........#.#................................ +.................#..............................#.....................#.....#...............#...#...................#.............. +..............................#.................#..........#............#.......#..............#.#................................. +...............#..............#....#............#......#...#.........#.......##............##...#..#..........................##... +..........................#.#...........#....#.........##..............##......#.........................#.....#................#.. +........#...................#..#...#.......................#..................#.#.............#..#.............#...........#....... +.............................#............#....#.....................#.....#..........#..##.............#.#......#.......#......... +....#.........................................#......##...#...........................##........#...#.#............................ +.....#.....................#..#....##..#..........#........................##.....#..........#................#.................... +.......................................#..#......#.#..##.....#...........#..#.......#.................#...#.................##..##. +....#.....#............#...#......#..............#...................#...........#.........#.........................#....##..##... +......#....#.................#.............#....#..#.....#........#.#........#.....#.#.#.#..#...................................... +.........#..........................................#..............##.......#........#...#..#............#.#.............#.#...#... +............#............#.....#..#............#..#.....#.....#....#....#..#............#................#..............#......#... +.###.........#....................................#.#..#......#...#.....#.......#..#.....#.....##.....##.............#....#.#...... +..###.......................#.......#..#..........#.............................#...............#..#..#.............##.......#..... +.#.......#...........................................#..#.................#........#.#...............#.....................#....... +.......#....#.....##...........#..#.............#........#..................#.......#.......#.........#......................#..... +.......#...#......#................#..#.#..........#.....................................##....#.............#......#..........##.. +.....###.#....#.#..................#........##.#........#...#..............#...........#......#.......................#....#.....#. +.#...........................................................#.#.......#..........#.#.......................#.......#.#......#..... +.....#.................................#....#...#.#.#....#...#....#....#....#.....##....#.............................#.#..#....... +.............#..#........#...........#.....#.......#..#....#..#...#.......................#....#...........#...............#....... +...##...#.##.....#............................#.....##.........................#..#.#...........#.............#........#........... +.........#..#........#..#..................#....#.#........#....#....##....#...........#...#............................#..#....... +..#....#..#.#......#.......#..............#.#............................#............#.................#.......#...###.....#.#.#.. +..#.......#.........###....#.........#........##....#......................#...........................#.....##.........#...#...... +.##.............#.........#...........#..................................#.....#....#....#.##...............#......#............... +.....#...........#...#......#..........#..................#..#..#.......................#.......................................... +.....#..................#..#..#............#..#...........#..#.......#........##...#..................#............................ +.....................#.......#...........#..........##........#...............#.#..#...................#........#..#....#.......... +.#.........#..#................#............#......#.......#.......#.....#..#.#.#..##..#..........#....##..#....................... +..................##..##..................................#................#.........#...........#....#.........#..#.#............. +.....#..#..............#......#................................#...........#...#...#............##...........................#..... +...#................##.........#.#...#............................#.#....#.#....#...#.........#.......#............#....#.#..#..#.. +.................#.......#.#......#.#............##........#................................#....#..#.............................. +...#................#................................#.##.#.##.......#...........#....................#......#..................... +.#.........#....#..........##........#.#..........#.#......#..#............##....#................#.......#.............#.......... +.................#....#..........#..................#........#.#..........#...............#.....#..#..............#............#.#. +...#..#.......#.......................#...........##.................#....#.....#............#........##.............#.....#..#.... +....#.............##............#...#..#....................#.......#.........#..............................#..................... +...#......................#.................#.............#............................#....#.............#......#...#............. +...#.........#........................................#..#.....##......#....##.......#..#........#...#..#.....#.#.............#..#. +..#.......#..................#..#.....#.....#.#.........#.....#......................#....##...............#..........#.....#...... +..................#..##........#....#...................#.......#..................#..#.......##................................... +.....#..#.#.#.#.....#........#.....................................#......#..........##........................#......#...#..#..... +...#.#.........##....#..#...................#............#.....##.............................##.........#.....#.............#..... +.#....#................#..........................................#............................#........#...##................#.#.. +.........#..........##...#........##.#....#.....#............#.....#..............#....#.#..#............##....#.....#.......##.... +.............##......#.................#........#..##...............#..........................#....#.......##........#........##.. +......#.....##.......#....................#..........#.........................#...#.......#...##..#..............#........#....... +..#..........#......#....#..............#.......................#...........#.....#................#....#.#.#...#.........#........ +.....##.#.#..#.#..............................#...#..##..........................#.#..............###.#............................ +.........#.....#...##.............#.........#.....#..........................#.....................................#..#..........#. +.#..##........................#........#............#..........................................#..#..........#.....#..#.....#...#.. +.............#..............#.##..............#........#..................##........#.........##.......#.#.....#..#......#..#.#.... +..........#....#.###...#........#..#......................................#......#..............#..............#................... +...........#..................#...........#..............................#....................#..#.................#............... +...................................................................................................................................