package aoc2023

import println
import readInput

/*
--- Day 18: Lavaduct Lagoon ---
https://adventofcode.com/2023/day/18
*/
fun main() {

    val inlineTestInput = """
R 6 (#70c710)
D 5 (#0dc571)
L 2 (#5713f0)
D 2 (#d2c081)
R 2 (#59c680)
D 2 (#411b91)
L 5 (#8ceee2)
U 2 (#caa173)
L 1 (#1b58a2)
U 2 (#caa171)
R 2 (#7807d2)
U 3 (#a77fa3)
L 2 (#015232)
U 2 (#7a21e3)
"""

    data class DigInst(val cmd: String, val len: Int)

    fun calcArea(insts: List<DigInst>): Long {
        val polygon = ArrayList<Pair<Long, Long>>()
        var x = 0L
        var y = 0L
        var sumOutline = 0L
        for (i in insts) {
            when (i.cmd) {
                "R" -> x += i.len
                "D" -> y += i.len
                "L" -> x -= i.len
                "U" -> y -= i.len
            }
            sumOutline += i.len
            polygon.add(x to y)
        }
        var area = 0L
        for (i in 0 until polygon.size) {
            val j = (i + 1) % polygon.size
            area += (polygon[i].second + polygon[j].second) * (polygon[i].first - polygon[j].first)
        }
        return (area + sumOutline) / 2 + 1
    }

    fun part1(input: List<String>): Long {
        val insts = input.map {
            val (cmd, len, color) = "([RDLU]) (\\d+) \\(#([a-z0-f]+)\\)".toRegex().matchEntire(it)!!.destructured
            DigInst(cmd, len.toInt())
        }
        return calcArea(insts)
    }

    fun part2(input: List<String>): Long {
        val insts = input.map {
            val (cmd, len, color) = "([RDLU]) (\\d+) \\(#([a-z0-f]+)\\)".toRegex().matchEntire(it)!!.destructured
            DigInst("RDLU"[(color.toInt(16) and 3)].toString(), color.toInt(16) shr 4)
        }
        return calcArea(insts)
    }

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

    val input = readInput("aoc2023/Day18")
    part1(input).println()
    part2(input).println()
}
