Skip to content

Commit 2108f2f

Browse files
committed
Day 24, part two: A Kotlin Notebook to generate a .dot file from the input
That file can be rendered using Graphviz (DOT, https://graphviz.org). The currently generated output is committed as `wiredGates.dot`.
1 parent 662f3c0 commit 2108f2f

File tree

2 files changed

+1047
-0
lines changed

2 files changed

+1047
-0
lines changed
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
{
2+
"cells": [
3+
{
4+
"metadata": {},
5+
"cell_type": "markdown",
6+
"source": [
7+
"# Plot CrossedWires\n",
8+
"\n",
9+
"This Kotlin Notebook uses the `CrossedWires` implementation from the main source set and writes the original input's wiring to a \".dot\" file, `wiredGates.dot`. That file can be rendered using GraphViz (DOT, https://graphviz.org)."
10+
]
11+
},
12+
{
13+
"metadata": {},
14+
"cell_type": "markdown",
15+
"source": "First, read and parse the input for lists of `Gate`s and `Wire`s."
16+
},
17+
{
18+
"metadata": {
19+
"ExecuteTime": {
20+
"end_time": "2025-06-19T15:02:31.995940700Z",
21+
"start_time": "2025-06-19T15:02:31.823908Z"
22+
}
23+
},
24+
"cell_type": "code",
25+
"source": [
26+
"import de.ronny_h.aoc.AdventOfCode\n",
27+
"import de.ronny_h.aoc.year24.day24.CrossedWires\n",
28+
"\n",
29+
"val crossedWires = CrossedWires()\n",
30+
"val input = crossedWires.readInput()\n",
31+
"val gates = crossedWires.parseGates(input)\n",
32+
"val wires = crossedWires.parseWires(input)"
33+
],
34+
"outputs": [],
35+
"execution_count": 1
36+
},
37+
{
38+
"metadata": {},
39+
"cell_type": "markdown",
40+
"source": "Add IDs to the Gates and Wires and construct some maps for fast lookup."
41+
},
42+
{
43+
"metadata": {
44+
"ExecuteTime": {
45+
"end_time": "2025-06-19T15:02:32.853145900Z",
46+
"start_time": "2025-06-19T15:02:32.001943800Z"
47+
}
48+
},
49+
"cell_type": "code",
50+
"source": [
51+
"data class GateWithId(val id: String, val in1: String, val in2: String, val op: String, val out: String)\n",
52+
"data class WireWithId(val id: String, val name: String)\n",
53+
"\n",
54+
"val gatesWithId = gates.mapIndexed { i, g -> GateWithId(\"$i\", g.in1, g.in2, g.operation.toString(), g.out) }\n",
55+
"val wiresWithId = wires.mapIndexed { i, w -> WireWithId(\"${i + gates.size}\", w.name) }\n",
56+
"val gatesOutLookup = gatesWithId.associateBy { it.out }\n",
57+
"val gatesInLookup = gatesWithId.fold(emptyMap<String, GateWithId>()) { acc, gate ->\n",
58+
" (acc + (gate.in1 to gate)) + (gate.in2 to gate)\n",
59+
"}\n",
60+
"val wiresLookup = wiresWithId.associateBy { it.name }"
61+
],
62+
"outputs": [],
63+
"execution_count": 2
64+
},
65+
{
66+
"metadata": {},
67+
"cell_type": "markdown",
68+
"source": [
69+
"Construct a pair of lists so that for each index `i` in both lists there is a wiring from `first[i]` to `second[i]`.\n",
70+
"\n",
71+
"`first` is a list of IDs of input wires or gates, `second` is a list of IDs of gates or output wires."
72+
]
73+
},
74+
{
75+
"metadata": {
76+
"ExecuteTime": {
77+
"end_time": "2025-06-19T15:02:33.181162100Z",
78+
"start_time": "2025-06-19T15:02:32.861150Z"
79+
}
80+
},
81+
"cell_type": "code",
82+
"source": [
83+
"fun wireTheGates(): Pair<List<String>, List<String>> {\n",
84+
" val from = mutableListOf<String>()\n",
85+
" val to = mutableListOf<String>()\n",
86+
"\n",
87+
" fun wireInput(gateId: String, inWireName: String) {\n",
88+
" val inGate = gatesOutLookup.get(inWireName)\n",
89+
" if (inGate == null) {\n",
90+
" // in is a wire\n",
91+
" from.add(wiresLookup.getValue(inWireName).id)\n",
92+
" } else {\n",
93+
" // in is another gate\n",
94+
" from.add(inGate.id)\n",
95+
" }\n",
96+
" to.add(gateId)\n",
97+
" }\n",
98+
"\n",
99+
" fun wireOutput(gateId: String, outWireName: String) {\n",
100+
" if (gatesInLookup.get(outWireName) == null) {\n",
101+
" // output is a wire; other gates are handled via wireInput()\n",
102+
" from.add(gateId)\n",
103+
" to.add(outWireName)\n",
104+
" }\n",
105+
" }\n",
106+
"\n",
107+
" for (g in gatesWithId) {\n",
108+
" wireInput(g.id, g.in1)\n",
109+
" wireInput(g.id, g.in2)\n",
110+
" wireOutput(g.id, g.out)\n",
111+
" check(from.size == to.size) { \"different sizes: from: '$from', to: $to\" }\n",
112+
" }\n",
113+
" return from to to\n",
114+
"}\n",
115+
"\n",
116+
"val wiredGateIds = wireTheGates()"
117+
],
118+
"outputs": [],
119+
"execution_count": 3
120+
},
121+
{
122+
"metadata": {},
123+
"cell_type": "markdown",
124+
"source": "Write the data to a .dot file that can be interpreted by Graphviz."
125+
},
126+
{
127+
"metadata": {
128+
"ExecuteTime": {
129+
"end_time": "2025-06-19T15:02:33.970587700Z",
130+
"start_time": "2025-06-19T15:02:33.192162900Z"
131+
}
132+
},
133+
"cell_type": "code",
134+
"source": [
135+
"import java.io.File\n",
136+
"\n",
137+
"File(\"wiredGates.dot\").printWriter().use { out ->\n",
138+
" out.println(\"digraph {\")\n",
139+
" val gatesCount = gatesWithId.size\n",
140+
" val outWires = gatesWithId.filter { gatesInLookup[it.out] == null }.map { it.out }\n",
141+
" val inXColor = \"\\\"#4A88D4\\\"\"\n",
142+
" val inYColor = \"\\\"#784AD4\\\"\"\n",
143+
" val outZColor = \"\\\"#48B540\\\"\"\n",
144+
"\n",
145+
" wiresWithId.forEach { wire ->\n",
146+
" val color = when {\n",
147+
" wire.name.startsWith(\"x\") -> inXColor\n",
148+
" wire.name.startsWith(\"y\") -> inYColor\n",
149+
" wire.name.startsWith(\"z\") -> outZColor\n",
150+
" else -> \"grey\"\n",
151+
" }\n",
152+
" out.println(\" ${wire.id} [label=${wire.name} fontcolor=$color color=$color]\")\n",
153+
" }\n",
154+
" outWires.forEach {\n",
155+
" out.println(\" ${it} [label=${it} fontcolor=$outZColor color=$outZColor]\")\n",
156+
" }\n",
157+
" gatesWithId.forEach { gate ->\n",
158+
" out.println(\" ${gate.id} [label=\\\"${gate.op}\\\"]\")\n",
159+
" }\n",
160+
"\n",
161+
" wiredGateIds.first.forEachIndexed { i, fromId ->\n",
162+
" val toId = wiredGateIds.second[i]\n",
163+
" out.println(\" $fromId -> $toId\")\n",
164+
" }\n",
165+
"\n",
166+
" out.println(\"}\")\n",
167+
"}"
168+
],
169+
"outputs": [],
170+
"execution_count": 4
171+
}
172+
],
173+
"metadata": {
174+
"kernelspec": {
175+
"display_name": "Kotlin",
176+
"language": "kotlin",
177+
"name": "kotlin"
178+
},
179+
"language_info": {
180+
"name": "kotlin",
181+
"version": "1.9.23",
182+
"mimetype": "text/x-kotlin",
183+
"file_extension": ".kt",
184+
"pygments_lexer": "kotlin",
185+
"codemirror_mode": "text/x-kotlin",
186+
"nbconvert_exporter": ""
187+
},
188+
"ktnbPluginMetadata": {
189+
"projectLibraries": false,
190+
"projectDependencies": [
191+
"kotlin-advent-of-code-2024.main"
192+
]
193+
}
194+
},
195+
"nbformat": 4,
196+
"nbformat_minor": 0
197+
}

0 commit comments

Comments
 (0)