diff --git a/src/main/java/com/adventofcode/flashk/day24/CrossedWires.java b/src/main/java/com/adventofcode/flashk/day24/CrossedWires.java new file mode 100644 index 0000000..0ac6183 --- /dev/null +++ b/src/main/java/com/adventofcode/flashk/day24/CrossedWires.java @@ -0,0 +1,154 @@ +package com.adventofcode.flashk.day24; + +import org.apache.commons.lang3.StringUtils; +import org.jgrapht.graph.DirectedMultigraph; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class CrossedWires { + + private static final Pattern GATE_PATTERN = Pattern.compile("(\\w*) (AND|XOR|OR) (\\w*) -> (\\w*)"); + + private DirectedMultigraph graph = new DirectedMultigraph<>(WireEdge.class); + + Map wires = new HashMap<>(); + private final List gates = new ArrayList<>(); + + // Attributes that help start and end the algorithm + private final List initialGates = new ArrayList<>(); + private final List endWires = new ArrayList<>(); + + public CrossedWires(List inputs) { + + // Maps a wire with the gate that generates it. + Map originGates = new HashMap<>(); + + boolean inputWires = true; + + for (String input : inputs) { + if (StringUtils.isBlank(input)) { + inputWires = false; + continue; + } + + if (inputWires) { + String[] wireInput = input.replace(StringUtils.SPACE, StringUtils.EMPTY).split(":"); + wires.put(wireInput[0], new Wire(wireInput[0], Integer.parseInt(wireInput[1]))); + } else { + createGate(input, originGates); + } + } + + + // Connect graph gates + /* + for(LogicalGate gate : gates) { + + // First input + if(originGates.containsKey(gate.getInput1())) { + Gate inputGate1 = originGates.get(gate.getInput1()); + graph.addEdge(inputGate1, gate, new WireEdge(gate.getInput1())); + } + + // Second input + if(originGates.containsKey(gate.getInput2())) { + Gate inputGate2 = originGates.get(gate.getInput2()); + graph.addEdge(inputGate2, gate, new WireEdge(gate.getInput2())); + } + } +*/ + } + + private void createGate(String input, Map wireOriginGates) { + Matcher matcher = GATE_PATTERN.matcher(input); + if(matcher.find()) { + + // Create the gate vertex + String operation = matcher.group(2); + LogicalGate gate = new LogicalGate(operation); + + // Create the wires + getOrCreateWire(matcher.group(1)); // Input wire 1 + getOrCreateWire(matcher.group(3)); // Input wire 2 + Wire outputWire = getOrCreateWire(matcher.group(4)); + + + // Add it to structures + gates.add(gate); + graph.addVertex(gate); + + /* + if(gate.canOperate()) { + initialGates.add(gate); + }*/ + + // Wire management for building the graph + if(outputWire.getLabel().startsWith("z")) { + endWires.add(outputWire); + } + + wireOriginGates.put(outputWire, gate); + + } + } + + private void buildGraph() { + LogicalGate start = new StartGate("OR"); + + } + /// Retrieves a [Wire]() associated to the label. + /// + /// If the label does not exist, it creates a new wire and returns it. + /// @param label the wire label + /// @return a [Wire]() + private Wire getOrCreateWire(String label) { + Wire wire = wires.getOrDefault(label, new Wire(label)); + wires.putIfAbsent(label, wire); + return wire; + } + + public long solveA() { + + /* + PriorityQueue gates = new PriorityQueue<>(); + gates.addAll(initialGates); + + while(!gates.isEmpty()) { + + // Extract first those gates which can operate + Gate gate = gates.poll(); + gate.setVisited(true); + + // Operate it + WireEdge outputEdge = gate.operate(); + Wire output = outputEdge.wire(); + System.out.println("Wire "+output.getLabel()+ " has value: "+output.getValue().get()); + + // Calculate the next gate that should be added to the queue. + if(!output.isEnd()) { + Gate outputGate = graph.getEdgeTarget(outputEdge); + if(!outputGate.isVisited()) { + gates.add(outputGate); + } + } + + }*/ + + String binaryValue = endWires.stream().sorted().map(Wire::getBinaryValue).collect(Collectors.joining()); + return Long.valueOf(binaryValue, 2); + } + + private Set getAdjacents(Gate gate) { + // TODO cálculo de adyacentes + return new HashSet<>(); + } +} diff --git a/src/main/java/com/adventofcode/flashk/day24/Gate.java b/src/main/java/com/adventofcode/flashk/day24/Gate.java new file mode 100644 index 0000000..316a22d --- /dev/null +++ b/src/main/java/com/adventofcode/flashk/day24/Gate.java @@ -0,0 +1,69 @@ +package com.adventofcode.flashk.day24; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +@Getter +@Setter +@EqualsAndHashCode +public class Gate implements Comparable { + + private String id = UUID.randomUUID().toString(); + private String operation; + private Wire input1; + private Wire input2; + private Wire output; + private WireEdge outputEdge; + + private boolean visited = false; + + public Gate(String operation, Wire input1, Wire input2, Wire output) { + this.operation = operation; + this.input1 = input1; + this.input2 = input2; + this.output = output; + this.outputEdge = new WireEdge(output); + } + + public boolean canOperate() { + return input1.hasCurrent() && input2.hasCurrent(); + } + + /// Operates the gate using its inputs wires + /// + /// @return the output [Wire]() + /// @throws IllegalStateException if any of the wires has no value present or if the gate operation is unknown. + public WireEdge operate() { + + int value1 = input1.getValue().orElseThrow(IllegalStateException::new); + int value2 = input2.getValue().orElseThrow(IllegalStateException::new); + + switch (operation) { + case "AND" -> output.setValue(value1 & value2); + case "XOR" -> output.setValue(value1 ^ value2); + case "OR" -> output.setValue(value1 | value2); + case null, default -> throw new IllegalStateException("Unknown gate operation: " + operation); + } + + return outputEdge; + } + + + @Override + public int compareTo(@NotNull Gate o) { + if(this.canOperate() && !o.canOperate()) { + return -1; + } + + if(!this.canOperate() && o.canOperate()) { + return 1; + } + + return 0; + } + +} diff --git a/src/main/java/com/adventofcode/flashk/day24/LogicalGate.java b/src/main/java/com/adventofcode/flashk/day24/LogicalGate.java new file mode 100644 index 0000000..93cf923 --- /dev/null +++ b/src/main/java/com/adventofcode/flashk/day24/LogicalGate.java @@ -0,0 +1,40 @@ +package com.adventofcode.flashk.day24; + +import java.util.UUID; + +public class LogicalGate { + + private final String id = UUID.randomUUID().toString(); + private final String operation; + + public LogicalGate(String operation) { + this.operation = operation; + } + + public boolean canOperate(Wire input1, Wire input2) { + return input1.getValue().isPresent() && input2.getValue().isPresent(); + } + + /// Operates the gate using its inputs wires + /// + /// @return the output [Wire]() + /// @throws IllegalStateException if any of the wires has no value present or if the gate operation is unknown. + public int operate(Wire input1, Wire input2) { + + int value1 = input1.getValue().orElseThrow(IllegalStateException::new); + int value2 = input2.getValue().orElseThrow(IllegalStateException::new); + + int result; + + switch (operation) { + case "AND" -> result = value1 & value2; + case "XOR" -> result = value1 ^ value2; + case "OR" -> result = value1 | value2; + case null, default -> throw new IllegalStateException("Unknown gate operation: " + operation); + } + + return result; + + } + +} diff --git a/src/main/java/com/adventofcode/flashk/day24/StartGate.java b/src/main/java/com/adventofcode/flashk/day24/StartGate.java new file mode 100644 index 0000000..c93c53f --- /dev/null +++ b/src/main/java/com/adventofcode/flashk/day24/StartGate.java @@ -0,0 +1,10 @@ +package com.adventofcode.flashk.day24; + +public class StartGate extends LogicalGate { + + public StartGate(String operation) { + super(operation); + } + + +} diff --git a/src/main/java/com/adventofcode/flashk/day24/Wire.java b/src/main/java/com/adventofcode/flashk/day24/Wire.java new file mode 100644 index 0000000..a53dc17 --- /dev/null +++ b/src/main/java/com/adventofcode/flashk/day24/Wire.java @@ -0,0 +1,59 @@ +package com.adventofcode.flashk.day24; + + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +@Getter +@EqualsAndHashCode +public class Wire implements Comparable{ + + private final String label; + + @Setter + private int value; + + public Wire(String label, int value) { + this.label = label; + this.value = value; + } + + public Wire(String label) { + this.label = label; + this.value = -1; + } + + public String getBinaryValue() { + if(value == -1) { + throw new IllegalStateException("Cannot convert to binary a non set value"); + } + return String.valueOf(value); + } + + public Optional getValue() { + if(value == -1) { + return Optional.empty(); + } + return Optional.of(value); + } + + public boolean hasCurrent() { + return value != -1; + } + + public boolean isStart() { + return label.startsWith("x") || label.startsWith("y"); + } + public boolean isEnd() { + return label.startsWith("z"); + } + + @Override + public int compareTo(@NotNull Wire o) { + return -1 * this.label.compareTo(o.label); + } +} diff --git a/src/main/java/com/adventofcode/flashk/day24/WireEdge.java b/src/main/java/com/adventofcode/flashk/day24/WireEdge.java new file mode 100644 index 0000000..8a9adc0 --- /dev/null +++ b/src/main/java/com/adventofcode/flashk/day24/WireEdge.java @@ -0,0 +1,10 @@ +package com.adventofcode.flashk.day24; + +import java.util.UUID; + +public record WireEdge(String id, Wire wire) { + + public WireEdge(Wire wire) { + this(UUID.randomUUID().toString(), wire); + } +}