package aoc2023

import CharGrid
import println
import readInput
import kotlin.math.abs

/*
--- Day 11: Cosmic Expansion ---
https://adventofcode.com/2023/day/11
*/
fun main() {

    val inlineTestInput = """
...#......
.......#..
#.........
..........
......#...
.#........
.........#
..........
.......#..
#...#.....
"""

    fun parts(input: List<String>, exp: Int): Long {
        val image = CharGrid(input, '.')
        val exCol = IntArray(image.width)
        val exRow = IntArray(image.height)
        var ex = 0
        for (c in exCol.indices) {
            var hasGalaxies = false
            for (r in 0 until image.height) {
                if (image[c, r] == '#') hasGalaxies = true
            }
            if (!hasGalaxies) ex += exp
            exCol[c] = ex
        }
        ex = 0
        for (r in exRow.indices) {
            var hasGalaxies = false
            for (c in 0 until image.width) {
                if (image[c, r] == '#') hasGalaxies = true
            }
            if (!hasGalaxies) ex += exp
            exRow[r] = ex
        }
        val gal = image.findMatches { it == '#' }.map { it.first + exCol[it.first] to it.second + exRow[it.second] }.toTypedArray()
        var minSum = 0L
        var pairCount = 0
        for (g1 in 0 until gal.lastIndex) {
            for (g2 in g1 + 1..gal.lastIndex) {
                val d = abs(gal[g1].first - gal[g2].first) + abs(gal[g1].second - gal[g2].second)
                minSum += d
                pairCount++
            }
        }
        return minSum
    }

    // test if implementation meets criteria from the description, like:
    val testInput = inlineTestInput.trim().reader().readLines()
    //val testInput = readInput("aoc2023/Day11_test")
    val testInputPart1Result = parts(testInput, 1)
    println("Part 1 Test: $testInputPart1Result")
    val testInputPart2aResult = parts(testInput, 9)
    println("Part 2a Test: $testInputPart2aResult")
    val testInputPart2Result = parts(testInput, 99)
    println("Part 2 Test: $testInputPart2Result")
    check(testInputPart1Result == 374L)
    check(testInputPart2aResult == 1030L)
    check(testInputPart2Result == 8410L)

    val input = readInput("aoc2023/Day11")
    parts(input, 1).println()
    parts(input, 1000000 - 1).println()
}
