package org.example.e3fxgaming.adventOfCode.aoc2023.day06

import org.example.e3fxgaming.adventOfCode.utility.Day
import org.example.e3fxgaming.adventOfCode.utility.InputParser
import org.example.e3fxgaming.adventOfCode.utility.MultiLineInputParser

class Day06(input: String) : Day<Pair<Int, Int>, Pair<Long, Long>> {
    override val partOneParser: InputParser<Pair<Int, Int>> = object : MultiLineInputParser<Pair<Int, Int>>(input) {
        override fun parseFullInput(fullInput: String): List<Pair<Int, Int>> =
            fullInput.split(System.lineSeparator()).map { lineString ->
                lineString.substringAfter(':').split(' ')
                    .filter { it.isNotEmpty() }.map { it.toInt() }
            }.let { (timeSteps, distanceSteps) -> timeSteps.zip(distanceSteps) }
    }
    override val partTwoParser: InputParser<Pair<Long, Long>> = object : MultiLineInputParser<Pair<Long, Long>>(input) {
        override fun parseFullInput(fullInput: String): List<Pair<Long, Long>> =
            fullInput.split(System.lineSeparator()).map { lineString ->
                lineString.substringAfter(':').replace(" ", "").toLong()
            }.zipWithNext()
    }


    override fun solveFirst(given: List<Pair<Int, Int>>): String =
        given.map { (time, distance) ->
            (0..time).count { windUpTime ->
                (windUpTime * (time - windUpTime)) > distance
            }
        }.reduce(Int::times).toString()

    override fun solveSecond(given: List<Pair<Long, Long>>): String {
        val (time, distance) = given.first()

        val firstPossible = (0..time).first { windUpTime ->
            (windUpTime * (time - windUpTime)) > distance
        }

        val lastPossible = (time downTo 0).first { windUpTime ->
            (windUpTime * (time - windUpTime)) > distance
        }

        return (lastPossible - firstPossible + 1).toString()
    }
}

fun main() = Day06(
    Day06::class.java.getResource("/2023/day06/realInput1.txt")!!.readText()
).runBoth()
package org.example.e3fxgaming.adventOfCode.aoc2023.day06

import org.example.e3fxgaming.adventOfCode.utility.Day
import org.example.e3fxgaming.adventOfCode.utility.InputParser
import org.example.e3fxgaming.adventOfCode.utility.MultiLineInputParser

class Day06(input: String) : Day<Pair<Int, Int>, Pair<Long, Long>> {
    override val partOneParser: InputParser<Pair<Int, Int>> = object : MultiLineInputParser<Pair<Int, Int>>(input) {
        override fun parseFullInput(fullInput: String): List<Pair<Int, Int>> =
            fullInput.split(System.lineSeparator()).map { lineString ->
                lineString.substringAfter(':').split(' ')
                    .filter { it.isNotEmpty() }.map { it.toInt() }
            }.let { (timeSteps, distanceSteps) -> timeSteps.zip(distanceSteps) }
    }
    override val partTwoParser: InputParser<Pair<Long, Long>> = object : MultiLineInputParser<Pair<Long, Long>>(input) {
        override fun parseFullInput(fullInput: String): List<Pair<Long, Long>> =
            fullInput.split(System.lineSeparator()).map { lineString ->
                lineString.substringAfter(':').replace(" ", "").toLong()
            }.zipWithNext()
    }


    override fun solveFirst(given: List<Pair<Int, Int>>): String =
        given.map { (time, distance) ->
            (0..time).count { windUpTime ->
                (windUpTime * (time - windUpTime)) > distance
            }
        }.reduce(Int::times).toString()

    override fun solveSecond(given: List<Pair<Long, Long>>): String {
        val (time, distance) = given.first()

        val firstPossible = (0..time).first { windUpTime ->
            (windUpTime * (time - windUpTime)) > distance
        }

        val lastPossible = (time downTo 0).first { windUpTime ->
            (windUpTime * (time - windUpTime)) > distance
        }

        return (lastPossible - firstPossible + 1).toString()
    }
}

fun main() = Day06(
    Day06::class.java.getResource("/2023/day06/realInput1.txt")!!.readText()
).runBoth()