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

Appearance settings

Commit 1f7a19f

Browse filesBrowse files
committed
Day 12
1 parent e413e5b commit 1f7a19f
Copy full SHA for 1f7a19f

File tree

2 files changed

+189
-0
lines changed
Filter options

2 files changed

+189
-0
lines changed

‎src/test/java/com/macasaet/Day12.java

Copy file name to clipboard
+182Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package com.macasaet;
2+
3+
import java.util.*;
4+
import java.util.stream.Stream;
5+
import java.util.stream.StreamSupport;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
/**
10+
* --- Day 12: Passage Pathing ---
11+
*/
12+
public class Day12 {
13+
14+
protected Stream<String> getInput() {
15+
return StreamSupport
16+
.stream(new LineSpliterator("day-12.txt"),
17+
false);
18+
}
19+
20+
/**
21+
* @return a map of the connected caves
22+
*/
23+
protected Map<String, Node> getMap() {
24+
final var map = new HashMap<String, Node>();
25+
getInput().forEach(line -> {
26+
final var components = line.split("-");
27+
final var sourceLabel = components[0];
28+
final var targetLabel = components[1];
29+
final var source = map.computeIfAbsent(sourceLabel, Node::new);
30+
final var target = map.computeIfAbsent(targetLabel, Node::new);
31+
source.connected.add(target);
32+
target.connected.add(source);
33+
});
34+
return Collections.unmodifiableMap(map);
35+
}
36+
37+
public Node getStartingPoint() {
38+
return getMap().get("start");
39+
}
40+
41+
/**
42+
* A distinct path through the cave system
43+
*/
44+
public record Path(List<Node> nodes, Node specialCave, int specialCaveVisits) {
45+
46+
public int hashCode() {
47+
int result = 0;
48+
for (final var node : nodes()) {
49+
result = result * 31 + node.hashCode();
50+
}
51+
return result;
52+
}
53+
54+
public boolean equals(final Object o) {
55+
if (o == null) {
56+
return false;
57+
}
58+
try {
59+
final var other = (Path) o;
60+
return nodes().equals(other.nodes());
61+
} catch (final ClassCastException cce) {
62+
return false;
63+
}
64+
}
65+
}
66+
67+
public static class Node {
68+
private final boolean isStart;
69+
private final boolean isEnd;
70+
private final boolean isSmallCave;
71+
private final String label;
72+
73+
private final Set<Node> connected = new HashSet<>();
74+
75+
public Node(final String label) {
76+
this("start".equalsIgnoreCase(label), "end".equalsIgnoreCase(label),
77+
label.toLowerCase(Locale.ROOT).equals(label), label);
78+
}
79+
80+
protected Node(boolean isStart, boolean isEnd, boolean isSmallCave, final String label) {
81+
this.isStart = isStart;
82+
this.isEnd = isEnd;
83+
this.isSmallCave = isSmallCave;
84+
this.label = label;
85+
}
86+
87+
public int hashCode() {
88+
int result = 0;
89+
result += result * 31 + label.hashCode();
90+
return result;
91+
}
92+
93+
public boolean equals(final Object o) {
94+
if (o == null) {
95+
return false;
96+
}
97+
try {
98+
final Node other = (Node) o;
99+
return label.equals(other.label);
100+
} catch (final ClassCastException cce) {
101+
return false;
102+
}
103+
}
104+
105+
}
106+
107+
protected Set<Path> getPaths(final Node node, final Path pathSoFar) {
108+
final var result = new HashSet<Path>();
109+
110+
if (node.isStart && pathSoFar.nodes.size() > 1) {
111+
// "once you leave the start cave, you may not return to it"
112+
return Collections.emptySet();
113+
}
114+
115+
final var nodes = new ArrayList<>(pathSoFar.nodes());
116+
if (node.isEnd) {
117+
// "once you reach the end cave, the path must end immediately"
118+
nodes.add(node);
119+
return Collections.singleton(new Path(Collections.unmodifiableList(nodes), pathSoFar.specialCave(), pathSoFar.specialCaveVisits()));
120+
}
121+
int specialCaveVisits = pathSoFar.specialCaveVisits();
122+
if (node.isSmallCave) {
123+
if (node.equals(pathSoFar.specialCave())) {
124+
// "a single small cave can be visited at most twice"
125+
if (pathSoFar.specialCaveVisits() < 1) {
126+
specialCaveVisits++;
127+
} else {
128+
return Collections.emptySet();
129+
}
130+
} else {
131+
if (pathSoFar.nodes().contains(node)) {
132+
// "the remaining small caves can be visited at most once"
133+
return Collections.emptySet();
134+
}
135+
}
136+
}
137+
nodes.add(node);
138+
for (final var neighbour : node.connected) {
139+
if (neighbour.isSmallCave && pathSoFar.specialCave() == null) {
140+
result.addAll(getPaths(neighbour, new Path(Collections.unmodifiableList(nodes), null, 0)));
141+
result.addAll(getPaths(neighbour, new Path(Collections.unmodifiableList(nodes), neighbour, 0)));
142+
} else {
143+
result.addAll(getPaths(neighbour, new Path(Collections.unmodifiableList(nodes), pathSoFar.specialCave(), specialCaveVisits)));
144+
}
145+
}
146+
return Collections.unmodifiableSet(result);
147+
}
148+
149+
protected int countPaths(final Node node, final Set<Node> visitedSmallCaves) {
150+
int result = 0;
151+
if (node.isEnd) {
152+
return 1;
153+
}
154+
if (visitedSmallCaves.contains(node)) {
155+
// invalid path
156+
return 0;
157+
}
158+
if (node.isSmallCave) {
159+
visitedSmallCaves.add(node);
160+
}
161+
for (final var connected : node.connected) {
162+
final var set = new HashSet<>(visitedSmallCaves);
163+
result += countPaths(connected, set);
164+
}
165+
return result;
166+
}
167+
168+
@Test
169+
public final void part1() {
170+
final var start = getStartingPoint();
171+
final int result = countPaths(start, new HashSet<>());
172+
System.out.println("Part 1: " + result);
173+
}
174+
175+
@Test
176+
public final void part2() {
177+
final var start = getStartingPoint();
178+
final var paths = getPaths(start, new Path(Collections.emptyList(), null, 0));
179+
System.out.println("Part 2: " + paths.size());
180+
}
181+
182+
}

‎src/test/resources/sample/day-12.txt

Copy file name to clipboard
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
start-A
2+
start-b
3+
A-c
4+
A-b
5+
b-d
6+
A-end
7+
b-end

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.