Skip to content

Commit

Permalink
feat: solve day 21 part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
Flashky committed Dec 28, 2024
1 parent 41fe37a commit e0c0847
Show file tree
Hide file tree
Showing 11 changed files with 398 additions and 18 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
<!-- Google Libraries -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.4.0-jre</version>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
Expand Down
34 changes: 34 additions & 0 deletions src/main/java/com/adventofcode/flashk/common/Input.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.adventofcode.flashk.common;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public final class Input {

private static final String PATH_INPUTS = "src/main/resources";

private Input() {
}

public static List<String> readStringLines(String inputFolder, String inputFile) {

List<String> input;

try {
Path path = Paths.get(PATH_INPUTS, inputFolder, inputFile).toAbsolutePath();
input = Files.lines(path).collect(Collectors.toList());

} catch (IOException e) {
input = new ArrayList<>();
e.printStackTrace();
}

return input;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.adventofcode.flashk.common.jgrapht;

import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.nio.Attribute;
import org.jgrapht.nio.AttributeType;

/// Labeled edge class based on [JGraphT LabeledEdges](https://jgrapht.org/guide/LabeledEdges)
///
/// Allows creating an edge with label.
///
/// It also implements the JGraphT Attribute interface to allow exporting the labels in DOT representation
public class LabeledEdge extends DefaultEdge implements Attribute {

private final String label;

public LabeledEdge(String label) {
this.label = label;
}

@Override
public String getValue() {
return label;
}

@Override
public AttributeType getType() {
return AttributeType.STRING;
}

@Override
public String toString() {
return "(" + getSource() + " : " + getTarget() + " : " + label + ")";
}
}
41 changes: 41 additions & 0 deletions src/main/java/com/adventofcode/flashk/day21/redesign/Key.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.adventofcode.flashk.day21.redesign;


import lombok.Getter;

public enum Key {

NUMBER_0("0"),
NUMBER_1("1"),
NUMBER_2("2"),
NUMBER_3("3"),
NUMBER_4("4"),
NUMBER_5("5"),
NUMBER_6("6"),
NUMBER_7("7"),
NUMBER_8("8"),
NUMBER_9("9"),
ARROW_LEFT("<"),
ARROW_DOWN("v"),
ARROW_UP("^"),
ARROW_RIGHT(">"),
ACCEPT("A");

@Getter
private final String value;

Key(String value) {
this.value = value;
}

/*
public static Key getKey(String value) {
for(Key key : values()) {
if(key.getValue().equals(value)) {
return key;
}
}
throw new IllegalArgumentException("Unknown enum value for: "+value);
}*/

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

import com.adventofcode.flashk.common.Input;
import com.adventofcode.flashk.common.jgrapht.LabeledEdge;
import com.adventofcode.flashk.day25.Key;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.jgrapht.Graph;
import org.jgrapht.GraphPath;
import org.jgrapht.alg.shortestpath.AllDirectedPaths;
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.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class Keypad {

private static final String FILE_DIRECTIONAL_MAPPINGS = "directional_mappings.txt";
private static final String FILE_NUMPAD_MAPPINGS = "numpad_mappings.txt";

private final Graph<String, LabeledEdge> graph = new DirectedMultigraph<>(LabeledEdge.class);
private final boolean directional;
private static final Map<KeypadPress,List<String>> memo = new HashMap<>();

// TODO opción 2: caché a nivel de code en lugar de button

private String currentButton = "A";


public Keypad(boolean isDirectional) {

// Create the graph using mappings files

// Each line of the mappings files is a comma delimited list which represents:
// source_vertex,edge_label,target_vertex

// This allows to create a complete graph based on the contents of the graph.
directional = isDirectional;

// Read the key mappings from the file
String filename = directional ? FILE_DIRECTIONAL_MAPPINGS : FILE_NUMPAD_MAPPINGS;
List<String> lines = Input.readStringLines("day21", filename);

// Create the vertexes and edges described at each line
for(String line : lines) {

String[] parts = line.split(",");
String vertexSource = parts[0];
String edgeLabel = parts[1];
String vertexTarget = parts[2];

if(!graph.containsVertex(vertexSource)) {
graph.addVertex(vertexSource);
}

if(!graph.containsVertex(vertexTarget)) {
graph.addVertex(vertexTarget);
}

graph.addEdge(vertexSource, vertexTarget, new LabeledEdge(edgeLabel));

}

}

/// Enters a code to be pressed at the pad returning a [String] representing the needed moves for it.
///
/// The code can be either an alphanumeric value as such as `029A` to be pressed at a numeric pad or an
/// alphanumeric value such as `<A^A^>^AvvvA` to be pressed at a directional keypad.
///
/// @param code the code to enter.
/// @return A list of possible instructions to be executed by the next robot
public Set<String> press(String code) {
char[] buttons = code.toCharArray();

List<List<String>> allButtonPaths = new ArrayList<>();
for(char button : buttons) {

if(directional) {
button = switch(button) {
case '<' -> 'L';
case '>' -> 'R';
case '^' -> 'U';
case 'v' -> 'D';
case 'A' -> 'A';
default -> throw new IllegalStateException("Unexpected button value: " + button);
};
}

// Generate a memoization status for this key press
KeypadPress state = new KeypadPress(currentButton, button);

// Obtain from memo or compute. Add it to memoization if it didn't exist.
List<String> buttonPaths = memo.getOrDefault(state, press(button));
memo.putIfAbsent(state, buttonPaths);

//
allButtonPaths.add(buttonPaths);
}

// Create all the possible path combinations
List<List<String>> cartesianList = Lists.cartesianProduct(allButtonPaths);
Set<String> paths = new HashSet<>();
for(List<String> possiblePaths : cartesianList) {
paths.add(String.join(StringUtils.EMPTY, possiblePaths));
}

return paths;
}

/// Presses the specified button retrieving a list of minimum cost directional key presses to achieve that key press.
///
/// @param button the button to press.
/// @return a list of different paths as String to achieve that key press from the current button position.
public List<String> press(char button) {
AllDirectedPaths<String, LabeledEdge> adp = new AllDirectedPaths<>(graph);

List<GraphPath<String, LabeledEdge>> graphPaths = adp.getAllPaths(currentButton, String.valueOf(button),
true,4);

int shortestPathSize = Integer.MAX_VALUE;

List<String> paths = new ArrayList<>();
for(GraphPath<String, LabeledEdge> graphPath : graphPaths) {
String path = graphPath.getEdgeList().stream().map(LabeledEdge::getValue).collect(Collectors.joining()) + "A";
shortestPathSize = Math.min(path.length(), shortestPathSize);
paths.add(path);
}

this.currentButton = String.valueOf(button);
int finalShortestPathSize = shortestPathSize;
return paths.stream().filter(p -> p.length() == finalShortestPathSize).toList();
}

public void paint() {

DOTExporter<String, LabeledEdge> exporter = new DOTExporter<>(v -> v);
exporter.setEdgeAttributeProvider(e -> Map.of("label", e));

Writer writer = new StringWriter();
exporter.exportGraph(graph, writer);
System.out.println(writer.toString());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.adventofcode.flashk.day21.redesign;



import org.apache.commons.lang3.StringUtils;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Set;

public class KeypadConundrum2 {

private List<String> codes;

private Deque<Keypad> keypads = new ArrayDeque<>();

public KeypadConundrum2(List<String> inputs, int keypadsNumber) {
codes = inputs;
keypads.add(new Keypad(false));
for(int i = 0; i < keypadsNumber; i++) {
keypads.add(new Keypad(true));
}
}

public long solveA() {

long result = 0;
for(String code : codes) {
result += press(code);
}

return result;
}

private long press(String code) {
long shortestSequenceLength = pressCode(code);
long numericValue = Long.parseLong(code.replace("A", StringUtils.EMPTY));
return shortestSequenceLength * numericValue;
}

private long pressCode(String code) {

if(keypads.isEmpty()) {
return code.length();
}

long shortestSequence = Long.MAX_VALUE;

Keypad nextKeypad = keypads.pollFirst();

Set<String> keyPressesList = nextKeypad.press(code);
for(String keyPresses : keyPressesList) {
long sequence = pressCode(keyPresses);
shortestSequence = Math.min(shortestSequence, sequence);
}

keypads.addFirst(nextKeypad);

return shortestSequence;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.adventofcode.flashk.day21.redesign;

public record KeypadPress(String currentButton, char nextButton) {
}
10 changes: 10 additions & 0 deletions src/main/resources/day21/directional_mappings.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
U,v,D
U,>,A
A,<,U
A,v,R
L,>,D
D,<,L
D,^,U
D,>,R
R,<,D
R,^,A
30 changes: 30 additions & 0 deletions src/main/resources/day21/numpad_mappings.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
7,>,8
7,v,4
8,<,7
8,>,9
8,v,5
9,<,8
9,v,6
4,^,7
4,>,5
4,v,1
5,<,4
5,^,8
5,>,6
5,v,2
6,<,5
6,^,9
6,v,3
1,>,2
1,^,4
2,<,1
2,^,5
2,>,3
2,v,0
3,<,2
3,^,6
3,v,A
0,>,A
0,^,2
A,<,0
A,^,3
Loading

0 comments on commit e0c0847

Please sign in to comment.