Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 250acdf

Browse files
wip for part 2
1 parent 8bfb2a1 commit 250acdf

File tree

3 files changed

+478
-368
lines changed

3 files changed

+478
-368
lines changed

‎src/main/java/com/codefork/aoc2024/day21/Part01.java

Lines changed: 3 additions & 368 deletions
Original file line numberDiff line numberDiff line change
@@ -3,387 +3,22 @@
33
import com.codefork.aoc2024.Problem;
44
import com.codefork.aoc2024.util.Assert;
55

6-
import java.util.ArrayList;
7-
import java.util.Comparator;
8-
import java.util.HashMap;
9-
import java.util.HashSet;
10-
import java.util.LinkedList;
11-
import java.util.List;
12-
import java.util.Map;
13-
import java.util.Set;
14-
import java.util.stream.Collectors;
15-
import java.util.stream.IntStream;
166
import java.util.stream.Stream;
177

18-
import static com.codefork.aoc2024.util.FoldLeft.foldLeft;
19-
208
public class Part01 extends Problem {
219

22-
public record Position(int x, int y) {
23-
24-
}
25-
26-
public record Button(String symbol, Position pos) {
27-
28-
public boolean isAdjacent(Button other) {
29-
var xDiff = Math.abs(pos().x() - other.pos().x());
30-
var yDiff = Math.abs(pos().y() - other.pos().y());
31-
return xDiff + yDiff == 1;
32-
}
33-
34-
/**
35-
* returns the action symbol when navigating from this button to (adjacent) target
36-
*/
37-
public String getAction(Button target) {
38-
var xDiff = pos().x() - target.pos().x();
39-
var yDiff = pos().y() - target.pos().y();
40-
if(xDiff > 0) {
41-
return "<";
42-
} else if(xDiff < 0) {
43-
return ">";
44-
}
45-
if(yDiff > 0) {
46-
return "^";
47-
} else if (yDiff < 0) {
48-
return "v";
49-
}
50-
throw new RuntimeException("buttons aren't adjacent in getAction=" + this + "," + target);
51-
}
52-
53-
public String toString() {
54-
return symbol + "(" + pos.x() + "," + pos.y() + ")";
55-
}
56-
}
57-
58-
public record Move(Button from, Button to) {
59-
60-
}
61-
62-
public record ShortestPaths(Button source, Map<Button, Integer> dist, Map<Button, Set<Button>> prev) {
63-
64-
// Dijkstra, yet again.
65-
// this is probably overkill since there's not weighted edges in the graph
66-
// but I've already implemented it twice so far for AoC, so it's the easiest way
67-
// for me to create shortest paths at this point
68-
private static ShortestPaths create(List<Button> buttons, Map<Button, List<Button>> graph, Button source) {
69-
record ButtonWithDist(Button button, int dist) {
70-
71-
}
72-
var dist = new HashMap<Button, Integer>();
73-
var prev = new HashMap<Button, Set<Button>>();
74-
var q = new HashSet<Button>();
75-
76-
for(var button : buttons) {
77-
dist.put(button, Integer.MAX_VALUE);
78-
q.add(button);
79-
}
80-
dist.put(source, 0);
81-
82-
while(!q.isEmpty()) {
83-
var u = q.stream()
84-
.map(button -> new ButtonWithDist(button, dist.get(button)))
85-
.min(Comparator.comparingInt(ButtonWithDist::dist))
86-
.orElseThrow()
87-
.button();
88-
q.remove(u);
89-
90-
var neighborsInQ = graph.get(u).stream()
91-
.filter(q::contains)
92-
.toList();
93-
94-
for(var v : neighborsInQ) {
95-
var alt = dist.get(u) + 1;
96-
if (alt <= dist.get(v)) {
97-
dist.put(v, alt);
98-
if(!prev.containsKey(v)) {
99-
prev.put(v, new HashSet<>());
100-
}
101-
prev.get(v).add(u);
102-
}
103-
}
104-
}
105-
return new ShortestPaths(source, dist, prev);
106-
}
107-
108-
/**
109-
* get all the possible paths for navigating from source to target
110-
*/
111-
public List<List<Button>> getPaths(Button target) {
112-
var paths = new ArrayList<List<Button>>();
113-
paths.add(new LinkedList<>(List.of(target)));
114-
var finalPaths = new ArrayList<List<Button>>();
115-
while(!paths.isEmpty()) {
116-
var newPaths = new ArrayList<List<Button>>();
117-
for(var path : paths) {
118-
var u = path.getFirst();
119-
if(prev.containsKey(u)){
120-
var allPrev = prev.get(u);
121-
for(var prevItem : allPrev) {
122-
var newPath = new LinkedList<>(path);
123-
newPath.addFirst(prevItem);
124-
newPaths.add(newPath);
125-
}
126-
127-
} else if (u.equals(source)) {
128-
finalPaths.add(path);
129-
}
130-
}
131-
paths = newPaths;
132-
}
133-
//System.out.println(source + "->" + target + ", returning " + finalPaths.size() + " finalPaths=" + finalPaths);
134-
return finalPaths;
135-
}
136-
137-
public List<String> getPossiblePressSequences(Button target) {
138-
var paths = getPaths(target);
139-
return paths.stream()
140-
.map(path -> {
141-
return IntStream.range(1, path.size()).boxed()
142-
.collect(foldLeft(
143-
StringBuilder::new,
144-
(acc, i) -> {
145-
var button = path.get(i);
146-
var prevButton = path.get(i - 1);
147-
var action = prevButton.getAction(button);
148-
acc.append(action);
149-
return acc;
150-
})
151-
)
152-
.append("A")
153-
.toString();
154-
})
155-
.toList();
156-
}
157-
}
158-
159-
public static class Keypad {
160-
private final List<Button> buttons;
161-
162-
private final Map<String, Button> buttonsMap;
163-
164-
private final Map<Move, List<String>> movesToPaths;
165-
166-
public Keypad(List<Button> buttons) {
167-
this.buttons = buttons;
168-
this.buttonsMap = buttons.stream()
169-
.collect(Collectors.toMap(
170-
Button::symbol,
171-
b -> b));
172-
173-
this.movesToPaths = createShortestPaths();
174-
}
175-
176-
private Map<Move, List<String>> createShortestPaths() {
177-
Map<Move, List<String>> result = new HashMap<>();
178-
179-
// generate graph of adjacent buttons
180-
var graph = new HashMap<Button, List<Button>>();
181-
for(var i=0; i < buttons.size(); i++) {
182-
var button1 = buttons.get(i);
183-
for(var j=i; j < buttons.size(); j++) {
184-
var button2 = buttons.get(j);
185-
if(button1.isAdjacent(button2)) {
186-
if(!graph.containsKey(button1)) {
187-
graph.put(button1, new ArrayList<>());
188-
}
189-
graph.get(button1).add(button2);
190-
if(!graph.containsKey(button2)) {
191-
graph.put(button2, new ArrayList<>());
192-
}
193-
graph.get(button2).add(button1);
194-
}
195-
}
196-
}
197-
198-
// generate shortest paths for every button to every other button
199-
for(var i=0; i < buttons.size(); i++) {
200-
var button1 = buttons.get(i);
201-
var shortestPaths = ShortestPaths.create(buttons, graph, button1);
202-
var otherButtons = buttons.stream().filter(b -> !b.equals(button1)).toList();
203-
for (var button2 : otherButtons) {
204-
var presses = shortestPaths.getPossiblePressSequences(button2);
205-
//System.out.println("move " + button1 + "->" + button2 + " adding presses=" + presses);
206-
result.put(new Move(button1, button2), presses);
207-
}
208-
}
209-
return result;
210-
}
211-
212-
public Map<String, Button> getButtonsMap() {
213-
return buttonsMap;
214-
}
215-
216-
public Map<Move, List<String>> getMovesToPaths() {
217-
return movesToPaths;
218-
}
219-
}
220-
221-
public static class KeypadNavigator {
222-
223-
private final Keypad keypad;
224-
private final Button current;
225-
226-
public KeypadNavigator(Keypad keypad, String current) {
227-
this.keypad = keypad;
228-
this.current = this.keypad.getButtonsMap().get(current);
229-
}
230-
231-
public List<String> getPossiblePressSequences(String seq) {
232-
List<StringBuilder> pressSeqList = new ArrayList<>();
233-
pressSeqList.add(new StringBuilder());
234-
var c = current;
235-
while(!seq.isEmpty()) {
236-
var newPressSeqList = new ArrayList<StringBuilder>();
237-
var symbol = seq.substring(0, 1);
238-
var next = keypad.getButtonsMap().get(symbol);
239-
if(next.equals(c)) {
240-
for(var pressSeq : pressSeqList) {
241-
pressSeq.append("A");
242-
newPressSeqList.add(pressSeq);
243-
}
244-
} else {
245-
var move = new Move(c, next);
246-
var paths = keypad.getMovesToPaths().get(move);
247-
for(var pressSeq : pressSeqList) {
248-
for(var path : paths) {
249-
var copy = new StringBuilder(pressSeq.toString());
250-
copy.append(path);
251-
//System.out.println("move " + move + ", appended " + path + ", copy is: " + copy);
252-
newPressSeqList.add(copy);
253-
}
254-
}
255-
}
256-
pressSeqList = newPressSeqList;
257-
c = next;
258-
seq = seq.substring(1);
259-
}
260-
return pressSeqList.stream()
261-
.map(StringBuilder::toString)
262-
.toList();
263-
}
264-
265-
}
266-
267-
public static class DoorKeypadNavigator extends KeypadNavigator {
268-
269-
private static final List<Button> doorButtons = List.of(
270-
new Button("7", new Position(0, 0)),
271-
new Button("8", new Position(1, 0)),
272-
new Button("9", new Position(2, 0)),
273-
new Button("4", new Position(0, 1)),
274-
new Button("5", new Position(1, 1)),
275-
new Button("6", new Position(2, 1)),
276-
new Button("1", new Position(0, 2)),
277-
new Button("2", new Position(1, 2)),
278-
new Button("3", new Position(2, 2)),
279-
new Button("0", new Position(1, 3)),
280-
new Button("A", new Position(2, 3))
281-
);
282-
283-
private static final Keypad doorKeypad = new Keypad(doorButtons);
284-
285-
public DoorKeypadNavigator(String startSymbol) {
286-
super(doorKeypad, startSymbol);
287-
}
288-
289-
}
290-
291-
public static class DirectionalKeypadNavigator extends KeypadNavigator {
292-
293-
private static final List<Button> robotButtons = List.of(
294-
new Button("^", new Position(1, 0)),
295-
new Button("A", new Position(2, 0)),
296-
new Button("<", new Position(0, 1)),
297-
new Button("v", new Position(1, 1)),
298-
new Button(">", new Position(2, 1))
299-
);
300-
301-
private static final Keypad robotKeypad = new Keypad(robotButtons);
302-
303-
public DirectionalKeypadNavigator(String startSymbol) {
304-
super(robotKeypad, startSymbol);
305-
}
306-
307-
}
308-
309-
public int getNumericPortion(String str) {
310-
return Integer.parseInt(str.chars()
311-
.boxed()
312-
.map(ch -> String.valueOf((char) ch.intValue()))
313-
.filter(s -> {
314-
try {
315-
Integer.parseInt(s);
316-
} catch(NumberFormatException e) {
317-
return false;
318-
}
319-
return true;
320-
})
321-
.collect(Collectors.joining()));
322-
}
323-
32410
public String solve(Stream<String> data) {
325-
var navigators = List.of(
326-
new DoorKeypadNavigator("A"),
327-
new DirectionalKeypadNavigator("A"),
328-
new DirectionalKeypadNavigator("A")
329-
);
330-
331-
var complexities = data
332-
.map(seq -> {
333-
System.out.println("doing " + seq);
334-
// run each sequence through a list of navigators, collecting results
335-
var pressesList = List.of(seq);
336-
for (var navigator : navigators) {
337-
var newPressesList = new ArrayList<String>();
338-
for (var presses : pressesList) {
339-
var possiblePresses = navigator.getPossiblePressSequences(presses);
340-
for (var p : possiblePresses) {
341-
System.out.println(p);
342-
}
343-
newPressesList.addAll(possiblePresses);
344-
}
345-
346-
// var lengthCounts = newPressesList.stream()
347-
// .collect(Collectors.toMap(
348-
// String::length,
349-
// s -> 1,
350-
// Integer::sum
351-
// ));
352-
// for(var len : lengthCounts.keySet().stream().sorted(Integer::compareTo).toList()) {
353-
// System.out.println("press sequences with len = " + len +
354-
// " occurred " + lengthCounts.get(len) + " times");
355-
// }
356-
357-
// group press sequences by their "signature" (where/which elements repeat)
358-
359-
360-
System.out.println(navigator + " found " + newPressesList.size() + " possible presses");
361-
362-
pressesList = newPressesList;
363-
}
364-
System.out.println("found " + pressesList.size() + " possible presses for last navigator");
365-
// find the shortest path of the LAST navigator only
366-
var shortestPress = pressesList.stream()
367-
.min(Comparator.comparingInt(String::length))
368-
.orElseThrow();
369-
System.out.println("shortest press found is "+ shortestPress.length() + " long");
370-
var result = shortestPress.length() * getNumericPortion(seq);
371-
return result;
372-
})
373-
.toList();
374-
375-
var total = complexities.stream().mapToInt(i -> i).sum();
376-
return String.valueOf(total);
11+
return String.valueOf(ShipLock.calculateSumOfComplexities(data, 2));
37712
}
37813

37914
@Override
38015
public String solve() {
38116
Assert.assertEquals("126384", solve(getSampleInput()));
382-
//return solve(getInput());
383-
return "";
17+
return solve(getInput());
38418
}
38519

38620
public static void main(String[] args) {
38721
new Part01().run();
38822
}
23+
38924
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /