Skip to content

Commit

Permalink
Finished 2024 day24 both parts
Browse files Browse the repository at this point in the history
  • Loading branch information
tymscar committed Dec 24, 2024
1 parent c938946 commit 86f9710
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 3 deletions.
2 changes: 2 additions & 0 deletions 2024/kotlin/src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import com.tymscar.day20.solve as day20
import com.tymscar.day21.solve as day21
import com.tymscar.day22.solve as day22
import com.tymscar.day23.solve as day23
import com.tymscar.day24.solve as day24

fun main() {
day01()
Expand All @@ -48,4 +49,5 @@ fun main() {
day21()
day22()
day23()
day24()
}
44 changes: 42 additions & 2 deletions 2024/kotlin/src/main/kotlin/com/tymscar/day24/part1/part1.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
package com.tymscar.day24.part1

fun solve(input: String): String {
return input

private enum class Gate { AND, OR, XOR, INPUT }
private data class Wire(val name: String, val value: Boolean?, val gate: Gate, val input1: String?, val input2: String?)
private typealias Circuit = MutableMap<String, Wire>
private fun Circuit.run() = this.keys
.filter { Regex("""z\d+""").matches(it) }
.sortedDescending()
.map { if (getWireValue(this, it)) 1 else 0 }
.joinToString("")
.toLong(2)
.toString()

private fun getCircuit(input: String): Circuit {
val circuit = Regex("""(\w+): (\d)""").findAll(input).map {
val (name, value) = it.destructured
name to Wire(name, value == "1", Gate.INPUT, null, null)
}.toMap().toMutableMap()

Regex("""(\w+) (AND|OR|XOR) (\w+) -> (\w+)""").findAll(input).forEach {
val (input1, gate, input2, output) = it.destructured
circuit[output] = Wire(output, null, Gate.valueOf(gate), input1, input2)
}

return circuit
}

private fun getWireValue(circuit: Circuit, wire: String): Boolean {
val wireValue = circuit[wire]?.value
if (wireValue != null) return wireValue

val wire = circuit[wire]!!
val value = when (wire.gate) {
Gate.INPUT -> wire.value!!
Gate.AND -> getWireValue(circuit, wire.input1!!) and getWireValue(circuit, wire.input2!!)
Gate.OR -> getWireValue(circuit, wire.input1!!) or getWireValue(circuit, wire.input2!!)
Gate.XOR -> getWireValue(circuit, wire.input1!!) xor getWireValue(circuit, wire.input2!!)
}

circuit[wire.name] = Wire(wire.name, value, wire.gate, wire.input1, wire.input2)
return value
}

fun solve(input: String) = getCircuit(input).run()
97 changes: 96 additions & 1 deletion 2024/kotlin/src/main/kotlin/com/tymscar/day24/part2/part2.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,100 @@
package com.tymscar.day24.part2


private enum class Gate { AND, OR, XOR, INPUT }
private data class Wire(var name: String, var value: Boolean?, val gate: Gate, val input1: String?, val input2: String?)
private typealias Circuit = MutableList<Wire>

private fun Circuit.run() = this
.filter { Regex("""z\d+""").matches(it.name) }
.sortedByDescending { it.name }
.map { if (getWireValue(this, it)) 1 else 0 }
.joinToString("")
.toLong(2)

private fun getCircuit(input: String): Circuit {
val circuit = Regex("""(\w+): (\d)""").findAll(input).map {
val (name, value) = it.destructured
Wire(name, value == "1", Gate.INPUT, null, null)
}.toMutableList()

Regex("""(\w+) (AND|OR|XOR) (\w+) -> (\w+)""").findAll(input).forEach {
val (input1, gate, input2, output) = it.destructured
circuit.add(Wire(output, null, Gate.valueOf(gate), input1, input2))
}

return circuit
}

private fun getWireValue(circuit: Circuit, wire: Wire): Boolean {
if (wire.value != null) return wire.value!!

val input1 = circuit.find { inputWire -> inputWire.name == wire.input1 }
val input2 = circuit.find { inputWire -> inputWire.name == wire.input2 }
val value = when (wire.gate) {
Gate.INPUT -> wire.value
Gate.AND -> getWireValue(circuit, input1!!) and getWireValue(circuit, input2!!)
Gate.OR -> getWireValue(circuit, input1!!) or getWireValue(circuit, input2!!)
Gate.XOR -> getWireValue(circuit, input1!!) xor getWireValue(circuit, input2!!)
}

wire.value = value
return value!!
}

private fun findFirstOutputFrom(circuit: Circuit, wire: String): String? {
val parents = circuit.filter { it.input1 == wire || it.input2 == wire }

val validOutput = parents.find { it.name.first() == 'z' }
if (validOutput == null) return parents.firstNotNullOfOrNull { findFirstOutputFrom(circuit, it.name) }

val previousOutputNumber = validOutput.name.drop(1).toInt() - 1
return "z" + previousOutputNumber.toString().padStart(2, '0')
}

private fun interpretWireAsNumber(start: Char, circuit: Circuit) = circuit
.filter { it.name.first() == start }
.sortedByDescending(Wire::name)
.map { if (it.value!!) '1' else '0' }
.joinToString("")
.toLong(2)

fun solve(input: String): String {
return input
val circuit = getCircuit(input)
val invalidEndWires = circuit.filter {
it.name.first() == 'z' && it.name != "z45" && it.gate != Gate.XOR
}

val invalidMidWires = circuit.filter {
it.name.first() != 'z'
&& it.input1?.first() != 'x' && it.input1?.first() != 'y'
&& it.input2?.first() != 'x' && it.input2?.first() != 'y'
&& it.gate == Gate.XOR
}

invalidMidWires.forEach { wire ->
val toSwitch = invalidEndWires.first { it.name == findFirstOutputFrom(circuit, wire.name) }
val temp = wire.name
wire.name = toSwitch.name
toSwitch.name = temp
}

val xInput = interpretWireAsNumber('x', circuit)
val yInput = interpretWireAsNumber('y', circuit)

val diffFromActual = xInput + yInput xor circuit.run()
val zeroBits = diffFromActual
.countTrailingZeroBits()
.toString()
.padStart(2, '0')

val invalidCarryWires = circuit.filter {
it.input1?.endsWith(zeroBits.toString()) == true
&& it.input2?.endsWith(zeroBits.toString()) == true
}

return (invalidEndWires + invalidMidWires + invalidCarryWires)
.map { it.name }
.sorted()
.joinToString(",")
}

0 comments on commit 86f9710

Please sign in to comment.