Skip to content

Commit 6fc62f0

Browse files
committed
Day 24 part 1 - I have regrets
1 parent 6dedff9 commit 6fc62f0

File tree

5 files changed

+296
-0
lines changed

5 files changed

+296
-0
lines changed

README.md

+12
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,15 @@ I thought I could dash off part 1 real quick over lunch...but it turned out I mi
181181
[Later] I rewrote part 1, now understanding what was being asked. Seems to work well! Sadly, it doesn't seem like what I wrote is going to help me with part 2, despite me trying to make it more general use than what they were asking! I'll need a new approach to tackle part 2.
182182

183183
[Later still] Yeah...my logic for part 2 is totally different from part 1, but both seem to work well, so I'm taking the W!
184+
185+
## Day 24: Crossed Wires
186+
187+
I had a pretty good time implementing part 1, due in no small part to thinking I was doing something "clever." Now having done part 1 and seen the ask for part 2, I think it's likely I'll have to throw away everything I did for part 1. I'm not going to try it out now, though; it's late and I have to sleep. I'll think on it, though...I'll try to use this extra mulling time to see if I an approach part 2 with the architecture I set up for part 1...or if I'll just have to start the whole thing over.
188+
189+
**Day 24 part 1 spoilers**
190+
191+
For whatever reason, it seemed to make sense to me to have the signal information work backwards...that it would get "pulled" from the output wires instead of "pushed" by the initial wire values. Since the gates have to "wait" for their signals to come in, it felt like it made sense for me to pull on the dependency chain from the output side. Like...it seemed like it would make it easier to detect errors?
192+
193+
[Later] Now that I've completed part 1 and seen part 2, I think I've really hosed myself. By "easier to detect errors" before, I meant easier to detect if I wasn't wiring the board internals correctly based on what the puzzle input was saying. Now that I've seen part 2, "easier to detect errors" is laughably wrong; I can't detect shit with this implementation, I'm pretty sure. I thought I was so funny not keeping any gate references. Who's laughing now?! Not me.
194+
195+
**End spoilers**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package com.robabrazado.aoc2024.day24;
2+
3+
import java.io.PrintWriter;
4+
import java.io.StringWriter;
5+
import java.math.BigInteger;
6+
import java.util.HashMap;
7+
import java.util.Iterator;
8+
import java.util.Map;
9+
import java.util.Set;
10+
import java.util.TreeSet;
11+
import java.util.regex.Matcher;
12+
import java.util.regex.Pattern;
13+
import java.util.stream.Stream;
14+
15+
/*
16+
* A Board is an assemblage of Wires and Gates. The state of the board is activated by
17+
* setting the value to input wires (wires whose inputs are not connected to any gate
18+
* outputs), and values can be read from any wire. A wire without a value generally
19+
* signals that the necessary input wires have not been assigned values or that the
20+
* Board is misconfigured.
21+
*/
22+
public class Board {
23+
private static final Pattern STATE_PATTERN = Pattern.compile("(\\w+): ([01])");
24+
private static final Pattern GATE_PATTERN = Pattern.compile("(\\w+) (\\w+) (\\w+) -> (\\w+)");
25+
26+
private final Map<String, Wire> wireMap = new HashMap<String, Wire>();
27+
28+
// Instantiates and initializes board to starting state
29+
public Board(Stream<String> puzzleInput) {
30+
Iterator<String> it = puzzleInput.iterator();
31+
String line = null;
32+
33+
// Input until first blank line is initial state
34+
while (it.hasNext()) {
35+
line = it.next();
36+
if (line.isEmpty()) {
37+
break;
38+
}
39+
40+
Matcher m = STATE_PATTERN.matcher(line);
41+
if (m.find()) {
42+
Wire w = this.getOrCreateWire(m.group(1));
43+
w.setValue(m.group(2).equals("1"));
44+
} else {
45+
throw new RuntimeException("Unrecognized initial state input: " + line);
46+
}
47+
}
48+
49+
// Rest of input is board configuration
50+
while (it.hasNext()) {
51+
line = it.next();
52+
Matcher m = GATE_PATTERN.matcher(line);
53+
if (m.find()) {
54+
Gate.connectGate(Gate.GateType.valueOf(m.group(2)),
55+
this.getOrCreateWire(m.group(1)),
56+
this.getOrCreateWire(m.group(3)),
57+
this.getOrCreateWire(m.group(4)));
58+
} else {
59+
throw new RuntimeException("Unrecognized gate input: " + line);
60+
}
61+
}
62+
63+
64+
}
65+
66+
public BigInteger getZOutputValue() {
67+
StringBuilder strb = new StringBuilder();
68+
Set<String> wireIds = new TreeSet<String>(this.wireMap.keySet());
69+
for (String s : wireIds) {
70+
if (s.startsWith("z")) {
71+
strb.insert(0, this.wireMap.get(s).getValue() ? '1' : '0');
72+
}
73+
}
74+
return new BigInteger(strb.toString(), 2);
75+
}
76+
77+
@Override
78+
public String toString() {
79+
StringWriter sw = new StringWriter();
80+
PrintWriter pw = new PrintWriter(sw, true);
81+
Set<String> wires = new TreeSet<String>(this.wireMap.keySet());
82+
for (String wire : wires) {
83+
pw.println(this.wireMap.get(wire));
84+
}
85+
return sw.toString();
86+
}
87+
88+
private Wire getOrCreateWire(String id) {
89+
if (!this.wireMap.containsKey(id)) {
90+
this.wireMap.put(id, new Wire(id));
91+
}
92+
return this.wireMap.get(id);
93+
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.robabrazado.aoc2024.day24;
2+
3+
import java.math.BigInteger;
4+
import java.util.stream.Stream;
5+
6+
import com.robabrazado.aoc2024.Solver;
7+
8+
// --- Day 24: Crossed Wires ---
9+
public class Day24Solver extends Solver {
10+
11+
public Day24Solver() {
12+
super(24);
13+
return;
14+
}
15+
16+
@Override
17+
public String solve(Stream<String> puzzleInput, boolean partOne, boolean isTest) {
18+
Board board = new Board(puzzleInput);
19+
System.out.println(board);
20+
BigInteger result = board.getZOutputValue();
21+
System.out.println(result.toString(2));
22+
return result.toString();
23+
}
24+
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.robabrazado.aoc2024.day24;
2+
3+
class Gate {
4+
private final GateType type;
5+
private final Wire input1;
6+
private final Wire input2;
7+
private final Wire output;
8+
9+
private Gate(GateType gateType, Wire input1, Wire input2, Wire output) {
10+
if (input1 == null || input2 == null || output == null) {
11+
throw new IllegalArgumentException("Gates must have all inputs and outputs connected");
12+
}
13+
this.input1 = input1;
14+
this.input2 = input2;
15+
this.output = output;
16+
this.type = gateType;
17+
return;
18+
}
19+
20+
Wire getInputWire1() {
21+
return this.input1;
22+
}
23+
24+
Wire getInputWire2() {
25+
return this.input2;
26+
}
27+
28+
Wire getOutputWire() {
29+
return this.output;
30+
}
31+
32+
// Throws exception if input signals not available
33+
boolean getOutput() {
34+
switch (this.type) {
35+
case AND:
36+
return this.input1.getValue() && this.input2.getValue();
37+
case OR:
38+
return this.input1.getValue() || this.input2.getValue();
39+
case XOR:
40+
return this.input1.getValue() ^ this.input2.getValue();
41+
default: // Uh oh
42+
throw new RuntimeException("Unsupported gate type");
43+
}
44+
}
45+
46+
@Override
47+
public String toString() {
48+
return String.format("%s %s %s -> %s",
49+
this.input1.getId(),
50+
this.type.name(),
51+
this.input2.getId(),
52+
this.output.getId());
53+
}
54+
55+
static Gate connectGate(GateType gateType, Wire toInput1, Wire toInput2, Wire fromOutput) {
56+
Gate gate = new Gate(gateType, toInput1, toInput2, fromOutput);
57+
toInput1.connectToGateInput(gate);
58+
toInput2.connectToGateInput(gate);
59+
fromOutput.connectToGateOutput(gate);
60+
return gate;
61+
}
62+
63+
enum GateType {
64+
AND (),
65+
OR (),
66+
XOR ();
67+
68+
}
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package com.robabrazado.aoc2024.day24;
2+
3+
import java.util.HashSet;
4+
import java.util.Set;
5+
6+
class Wire {
7+
private final String id;
8+
private Gate inputGate = null; // Zero or one input
9+
private Set<Gate> outputGates = new HashSet<Gate>(); // Zero or more outputs
10+
private Boolean value = null;
11+
12+
Wire(String id) {
13+
if (id == null || id.isEmpty()) {
14+
throw new IllegalArgumentException("Wire must have a valid ID");
15+
}
16+
this.id = id;
17+
return;
18+
}
19+
20+
String getId() {
21+
return this.id;
22+
}
23+
24+
Gate getInput() {
25+
return this.inputGate;
26+
}
27+
28+
// This is the wire's "input"; there can be at most one
29+
void connectToGateOutput(Gate fromGate) {
30+
if (this.inputGate == null) {
31+
this.inputGate = fromGate;
32+
} else {
33+
throw new IllegalStateException("A wire can only be connected to one gate output");
34+
}
35+
}
36+
37+
Set<Gate> getOutputs() {
38+
return new HashSet<Gate>(this.outputGates);
39+
}
40+
41+
// This is the wire's "output"
42+
void connectToGateInput(Gate toGate) {
43+
this.outputGates.add(toGate);
44+
return;
45+
}
46+
47+
// Throws error if value unavailable
48+
// Once called, value will remain in wire until cleared
49+
boolean getValue() {
50+
if (this.inputGate != null) {
51+
this.value = this.inputGate.getOutput();
52+
}
53+
if (this.value != null) {
54+
return this.value.booleanValue();
55+
} else {
56+
String message = this.inputGate == null ?
57+
"Input wire " + this.id + " has no value assigned" :
58+
"Wire " + this.id + " unable to read value from input gate";
59+
throw new RuntimeException(message);
60+
}
61+
}
62+
63+
void setValue(boolean b) {
64+
if (this.isInputWire()) {
65+
this.value = Boolean.valueOf(b);
66+
return;
67+
} else {
68+
throw new IllegalStateException("Value cannot be manually set; " + this.id + " is not an input wire");
69+
}
70+
}
71+
72+
void clearValue() {
73+
this.value = null;
74+
}
75+
76+
boolean isInputWire() {
77+
return this.inputGate == null;
78+
}
79+
80+
@Override
81+
public String toString() {
82+
StringBuilder strb = new StringBuilder();
83+
strb.append(this.id).append(" (");
84+
if (this.value == null) {
85+
strb.append('X');
86+
} else {
87+
strb.append(this.value ? '1' : '0');
88+
}
89+
strb.append("); ");
90+
91+
strb.append(this.inputGate == null ? '0' : '1').append(" input; ");
92+
strb.append(this.outputGates.size()).append(" output(s)");
93+
94+
return strb.toString();
95+
}
96+
}

0 commit comments

Comments
 (0)