package aoc2024

import CharGrid
import println
import readInput

/*
--- Day 14: Restroom Redoubt ---
https://adventofcode.com/2024/day/14
*/
fun main() {

    val inlineTestInput = """
p=0,4 v=3,-3
p=6,3 v=-1,-3
p=10,3 v=-1,2
p=2,0 v=2,-1
p=0,0 v=1,3
p=3,0 v=-2,-2
p=7,6 v=-1,-3
p=3,0 v=-1,-2
p=9,3 v=2,3
p=7,3 v=-1,2
p=2,4 v=2,-3
p=9,5 v=-3,-3
"""

    fun part1(input: List<String>, time: Int, w: Int, h: Int): Int {
        val robots = input.map { "p=(\\d+),(\\d+) v=(-?\\d+),(-?\\d+)".toRegex().find(it)!!.groupValues.drop(1).map { it.toInt() }.toIntArray() }
        for (r in robots) {
            r[0] = (r[0] + time * (r[2] + w)) % w
            r[1] = (r[1] + time * (r[3] + h)) % h
        }
        val q1 = robots.count { it[0] < w / 2 && it[1] < h / 2 }
        val q2 = robots.count { it[0] > w / 2 && it[1] < h / 2 }
        val q3 = robots.count { it[0] < w / 2 && it[1] > h / 2 }
        val q4 = robots.count { it[0] > w / 2 && it[1] > h / 2 }
        return q1 * q2 * q3 * q4
    }

    fun part2(input: List<String>, w: Int, h: Int): Int {
        val robots = input.map { "p=(\\d+),(\\d+) v=(-?\\d+),(-?\\d+)".toRegex().find(it)!!.groupValues.drop(1).map { it.toInt() }.toIntArray() }
        /*
          either: 1) x == w/2 -+ c, y == c c in [0..w/2]
          or    : 2) x == w/2, y in (w/2..h)

          1) px + t * (vx + w) % w = w/2 - c; py + t * (vy + h) % h = c
             px + t * (vx + w) % w = w/2 - (py + t * (vy + h) % h)
             (px - py) + t * (((vx + w) % w) - ((vy + h) % h)) = w/2

          2) px == w/2, py > w/2 % h
         */
        val z = Array(robots.size) { IntArray(4) }
        for (t in 1..w * h) {
            /*val good = robots.all {
                val x = ((it[0] + t * (it[2] + w)) % w).toInt()
                val y = ((it[1] + t * (it[3] + h)) % h).toInt()
                (y <= w / 2 && ((x >= w / 2 - y) && (x <= w / 2 + y))) || (x == w / 2 && y > w / 2)
            }
            if (!good) continue*/
            for ((i, r) in robots.withIndex()) {
                z[i][0] = ((r[0] + t * (r[2] + w)) % w).toInt()
                z[i][1] = ((r[1] + t * (r[3] + h)) % h).toInt()
            }
            if (z.map { it[0] to it[1] }.distinct().count() < robots.size) continue
            println("Solution $t")
            val grid = CharGrid(w, h, '.')
            z.forEach { grid[it[0], it[1]] = '*' }
            grid.debug()
            println()
            return t
        }
        return 0
    }

    // test if implementation meets criteria from the description, like:
    val testInput = inlineTestInput.trim().reader().readLines()
    //val testInput = readInput("aoc2024/Day14_test")
    val testInputPart1Result = part1(testInput, 100, 11, 7)
    println("Part 1 Test: $testInputPart1Result")
    //val testInputPart2Result = part2(testInput, 11, 7)
    //println("Part 2 Test: $testInputPart2Result")
    check(testInputPart1Result == 12)
    //check(testInputPart2Result == 0)

    val input = readInput("aoc2024/Day14")
    part1(input, 100, 101, 103).println()
    part2(input, 101, 103).println()
}
