diff --git a/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb b/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb index 228a06c..79c8170 100644 --- a/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb +++ b/src/AoC_2024/Dazbo's_Advent_of_Code_2024.ipynb @@ -9215,7 +9215,20 @@ "- Generates a single _sum_ output.\n", "- Generates a single carry output (Cout).\n", "\n", - "A single adder looks like this:\n", + "So we can think of an adder as taking 3 inputs and having two outputs. One output is the sum of binary digits for this _column_, and the other output is the carry-over digit, to be added to the next column.\n", + "\n", + "For example, if we want to add two 1-bit numbers like this:\n", + "\n", + "```text\n", + "\n", + "Carry 1 0\n", + "Input x 1\n", + "Input y 1\n", + " ---\n", + "Result 0\n", + "```\n", + "\n", + "A single adder can be depicted like this:\n", "\n", "\"Full\n", "\n", @@ -9223,14 +9236,14 @@ "\n", "\"Ripple\n", "\n", - "Let's turn our input data into single line readable instructions, for each output. We can use this to look for anomalies.\n", + "And this is how we can generate a single 5-bit number from the addition of two 4-bit numbers.\n", "\n", - "And we can visualise it too.\n" + "How do we relate this to the problem? Well, to implement each adder in the ripple carry adder, we need to combine a number of gates. There are a couple of ways this can be done. So let's actually visualise what our instructions are doing, and then we'll know..." ] }, { "cell_type": "code", - "execution_count": 79, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -9265,10 +9278,23 @@ " \n", "def create_vis(wires: dict):\n", " dot = graphviz.Digraph(format='png', engine='dot')\n", - "\n", + " \n", + " # Define gate shapes, colors, and output styles\n", + " gate_styles = {\n", + " \"AND\": {\"shape\": \"invtrapezium\", \"fillcolor\": \"lightblue\"},\n", + " \"OR\": {\"shape\": \"invtriangle\", \"fillcolor\": \"lightgreen\"},\n", + " \"XOR\": {\"shape\": \"box\", \"fillcolor\": \"lightyellow\"},\n", + " }\n", + " output_styles = {\n", + " \"z\": {\"fillcolor\": \"black\", \"fontcolor\": \"white\"},\n", + " \"x\": {\"fillcolor\": \"blue\", \"fontcolor\": \"white\"},\n", + " \"y\": {\"fillcolor\": \"red\", \"fontcolor\": \"white\"},\n", + " }\n", + " \n", " # Add operand nodes (inputs/outputs) as circles\n", " for wire in wires:\n", - " dot.node(wire, wire, shape='circle') # Circle shape for operands\n", + " style = output_styles.get(wire[0], {}) # Get style based on first character\n", + " dot.node(wire, wire, shape='circle', style='filled', **style)\n", "\n", " # Add operations as nodes (gates as boxes)\n", " for output in op_by_ouput:\n", @@ -9277,14 +9303,20 @@ " # Create gate node in a box\n", " gate_label = f'{gate}'\n", " gate_name = f'{left}_{right}_{gate}' # Unique gate name\n", - " dot.node(gate_name, gate_label, shape='box') # Box shape for operators\n", + " gate_style = gate_styles.get(gate, {\"shape\": \"box\"})\n", + " dot.node(gate_name, gate_label, style='filled', **gate_style) # Box shape for operators\n", "\n", " # Connect inputs to gate\n", + " left_style = output_styles.get(left[0], {}) \n", + " right_style = output_styles.get(right[0], {}) \n", + " dot.node(left, left, shape='circle', style='filled', **left_style) \n", + " dot.node(right, right, shape='circle', style='filled', **right_style) \n", " dot.edge(left, gate_name)\n", " dot.edge(right, gate_name)\n", "\n", " # Connect gate to output\n", - " dot.node(output, output, shape='circle') # Output node as circle\n", + " output_style = output_styles.get(output[0], {}) \n", + " dot.node(output, output, shape='circle', style='filled', **output_style) # Output node as circle\n", " dot.edge(gate_name, output)\n", "\n", " # Render the graph to a file\n",