generated from Flashky/advent-of-code-yyyy
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from Flashky/feature/day_21
Feature/day 21
- Loading branch information
Showing
12 changed files
with
355 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
|
||
} |
34 changes: 34 additions & 0 deletions
34
src/main/java/com/adventofcode/flashk/common/jgrapht/LabeledEdge.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 + ")"; | ||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
src/main/java/com/adventofcode/flashk/day21/CharacterPress.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package com.adventofcode.flashk.day21; | ||
|
||
public record CharacterPress(char currentButton, char nextButton) { | ||
} |
160 changes: 160 additions & 0 deletions
160
src/main/java/com/adventofcode/flashk/day21/Keypad.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
package com.adventofcode.flashk.day21; | ||
|
||
import com.adventofcode.flashk.common.Input; | ||
import com.adventofcode.flashk.common.jgrapht.LabeledEdge; | ||
import lombok.Setter; | ||
import org.jgrapht.Graph; | ||
import org.jgrapht.GraphPath; | ||
import org.jgrapht.alg.shortestpath.AllDirectedPaths; | ||
import org.jgrapht.graph.DirectedMultigraph; | ||
|
||
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; | ||
|
||
// Memoization maps | ||
private static final Map<CharacterPress,Set<String>> memoGetPaths = new HashMap<>(); | ||
private final Map<CharacterPress,Long> memoMinButtonLength = new HashMap<>(); | ||
|
||
@Setter | ||
private Keypad nextKeypad; | ||
|
||
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)); | ||
|
||
} | ||
|
||
} | ||
|
||
public long press(String code) { | ||
|
||
char[] buttons = code.toCharArray(); | ||
|
||
long minimumLength = 0; | ||
|
||
char previousButton = 'A'; | ||
|
||
for(char button : buttons) { | ||
|
||
button = mapDirectionalButton(button); | ||
long minimumButtonLength = getMinimumButtonLength(previousButton, button); | ||
previousButton = button; | ||
|
||
minimumLength += minimumButtonLength; | ||
|
||
} | ||
|
||
return minimumLength; | ||
} | ||
|
||
private long getMinimumButtonLength(char previousButton, char button) { | ||
|
||
// Memoization | ||
CharacterPress state = new CharacterPress(previousButton, button); | ||
if(memoMinButtonLength.containsKey(state)) { | ||
return memoMinButtonLength.get(state); | ||
} | ||
|
||
// Obtain from memo or compute. Add it to memoization if it didn't exist. | ||
Set<String> buttonPaths = getPaths(previousButton, button); | ||
|
||
long minimumButtonLength = Long.MAX_VALUE; | ||
|
||
for (String buttonPath : buttonPaths) { | ||
long buttonLength = nextKeypad != null ? nextKeypad.press(buttonPath) : buttonPath.length(); | ||
minimumButtonLength = Math.min(buttonLength, minimumButtonLength); | ||
} | ||
|
||
// Memoization | ||
memoMinButtonLength.put(state, minimumButtonLength); | ||
|
||
return minimumButtonLength; | ||
} | ||
|
||
private char mapDirectionalButton(char button) { | ||
if(directional) { | ||
return switch(button) { | ||
case '<' -> 'L'; | ||
case '>' -> 'R'; | ||
case '^' -> 'U'; | ||
case 'v' -> 'D'; | ||
case 'A' -> 'A'; | ||
default -> throw new IllegalStateException("Unexpected button value: " + button); | ||
}; | ||
} | ||
|
||
return button; | ||
} | ||
|
||
public Set<String> getPaths(char origin, char destination) { | ||
|
||
// Use cache first | ||
CharacterPress state = new CharacterPress(origin, destination); | ||
if(memoGetPaths.containsKey(state)) { | ||
return memoGetPaths.get(state); | ||
} | ||
|
||
AllDirectedPaths<String, LabeledEdge> adp = new AllDirectedPaths<>(graph); | ||
|
||
List<GraphPath<String, LabeledEdge>> graphPaths = adp.getAllPaths(String.valueOf(origin), String.valueOf(destination), | ||
true,4); | ||
|
||
int shortestPathSize = Integer.MAX_VALUE; | ||
|
||
Set<String> paths = new HashSet<>(); | ||
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); | ||
} | ||
|
||
int finalShortestPathSize = shortestPathSize; | ||
paths = paths.stream().filter(p -> p.length() == finalShortestPathSize).collect(Collectors.toSet()); | ||
|
||
// Memoize paths | ||
memoGetPaths.put(state, paths); | ||
|
||
return paths; | ||
} | ||
|
||
} |
50 changes: 50 additions & 0 deletions
50
src/main/java/com/adventofcode/flashk/day21/KeypadConundrum.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package com.adventofcode.flashk.day21; | ||
|
||
|
||
|
||
import org.apache.commons.lang3.StringUtils; | ||
|
||
import java.util.List; | ||
|
||
public class KeypadConundrum { | ||
|
||
private final List<String> codes; | ||
|
||
private final Keypad numpad; | ||
|
||
public KeypadConundrum(List<String> inputs, int keypadsNumber) { | ||
codes = inputs; | ||
|
||
// Create all keypad robots and link between them | ||
Keypad previousRobot = null; | ||
|
||
for(int i = 0; i < keypadsNumber; i++) { | ||
Keypad currentRobot = new Keypad(true); | ||
if(previousRobot != null) { | ||
currentRobot.setNextKeypad(previousRobot); | ||
} | ||
previousRobot = currentRobot; | ||
} | ||
|
||
numpad = new Keypad(false); | ||
numpad.setNextKeypad(previousRobot); | ||
} | ||
|
||
public long solveA() { | ||
|
||
long result = 0; | ||
for(String code : codes) { | ||
result += press(code); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
private long press(String code) { | ||
long shortestSequenceLength = numpad.press(code); | ||
long numericValue = Long.parseLong(code.replace("A", StringUtils.EMPTY)); | ||
return shortestSequenceLength * numericValue; | ||
} | ||
|
||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
# Day 21: | ||
# Day 21: Keypad Conundrum | ||
|
||
[https://adventofcode.com/2024/day/21](https://adventofcode.com/2024/day/21) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.