Skip to content

Commit aabda3b

Browse files
committed
Explore JGraphT usage on day 16
1 parent 077a699 commit aabda3b

File tree

2 files changed

+211
-0
lines changed

2 files changed

+211
-0
lines changed
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package com.adventofcode.flashk.day16;
2+
3+
import org.apache.commons.lang3.StringUtils;
4+
import org.jgrapht.Graph;
5+
import org.jgrapht.alg.interfaces.ManyToManyShortestPathsAlgorithm;
6+
import org.jgrapht.alg.interfaces.ShortestPathAlgorithm;
7+
import org.jgrapht.alg.shortestpath.DijkstraManyToManyShortestPaths;
8+
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
9+
import org.jgrapht.graph.DefaultEdge;
10+
import org.jgrapht.graph.DefaultUndirectedGraph;
11+
import org.jgrapht.graph.SimpleGraph;
12+
13+
import java.util.*;
14+
import java.util.regex.Matcher;
15+
import java.util.regex.Pattern;
16+
import java.util.stream.Collectors;
17+
18+
public class ProboscideaVolcaniumJGraphT {
19+
20+
private static final String VALVE_REGEX = "Valve ([A-Z]*) has flow rate=(\\d*)";
21+
private static final Pattern VALVE_PATTERN = Pattern.compile(VALVE_REGEX);
22+
private static final String TUNNELS_REGEX = "lead to valves ([,A-Z ]*)|leads to valve ([A-Z]*)";
23+
private static final Pattern TUNNELS_PATTERN = Pattern.compile(TUNNELS_REGEX);
24+
private static final String SEPARATOR = ", ";
25+
public static final int MAX_TIME_PART_1 = 30;
26+
public static final int MAX_TIME_PART_2 = 26;
27+
28+
private Graph<SimpleValve, DefaultEdge> graph = new SimpleGraph<>(DefaultEdge.class);
29+
private ManyToManyShortestPathsAlgorithm.ManyToManyShortestPaths<SimpleValve,DefaultEdge> paths;
30+
private long maxReleasedPressure = 0;
31+
private int maxTime = MAX_TIME_PART_1;
32+
33+
34+
// TODO DijkstraManyToManyShortestPaths
35+
// Método:getManyToManyPaths
36+
// Permite obtenre todos los caminos que hay desde un Set de vértices de origen hasta un set de vértices objetivo
37+
38+
public ProboscideaVolcaniumJGraphT(List<String> inputs) {
39+
40+
for(String input : inputs) {
41+
42+
// Create valves (graph vertex)
43+
SimpleValve currentValve = createValve(input);
44+
45+
// Create tunnels (graph edges)
46+
createTunnel(input, currentValve);
47+
}
48+
49+
// Calculate all shortest paths from all openable valves and starting valve to the all the openable valves.
50+
DijkstraManyToManyShortestPaths<SimpleValve, DefaultEdge> dijkstra = new DijkstraManyToManyShortestPaths<>(graph);
51+
paths = dijkstra.getManyToManyPaths(graph.vertexSet(), getOpenableValves());
52+
53+
System.out.println("test");
54+
}
55+
56+
private SimpleValve createValve(String input) {
57+
58+
Matcher valveMatcher = VALVE_PATTERN.matcher(input);
59+
valveMatcher.find();
60+
61+
String name = valveMatcher.group(1);
62+
int flow = Integer.parseInt(valveMatcher.group(2));
63+
64+
SimpleValve currentValve = getValveOrDefault(name);
65+
currentValve.setFlow(flow);
66+
67+
return currentValve;
68+
}
69+
70+
private void createTunnel(String input, SimpleValve currentValve) {
71+
72+
String[] neighbourNames = getNeighbourNames(input);
73+
74+
graph.addVertex(currentValve);
75+
76+
for(String neighbourName : neighbourNames) {
77+
78+
// Search or create neighbour valve
79+
//SimpleValve neighbourValve = valves.getOrDefault(neighbourName, new SimpleValve(neighbourName));
80+
SimpleValve neighbourValve = getValveOrDefault(neighbourName);
81+
graph.addVertex(neighbourValve);
82+
83+
// Add edge between both
84+
graph.addEdge(currentValve, neighbourValve);
85+
86+
}
87+
}
88+
89+
private static String[] getNeighbourNames(String input) {
90+
Matcher tunnelMatcher = TUNNELS_PATTERN.matcher(input);
91+
tunnelMatcher.find();
92+
93+
String tunnels = tunnelMatcher.group(1);
94+
String tunnel = tunnelMatcher.group(2);
95+
96+
String[] neighbourNames = null;
97+
98+
if(!StringUtils.isBlank(tunnels)) {
99+
neighbourNames = tunnelMatcher.group(1).split(SEPARATOR);
100+
} else if(!StringUtils.isBlank(tunnel)){
101+
neighbourNames = new String[1];
102+
neighbourNames[0] = tunnel;
103+
}
104+
return neighbourNames;
105+
}
106+
107+
public long solveA() {
108+
109+
maxReleasedPressure = 0;
110+
111+
// Always start from "AA" valve
112+
SimpleValve startingValve = getValveOrDefault("AA");
113+
startingValve.setOpen(true); // Consider origin valve as open as its flow is 0
114+
for(SimpleValve nextValve : getOpenableValves()) {
115+
double time = paths.getPath(startingValve, nextValve).getWeight();
116+
releasePressure(nextValve, maxTime, (int) time,0);
117+
}
118+
119+
return maxReleasedPressure;
120+
}
121+
122+
private void releasePressure(SimpleValve currentValve, int remainingTime, int timeToReach, long totalPressure) {
123+
// PRE 1: currentValve no está abierta (hemos prefiltrado)
124+
// PRE 2: La válvula actual da tiempo a abrirla y a producir presión (hemos prefiltrado)
125+
126+
currentValve.setOpen(true);
127+
int remainingTimeAfterOpen = remainingTime - (timeToReach + SimpleValve.OPEN_TIME);
128+
long updatedPressure = totalPressure + currentValve.getFlow() * remainingTimeAfterOpen;
129+
130+
//Set<Valve> candidates = getNextCandidates(remainingTimeAfterOpen);
131+
132+
Set<SimpleValve> candidates = getOpenableValves(currentValve, remainingTimeAfterOpen);
133+
if(candidates.isEmpty()) {
134+
maxReleasedPressure = Math.max(updatedPressure, maxReleasedPressure);
135+
} else {
136+
for(SimpleValve nextValve : candidates) {
137+
double timeToReachNext = paths.getPath(currentValve, nextValve).getWeight();
138+
releasePressure(nextValve, remainingTimeAfterOpen, (int) timeToReachNext, updatedPressure);
139+
}
140+
}
141+
142+
// Backtrack
143+
currentValve.setOpen(false);
144+
}
145+
146+
private SimpleValve getValveOrDefault(String name) {
147+
return graph.vertexSet().stream()
148+
.filter(v -> name.equals(v.getName()))
149+
.findFirst()
150+
.orElse(new SimpleValve(name));
151+
}
152+
153+
private Set<SimpleValve> getOpenableValves(SimpleValve currentValve, int remainingTime) {
154+
return graph.vertexSet().stream()
155+
.filter(v -> !v.isOpen())
156+
.filter(v -> v.getFlow() > 0)
157+
.filter(v -> paths.getPath(currentValve, v).getWeight() + SimpleValve.OPEN_TIME < remainingTime)
158+
.collect(Collectors.toSet());
159+
}
160+
161+
private Set<SimpleValve> getOpenableValves() {
162+
return graph.vertexSet().stream()
163+
.filter(v -> !v.isOpen())
164+
.filter(v -> v.getFlow() > 0)
165+
.collect(Collectors.toSet());
166+
}
167+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.adventofcode.flashk.day16;
2+
3+
import lombok.Getter;
4+
import lombok.Setter;
5+
6+
import java.util.Objects;
7+
8+
@Getter
9+
@Setter
10+
public class SimpleValve {
11+
12+
public static final int OPEN_TIME = 1;
13+
14+
private String name;
15+
private int flow;
16+
private boolean open = false;
17+
18+
public SimpleValve(String name) {
19+
this.name = name;
20+
}
21+
22+
@Override
23+
public int hashCode() {
24+
return Objects.hash(name);
25+
}
26+
27+
@Override
28+
public boolean equals(Object obj) {
29+
if (this == obj)
30+
return true;
31+
if (obj == null)
32+
return false;
33+
if (getClass() != obj.getClass())
34+
return false;
35+
SimpleValve other = (SimpleValve) obj;
36+
return Objects.equals(name, other.name);
37+
}
38+
39+
@Override
40+
public String toString() {
41+
return "Valve [name=" + name + "]";
42+
}
43+
44+
}

0 commit comments

Comments
 (0)