diff --git a/2024/src/main/kotlin/aoc/year2024/Day24.kt b/2024/src/main/kotlin/aoc/year2024/Day24.kt new file mode 100644 index 0000000..b98e1d8 --- /dev/null +++ b/2024/src/main/kotlin/aoc/year2024/Day24.kt @@ -0,0 +1,66 @@ +package aoc.year2024 + +import aoc.library.Puzzle + +object Day24 : Puzzle(day = 24) { + + override fun solvePart1(input: String): Long { + val (wiresValue, gatesValue) = input.split("\n\n") + val wires = wiresValue.lines().associate { + val (name, value) = it.split(": ") + name to (value == "1") + }.toMutableMap() + val gates = gatesValue.lines().map(Gate::parse) + + while (true) { + val solvableGate = gates.firstOrNull { gate -> + gate.left in wires && gate.right in wires && gate.output !in wires + } ?: break + wires[solvableGate.output] = solvableGate.operator(wires.getValue(solvableGate.left), wires.getValue(solvableGate.right)) + } + + return wires.filterKeys { it.startsWith("z") } + .toSortedMap() + .values + .reversed() + .joinToString("") { + if (it) "1" else "0" + } + .toLong(2) + } + + data class Gate(val left: String, val right: String, val operator: Operator, val output: String) { + companion object { + // ntg XOR fgs -> mjb + fun parse(input: String): Gate { + val elements = input.split(" ") + return Gate(elements[0], elements[2], Operator.parse(elements[1]), elements[4]) + } + } + } + + enum class Operator { + Xor, + Or, + And, + ; + + operator fun invoke( + left: Boolean, + right: Boolean, + ): Boolean = when (this) { + Xor -> left xor right + Or -> left or right + And -> left and right + } + + companion object { + fun parse(input: String): Operator = entries.find { it.name.equals(input, ignoreCase = true) } + ?: error("Invalid operator=$input") + } + } + + override fun solvePart2(input: String): Long { + TODO() + } +} diff --git a/2024/src/test/kotlin/aoc/year2024/Day24Test.kt b/2024/src/test/kotlin/aoc/year2024/Day24Test.kt new file mode 100644 index 0000000..c37dcd3 --- /dev/null +++ b/2024/src/test/kotlin/aoc/year2024/Day24Test.kt @@ -0,0 +1,96 @@ +package aoc.year2024 + +import aoc.library.solvePart1 +import aoc.library.solvePart2 +import io.kotest.matchers.longs.shouldBeExactly +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Disabled +import org.junit.jupiter.api.Test + +class Day24Test { + + @Test + fun part1TestInput() { + Day24.solvePart1( + """ + x00: 1 + x01: 0 + x02: 1 + x03: 1 + x04: 0 + y00: 1 + y01: 1 + y02: 1 + y03: 1 + y04: 1 + + ntg XOR fgs -> mjb + y02 OR x01 -> tnw + kwq OR kpj -> z05 + x00 OR x03 -> fst + tgd XOR rvg -> z01 + vdt OR tnw -> bfw + bfw AND frj -> z10 + ffh OR nrd -> bqk + y00 AND y03 -> djm + y03 OR y00 -> psh + bqk OR frj -> z08 + tnw OR fst -> frj + gnj AND tgd -> z11 + bfw XOR mjb -> z00 + x03 OR x00 -> vdt + gnj AND wpb -> z02 + x04 AND y00 -> kjc + djm OR pbm -> qhw + nrd AND vdt -> hwm + kjc AND fst -> rvg + y04 OR y02 -> fgs + y01 AND x02 -> pbm + ntg OR kjc -> kwq + psh XOR fgs -> tgd + qhw XOR tgd -> z09 + pbm OR djm -> kpj + x03 XOR y03 -> ffh + x00 XOR y04 -> ntg + bfw OR bqk -> z06 + nrd XOR fgs -> wpb + frj XOR qhw -> z04 + bqk OR frj -> z07 + y03 OR x01 -> nrd + hwm AND bqk -> z03 + tgd XOR rvg -> z12 + tnw OR pbm -> gnj + """.trimIndent(), + ) shouldBeExactly 2024 + } + + @Test + fun gateParsing() { + Day24.Gate.parse("le XOR ri -> out") + .shouldBe( + Day24.Gate( + left = "le", + right = "ri", + output = "out", + operator = Day24.Operator.Xor, + ), + ) + } + + @Test + fun part1() { + Day24.solvePart1() shouldBeExactly 48063513640678 + } + + @Test + @Disabled + fun part2TestInput() { + Day24.solvePart2() shouldBeExactly 42 + } + + @Test + @Disabled + fun part2() { + Day24.solvePart2() shouldBeExactly 42 + } +}