Skip to content

Commit b4ddc31

Browse files
committed
24 finally...
1 parent a726bb3 commit b4ddc31

File tree

6 files changed

+577
-23
lines changed

6 files changed

+577
-23
lines changed

.idea/workspace.xml

Lines changed: 39 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/kotlin/24.kt

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
fun main() {
2+
println(solve24a(readInputLines("24")))
3+
println(solve24b(readInputLines("24")))
4+
}
5+
6+
fun solve24a(lines: List<String>): Long {
7+
val (map, operations) = parseInput(lines)
8+
9+
for (op in sortOperations(operations)) {
10+
map[op.result] = op.execute(map[op.l]!!, map[op.r]!!)
11+
}
12+
13+
return combineValue(map, "z")
14+
}
15+
16+
fun solve24b(lines: List<String>): Boolean {
17+
val (map, operations) = parseInput(lines)
18+
19+
for (op in sortOperations(operations)) {
20+
map[op.result] = op.execute(map[op.l]!!, map[op.r]!!)
21+
}
22+
23+
val x = combineString(map, "x")
24+
val y = combineString(map, "y")
25+
val z = combineString(map, "z")
26+
val expected = (x.toLong(2) + y.toLong(2)).toString(2)
27+
28+
println("x: 0$x")
29+
println("y: 0$y")
30+
println("z: $z")
31+
println("e: $expected")
32+
33+
/**
34+
* Solved manually, answer:
35+
* mks XOR bhr -> vcv
36+
* x13 AND y13 -> z13
37+
*
38+
* vbw OR qkk -> z25
39+
* mqj XOR pqn -> mps
40+
*
41+
* csn AND nmn -> z19
42+
* csn XOR nmn -> vwp
43+
*
44+
* x33 AND y33 -> cqm
45+
* x33 XOR y33 -> vjv
46+
*
47+
* cqm,mps,vcv,vjv,vwp,z13,z19,z25
48+
*/
49+
50+
for (op in operations) {
51+
println("${op.l} -> ${op.result} [label=\"${op.toStringType()} ${op.r}\"];")
52+
println("${op.r} -> ${op.result} [label=\"${op.toStringType()} ${op.l}\"];")
53+
}
54+
55+
return expected == z
56+
}
57+
58+
private fun combineString(map: Map<String, Int>, prefix: String): String =
59+
map.entries.filter { it.key.startsWith(prefix) }.sortedByDescending { it.key }
60+
.joinToString(separator = "") { it.value.toString() }
61+
62+
private fun combineValue(map: Map<String, Int>, prefix: String): Long =
63+
map.entries.filter { it.key.startsWith(prefix) }.sortedByDescending { it.key }.map { it.value }
64+
.fold(0L) { result, b -> result * 2 + b }
65+
66+
private val OPERATION_LINE_REGEX = Regex("""^(\w+) (OR|XOR|AND) (\w+) -> (\w+)$""")
67+
68+
private data class Input24(val map: MutableMap<String, Int>, val operations: List<Operation>)
69+
70+
private fun parseInput(lines: List<String>): Input24 {
71+
val map = mutableMapOf<String, Int>()
72+
73+
var i = 0
74+
while (lines[i].isNotEmpty()) {
75+
val split = lines[i].split(": ")
76+
map[split[0]] = split[1].toInt()
77+
i += 1
78+
}
79+
80+
val operations = lines.drop(i + 1).map {
81+
val match = OPERATION_LINE_REGEX.find(it)
82+
checkNotNull(match)
83+
when (match.groupValues[2]) {
84+
"OR" -> OrOperation(match.groupValues[1], match.groupValues[3], match.groupValues[4])
85+
"XOR" -> XorOperation(match.groupValues[1], match.groupValues[3], match.groupValues[4])
86+
"AND" -> AndOperation(match.groupValues[1], match.groupValues[3], match.groupValues[4])
87+
else -> throw IllegalStateException()
88+
}
89+
}
90+
return Input24(map, operations)
91+
}
92+
93+
private sealed interface Operation {
94+
val l: String
95+
val r: String
96+
val result: String
97+
fun execute(a: Int, b: Int): Int
98+
}
99+
100+
private data class OrOperation(override val l: String, override val r: String, override val result: String) :
101+
Operation {
102+
override fun execute(a: Int, b: Int): Int = a.or(b)
103+
}
104+
105+
private data class AndOperation(override val l: String, override val r: String, override val result: String) :
106+
Operation {
107+
override fun execute(a: Int, b: Int): Int = a.and(b)
108+
}
109+
110+
private data class XorOperation(override val l: String, override val r: String, override val result: String) :
111+
Operation {
112+
override fun execute(a: Int, b: Int): Int = a.xor(b)
113+
}
114+
115+
private fun sortOperations(operations: List<Operation>): List<Operation> {
116+
val allNodes = operations.flatMap { listOf(it.l, it.r, it.result) }.toSet()
117+
val ns = mutableMapOf<String, Set<String>>()
118+
for (op in operations) {
119+
ns[op.l] = ns.getOrDefault(op.l, setOf()) + op.result
120+
ns[op.r] = ns.getOrDefault(op.r, setOf()) + op.result
121+
}
122+
123+
val visited = mutableSetOf<String>()
124+
val stack = ArrayDeque<String>()
125+
126+
fun dfs(node: String) {
127+
visited.add(node)
128+
for (n in ns.getOrDefault(node, setOf())) {
129+
if (n !in visited) {
130+
dfs(n)
131+
}
132+
}
133+
stack.addLast(node)
134+
}
135+
for (node in allNodes) {
136+
if (node !in visited) {
137+
dfs(node)
138+
}
139+
}
140+
141+
val nodeOrder: Map<String, Int> = stack.withIndex().associate { Pair(it.value, it.index) }
142+
143+
return operations.sortedByDescending { nodeOrder[it.result]!! }
144+
}
145+
146+
private fun Operation.toStringType() = when (this) {
147+
is OrOperation -> "OR"
148+
is XorOperation -> "XOR"
149+
is AndOperation -> "AND"
150+
}

0 commit comments

Comments
 (0)