aoc2024

Advent of Code 2024
Log | Files | Refs | README

Day6.scala (2843B)


      1 import scala.annotation.tailrec
      2 def day6_pt1(input: Iterator[String]): Int =
      3     val lst = input.toList
      4     val pos = lst.zipWithIndex.find((s, y) => s.contains("^")).map((s, y) => (s.indexOf('^'), y)).get
      5     val grid = updated(lst, pos, '.')
      6     val grid2 = do_follow(grid, pos, '^')
      7     grid2.map(line => line.count(ch => ch == 'X')).sum
      8 
      9 @tailrec()
     10 def do_follow(grid: List[String], pos: (Int,Int), dir: Char): List[String] =
     11     val grid2 = updated(grid, pos, 'X')
     12     val pos2 = next_pos(pos, dir)
     13     val (x2, y2) = pos2
     14     if (oob(grid2, pos2)) {
     15         return grid2
     16     }
     17     if (grid_at(grid2, pos2) == '#') {
     18         val dir2 = next_dir(dir)
     19         do_follow(grid2, pos, dir2)
     20     } else {
     21         do_follow(grid2, pos2, dir)
     22     }
     23 
     24 def day6_pt2(input: Iterator[String]): Int =
     25     val lst = input.toList
     26     val pos = lst.zipWithIndex.find((s, y) => s.contains("^")).map((s, y) => (s.indexOf('^'), y)).get
     27     val grid = updated(lst, pos, '.')
     28     val grid2 = do_follow(grid, pos, '^')
     29     List.range(0, grid.size).flatMap(y => List.range(0, grid(0).size).map(x => (x, y)))
     30         .filter(block => block != pos) // Can't add a block where the guard currenly is... 
     31         .filter(block => grid_at(grid2, block) == 'X') // only bother testing locations the guard actually visited; otherwise it's an ineffective block
     32         .filter(block => {
     33             val res = do_follow3(updated(grid, block, '#'), pos, '^', Set())
     34             println(s"Testing new block at $block: $res")
     35             res
     36         })
     37         .size
     38 
     39 @tailrec()
     40 def do_follow3(grid: List[String], pos: (Int,Int), dir: Char, hist: Set[((Int,Int), Char)]): Boolean =
     41     if (hist.contains(pos, dir)) {
     42         return true
     43     }
     44     val pos2 = next_pos(pos, dir)
     45     if (oob(grid, pos2)) {
     46         return false
     47     } 
     48 
     49     if (grid_at(grid, pos2) == '#') {
     50         do_follow3(grid, pos, next_dir(dir), hist + ((pos, dir)))
     51     } else {
     52         do_follow3(grid, pos2, dir, hist + ((pos, dir)))
     53     }
     54 
     55 // def print(grid: List[String]): Unit =
     56 //     grid.foreach(line => println(line))
     57 
     58 def grid_at(grid: List[String], pos: (Int, Int)): Char =
     59     grid(pos(1)).charAt(pos(0))
     60 
     61 def updated(grid: List[String], pos: (Int,Int), replacement: Char): List[String] =
     62     val (x, y) = pos
     63     return grid.updated(y, grid(y).updated(x, replacement))    
     64 
     65 def next_pos(pos: (Int,Int), dir: Char): (Int,Int) =
     66     dir match
     67         case '^' => (pos(0), pos(1)-1)
     68         case '>' => (pos(0)+1, pos(1))
     69         case 'v' => (pos(0), pos(1)+1)
     70         case '<' => (pos(0)-1, pos(1))
     71 
     72 def next_dir(dir: Char): Char =
     73     dir match
     74             case '^' => '>'
     75             case '>' => 'v'
     76             case 'v' => '<'
     77             case '<' => '^'
     78 
     79 def oob(grid: List[String], pos: (Int,Int)): Boolean =
     80     val (x, y) = pos
     81     x < 0 || y < 0 || x >= grid(0).size || y >= grid.size