Skip to content

Commit

Permalink
Merge branch 'master' into feature/day_17
Browse files Browse the repository at this point in the history
  • Loading branch information
Flashky committed Dec 27, 2024
2 parents 2759a28 + e4edd8c commit 47791dd
Show file tree
Hide file tree
Showing 12 changed files with 378 additions and 48 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
- [Day 22 - Monkey Market](https://github.com/Flashky/advent-of-code-2024/tree/master/src/main/java/com/adventofcode/flashk/day22)
- [Day 23 - LAN Party](https://github.com/Flashky/advent-of-code-2024/tree/master/src/main/java/com/adventofcode/flashk/day23)
- [Day 24 - Crossed Wires](https://github.com/Flashky/advent-of-code-2024/tree/master/src/main/java/com/adventofcode/flashk/day24)
- [Day 25](https://github.com/Flashky/advent-of-code-2024/tree/master/src/main/java/com/adventofcode/flashk/day25)
- [Day 25 - Code Chronicle](https://github.com/Flashky/advent-of-code-2024/tree/master/src/main/java/com/adventofcode/flashk/day25)

## Cloning this repository

Expand Down
7 changes: 6 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<dependency>
<groupId>nl.jqno.equalsverifier</groupId>
<artifactId>equalsverifier</artifactId>
<version>3.17.5</version>
<version>3.18</version>
<scope>test</scope>
</dependency>
<dependency>
Expand All @@ -46,6 +46,11 @@
<artifactId>jgrapht-core</artifactId>
<version>1.5.2</version>
</dependency>
<dependency>
<groupId>org.jgrapht</groupId>
<artifactId>jgrapht-io</artifactId>
<version>1.5.2</version>
</dependency>
<!-- JSON management -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
Expand Down
174 changes: 174 additions & 0 deletions src/main/java/com/adventofcode/flashk/day24/CrossedWiresVisual.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package com.adventofcode.flashk.day24;

import org.apache.commons.lang3.StringUtils;
import org.jgrapht.Graph;
import org.jgrapht.graph.DirectedMultigraph;
import org.jgrapht.nio.dot.DOTExporter;

import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class CrossedWiresVisual {

private static final Pattern GATE_PATTERN = Pattern.compile("(\\w*) (AND|XOR|OR) (\\w*) -> (\\w*)");

private final Graph<GateVisual, String> graph = new DirectedMultigraph<>(String.class);

private final Map<String,GateVisual> gatesPerOutput = new HashMap<>();
private final Map<String,Integer> wires = new HashMap<>();
private final List<GateVisual> gates = new ArrayList<>();

public CrossedWiresVisual(List<String> inputs) {
initializeWires(inputs);
initializeGates(inputs);
createStartEndVertexes();
connectGates();
}

private void connectGates() {
// Por cada puerta
// Buscar si existe en gatesPerOutput
for(GateVisual gate : gatesPerOutput.values()) {
String output = gate.getOutput();

// Search gates that have this output gate as input 1.
List<GateVisual> gatesInput1 = gates.stream().filter(g -> output.equals(g.getInput1())).toList();
for(GateVisual gateInput1 : gatesInput1) {
String edgeId = output + "_" + UUID.randomUUID();
graph.addEdge(gate, gateInput1, edgeId);
}

// Search gates that have this output gate as input 2.
List<GateVisual> gatesInput2 = gates.stream().filter(g -> output.equals(g.getInput2())).toList();
for(GateVisual gateInput2 : gatesInput2) {
String edgeId = output + "_" + UUID.randomUUID();
graph.addEdge(gate, gateInput2, edgeId);
}

}

}

private void createStartEndVertexes() {
wires.keySet().stream().filter(this::isStartOrEnd).forEach(this::createStartEndVertex);
}


private void initializeGates(List<String> inputs) {
List<String> gatesInputs = inputs.stream().skip(inputs.indexOf(StringUtils.EMPTY)+1).toList();

for(String input : gatesInputs) {
Matcher matcher = GATE_PATTERN.matcher(input);
if(matcher.find()) {
String operation = matcher.group(2);
String input1 = matcher.group(1);
String input2 = matcher.group(3);
String output = matcher.group(4);

GateVisual gateVisual = new GateVisual(operation, input1, input2, output);
gates.add(gateVisual);
gatesPerOutput.put(output, gateVisual);
graph.addVertex(gateVisual);
}
}
}

private void initializeWires(List<String> inputs) {

boolean inputGates = false;
for (String input : inputs) {

if (StringUtils.EMPTY.equals(input)) {
inputGates = true;
continue;
}

if (!inputGates) {
String[] wireInput = input.replace(StringUtils.SPACE, StringUtils.EMPTY).split(":");
wires.put(wireInput[0], Integer.parseInt(wireInput[1]));
} else {
Matcher matcher = GATE_PATTERN.matcher(input);
if (matcher.find()) {
wires.putIfAbsent(matcher.group(1), -1);
wires.putIfAbsent(matcher.group(3), -1);
wires.putIfAbsent(matcher.group(4), -1);
}
}
}
}


public String solveB() {

// Obtain the graph in DOT format:
paint();

// Visual finding of invalid edges
System.out.println("Tools:");
System.out.println("- (Optional) graphviz: sudo apt install graphviz");
System.out.println("- graphviz2drawio: pip install graphviz2drawio");
System.out.println();
System.out.println("Procedure:");
System.out.println("1. Add the result to a file: dotgraph_day24.txt");
System.out.println("2. (Optional) Execute command: cat day24.txt | dot -Tsvg > day24.svg");
System.out.println("3. Execute command: graphviz2drawio dotgraph_day24.txt");
System.out.println("4. Open the exported 'dotgraph_day24.xml' file at https://draw.io");
System.out.println("5. Order the graph nodes until you see the invalid connections");

// Invalid gates are:
// bbp AND wwg -> z09
// wwg XOR bbp -> hnd
// ncj OR pwk -> z16
// jkw XOR mqf -> tdv
// x23 AND y23 -> z23
// mfr XOR scw -> bks
// x37 AND y37 -> tjp
// x37 XOR y37 -> nrn

// So the outputs are: z09,hnd,z16,tdv,z23,bks,tjp,nrn
List<String> outputGates = List.of("z09","hnd","z16","tdv","z23","bks","tjp","nrn");

return outputGates.stream().sorted().collect(Collectors.joining(","));
}

private void createStartEndVertex(String wire) {
GateVisual gateVisual = new GateVisual(wire);
graph.addVertex(gateVisual);

if(isStart(wire)) {
gatesPerOutput.put(wire, gateVisual);
} else if(isEnd(wire)) {
gates.add(gateVisual);
}

}

private boolean isStart(String wire) {
return wire.startsWith("x") || wire.startsWith("y");
}

private boolean isEnd(String wire) {
return wire.startsWith("z");
}

private boolean isStartOrEnd(String wire) {
return isStart(wire) || isEnd(wire);
}

private void paint() {
DOTExporter<GateVisual, String> exporter = new DOTExporter<>(v -> v.getLabel());
Writer writer = new StringWriter();
exporter.exportGraph(graph, writer);
System.out.println(writer.toString());
}


}
44 changes: 44 additions & 0 deletions src/main/java/com/adventofcode/flashk/day24/GateVisual.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.adventofcode.flashk.day24;

import lombok.Getter;
import org.apache.commons.lang3.StringUtils;

@Getter
public class GateVisual {

private static int id = 0;

private final String label;
private final String operation;
private String input1;
private String input2;
private String output;

public GateVisual(String label) {
this.label = label;
this.operation = StringUtils.EMPTY;
if(label.startsWith("x") || label.startsWith("y")) {
this.output = label;
} else if(label.startsWith("z")) {
this.input1 = label;
}
}

public GateVisual(String operation, String input1, String input2, String output) {
this.label = operation + "_" + output;
this.operation = operation;
this.input1 = input1;
this.input2 = input2;
this.output = output;
}

public int operate(int value1, int value2) {
return switch (operation) {
case "AND" -> value1 & value2;
case "XOR" -> value1 ^ value2;
case "OR" -> value1 | value2;
case null, default -> throw new IllegalStateException("Unknown gate operation: " + operation);
};
}

}
60 changes: 60 additions & 0 deletions src/main/java/com/adventofcode/flashk/day25/CodeChronicle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.adventofcode.flashk.day25;


import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class CodeChronicle {

private Set<Lock> locks = new HashSet<>();
private Set<Key> keys = new HashSet<>();

public CodeChronicle(List<String> inputs) {

int i = 0;
char[][] map = new char[7][5];
boolean isLock = false;

for(String row : inputs) {

if(i == 0) {
isLock = "#####".equals(row);
}

if(i == 7) {

if(isLock) {
locks.add(new Lock(map));
} else {
keys.add(new Key(map));
}

map = new char[7][5];
i = 0;

} else {
map[i++] = row.toCharArray();
}

}

if(isLock) {
locks.add(new Lock(map));
} else {
keys.add(new Key(map));
}
}

public long solveA() {
long count = 0;
for(Lock lock : locks) {
for(Key key :keys) {
if(lock.canFit(key)) {
count++;
}
}
}
return count;
}
}
22 changes: 22 additions & 0 deletions src/main/java/com/adventofcode/flashk/day25/Key.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.adventofcode.flashk.day25;

import com.adventofcode.flashk.common.Array2DUtil;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;

public class Key {

@Getter
private final int[] heights = new int[5];

public Key(char[][] keyMap) {
char[][] transposedMap = Array2DUtil.transpose(keyMap);

for(int i = 0; i < transposedMap.length; i++) {
String rowValue = new String(transposedMap[i]);
heights[i] = StringUtils.countMatches(rowValue, "#")-1;
}
}


}
36 changes: 36 additions & 0 deletions src/main/java/com/adventofcode/flashk/day25/Lock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.adventofcode.flashk.day25;

import com.adventofcode.flashk.common.Array2DUtil;
import org.apache.commons.lang3.StringUtils;

public class Lock {

private final int[] pins = new int[5];

public Lock(char[][] lockMap) {

char[][] transposedMap = Array2DUtil.transpose(lockMap);

for(int i = 0; i < transposedMap.length; i++) {
String rowValue = new String(transposedMap[i]);
pins[i] = StringUtils.countMatches(rowValue, "#")-1;
}
}

public boolean canFit(Key key) {

boolean fit = true;
int[] heights = key.getHeights();
int i = 0;

while(fit && i < 5) {
int spaceLeft = 5 - pins[i];
if(spaceLeft < heights[i]){
fit = false;
}
i++;
}

return fit;
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/adventofcode/flashk/day25/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Day 25:
# Day 25: Code Chronicle

[https://adventofcode.com/2024/day/25](https://adventofcode.com/2024/day/25)
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ private TestFilename() {}
public static final String INPUT_FILE = "data.input";
public static final String INPUT_FILE_SAMPLE = "sample.input";
public static final String INPUT_FILE_SAMPLE_2 = "sample_2.input";
public static final String INPUT_FILE_SAMPLE_3 = "sample_3.input";
public static final String INPUT_FILE_SAMPLE_PART_2 = "sample_part_2.input";
public static final String INPUT_FILE_SINGLE_SAMPLE = "single_sample.input";
public static final String INPUT_FILE_SINGLE_SAMPLE_2 = "single_sample_2.input";
Expand Down
1 change: 0 additions & 1 deletion src/test/java/com/adventofcode/flashk/day23/Day23Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@

@DisplayName(TestDisplayName.DAY_23)
@TestMethodOrder(OrderAnnotation.class)
@Disabled // TODO Remove comment when implemented
public class Day23Test extends PuzzleTest {

private static final String INPUT_FOLDER = TestFolder.DAY_23;
Expand Down
Loading

0 comments on commit 47791dd

Please sign in to comment.