package aoc2025

import CharGrid
import println
import readInput

/*
--- Day 7: Laboratories ---
https://adventofcode.com/2025/day/7
*/
fun main() {

    val inlineTestInput = """
.......S.......
...............
.......^.......
...............
......^.^......
...............
.....^.^.^.....
...............
....^.^...^....
...............
...^.^...^.^...
...............
..^...^.....^..
...............
.^.^.^.^.^...^.
...............
"""

    val memo = ArrayList<HashMap<Int, Long>>()

    fun part1(input: List<String>): Int {
        val grid = CharGrid(input)
        var splits = 0
        for (row in 2 until grid.height step 2) {
            for (col in 1 until grid.width - 1) {
                val ch = grid[col, row - 2]
                if (ch == 'S') {
                    if (grid[col, row] == '^') {
                        grid[col - 1, row] = 'S'
                        grid[col + 1, row] = 'S'
                        splits++
                    } else {
                        grid[col, row] = 'S'
                    }
                }
            }
        }
        return splits
    }

    fun rec(grid: CharGrid, col: Int, row: Int): Long {
        if (row >= grid.height) return 1
        return memo[row / 2].getOrPut(col) {
            if (grid[col, row + 2] == '^')
                rec(grid, col - 1, row + 2) + rec(grid, col + 1, row + 2)
            else
                rec(grid, col, row + 2)
        }
    }

    fun part2(input: List<String>): Long {
        val grid = CharGrid(input)
        val col = grid.collectMatches { it == 'S' }.single().second.dc
        while (memo.size <= grid.height / 2) memo.add(HashMap())
        return rec(grid, col, 0)
    }

    // test if implementation meets criteria from the description, like:
    val testInput = inlineTestInput.trim().reader().readLines()
    //val testInput = readInput("aoc2025/Day07_test")
    val testInputPart1Result = part1(testInput)
    println("Part 1 Test: $testInputPart1Result")
    val testInputPart2Result = part2(testInput)
    println("Part 2 Test: $testInputPart2Result")
    check(testInputPart1Result == 21)
    check(testInputPart2Result == 40L)

    val input = readInput("aoc2025/Day07")
    part1(input).println()
    part2(input).println()
}
