Skip to content

Commit a29691d

Browse files
committed
feat: solve day 16 part 2 WIP
1 parent 31bfcbd commit a29691d

File tree

3 files changed

+269
-8
lines changed

3 files changed

+269
-8
lines changed

src/main/java/com/adventofcode/flashk/day16/ReindeerMaze.java

Lines changed: 166 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.adventofcode.flashk.day16;
22

33
import com.adventofcode.flashk.common.Vector2;
4+
import org.jetbrains.annotations.NotNull;
45

56
import java.util.HashSet;
67
import java.util.PriorityQueue;
@@ -16,6 +17,7 @@ public class ReindeerMaze {
1617
private Vector2 startPos;
1718
private Vector2 endPos;
1819
private Tile startTile;
20+
private Tile endTile;
1921

2022
private Set<Vector2> directions = Set.of(Vector2.right(), Vector2.left(), Vector2.up(), Vector2.down());
2123

@@ -32,6 +34,7 @@ public ReindeerMaze(char[][] inputs) {
3234
startTile = map[row][col];
3335
} else if(map[row][col].isEnd()) {
3436
endPos = map[row][col].getPosition();
37+
endTile = map[row][col];
3538
}
3639
}
3740
}
@@ -58,14 +61,20 @@ public ReindeerMaze(char[][] inputs) {
5861
*/
5962

6063
public long solveA2() {
64+
return dijkstra(startTile);
65+
}
66+
67+
private long dijkstra(Tile start) {
68+
69+
reset();
6170

6271
// Initialize start tile
63-
startTile.setScore(0);
64-
startTile.setDirection(Vector2.right());
72+
start.setScore(0);
73+
start.setDirection(Vector2.right());
6574

6675
// Execute dijkstra
6776
PriorityQueue<Tile> tiles = new PriorityQueue<>();
68-
tiles.add(startTile);
77+
tiles.add(start);
6978

7079
while(!tiles.isEmpty()) {
7180
Tile tile = tiles.poll();
@@ -79,6 +88,7 @@ public long solveA2() {
7988
long scoreIncrementer = newDirection.equals(tile.getDirection()) ? 1 : 1001;
8089
if(adjacentTile.getScore() > tile.getScore() + scoreIncrementer) {
8190
adjacentTile.setScore(tile.getScore() + scoreIncrementer);
91+
adjacentTile.setPartialScore(scoreIncrementer);
8292
adjacentTile.setParent(tile);
8393
adjacentTile.setDirection(newDirection);
8494
tiles.add(adjacentTile);
@@ -90,6 +100,130 @@ public long solveA2() {
90100
return map[endPos.getY()][endPos.getX()].getScore();
91101
}
92102

103+
/*
104+
Subproblem for part 2
105+
106+
Looking at the first example there are certain intersections that allow alternative shortest paths:
107+
#.#.###
108+
#..OOOO
109+
###O#O#
110+
#OOO#O.
111+
#O#O#O#
112+
#OOOOO#
113+
#O###.#
114+
#O..#..
115+
#######
116+
117+
Filling with walls to analyze the smaller problem:
118+
119+
########
120+
#.....S#
121+
###.#.##
122+
#...#..#
123+
#.#.#.##
124+
#.....##
125+
#.###.##
126+
#E..#..#
127+
########
128+
129+
Path 1: Path 2: Path 3:
130+
######## ######## ########
131+
#....11# #..2222# #..3333#
132+
###.#1## ###2#.## ###3#.##
133+
#...#1.# #..2#..# #333#..#
134+
#.#.#1## #.#2#.## #3#.#.##
135+
#11111## #222..## #3....##
136+
#1###.## #2###.## #3###.##
137+
#1..#..# #2..#..# #3..#..#
138+
######## ######## ########
139+
140+
- 3 turns - 3 turns - 3 turns
141+
- 11 steps - 11 steps - 11 steps
142+
143+
*/
144+
public long solveB(){
145+
// Idea:
146+
147+
// 1. Primero aplicamos un dijkstra normal para encontrar el camino más corto.
148+
// 2, Metemos en una lista los tiles del camino más corto.
149+
150+
// Ahora recorremos cada tile del camino más corto
151+
// 1. Calculamos los adyacentes de un tile.
152+
// 2. Si la distancia del tile adyacente al inicio + la distancia del tile al final es igual que la distancia
153+
// del camino más corto, entonces estamos ante un camino alternativo.
154+
155+
long score = dijkstra(startTile);
156+
157+
// Parte 1, encontrar las intersecciones que hay en el camino más corto
158+
159+
Set<Tile> intersections = findPathIntersections();
160+
161+
for(Tile intersection : intersections) {
162+
//intersection.setPath(true);
163+
// calcular dijkstra para adyacentes que no formen parte de path
164+
Set<Tile> adjacents = getAdjacentsIncludingVisited(intersection);
165+
for(Tile adjacent : adjacents) {
166+
if(adjacent.isPath()) {
167+
continue;
168+
}
169+
dijkstra(adjacent);
170+
long adjacentScore = endTile.getScore() + startTile.getScore();
171+
if(adjacentScore == score) {
172+
fillPath(adjacent, endTile);
173+
fillPath(adjacent, startTile);
174+
paint();
175+
System.out.println();
176+
}
177+
}
178+
}
179+
// Pasada 2, buscamos caminos alternativos en cada una de las intersecciones.
180+
181+
//paint();
182+
return countPathTiles();
183+
}
184+
185+
private long countPathTiles() {
186+
long count = 0;
187+
for(int row = 0; row < rows; row++) {
188+
for (int col = 0; col < cols; col++) {
189+
if (map[row][col].isPath()) {
190+
count++;
191+
}
192+
}
193+
}
194+
return count;
195+
}
196+
197+
private Set<Tile> findPathIntersections() {
198+
Set<Tile> intersections = new HashSet<>();
199+
200+
Tile end = map[endPos.getY()][endPos.getX()];
201+
Tile start = map[startPos.getY()][startPos.getX()];
202+
203+
Tile current = end;
204+
do {
205+
current.setPath(true);
206+
if(getAdjacentsIncludingVisited(current).size() > 2) {
207+
intersections.add(current);
208+
}
209+
current = current.getParent();
210+
} while(current != start);
211+
212+
return intersections;
213+
}
214+
215+
216+
private void reset() {
217+
for(int row = 0; row < rows; row++) {
218+
for(int col = 0; col < cols; col++) {
219+
map[row][col].setVisited(false);
220+
map[row][col].setScore(Long.MAX_VALUE);
221+
map[row][col].setParent(null);
222+
//map[row][col].setPath(false);
223+
}
224+
}
225+
}
226+
93227
private void fillPath() {
94228
Tile end = map[endPos.getY()][endPos.getX()];
95229
Tile start = map[startPos.getY()][startPos.getX()];
@@ -99,12 +233,39 @@ private void fillPath() {
99233
current.setPath(true);
100234
}
101235
}
236+
237+
private void fillPath(Tile start, Tile end) {
238+
//Tile start = map[startPos.getY()][startPos.getX()];
239+
//Tile end = map[endPos.getY()][endPos.getX()];
240+
241+
Tile current = end;
242+
while(current != start) {
243+
current = current.getParent();
244+
current.setPath(true);
245+
}
246+
247+
end.setPath(true);
248+
}
249+
102250
private Set<Tile> getAdjacents(Tile parent) {
103251
Set<Tile> adjacents = new HashSet<>();
104252
for(Vector2 dir : directions) {
105253
Vector2 newPos = Vector2.transform(parent.getPosition(), dir);
106254
Tile newTile = map[newPos.getY()][newPos.getX()];
107-
if(!newTile.isWall() & !newTile.isVisited()) {
255+
if(!newTile.isWall() && !newTile.isVisited()) {
256+
adjacents.add(newTile);
257+
}
258+
}
259+
return adjacents;
260+
261+
}
262+
263+
private Set<Tile> getAdjacentsIncludingVisited(Tile parent) {
264+
Set<Tile> adjacents = new HashSet<>();
265+
for(Vector2 dir : directions) {
266+
Vector2 newPos = Vector2.transform(parent.getPosition(), dir);
267+
Tile newTile = map[newPos.getY()][newPos.getX()];
268+
if(!newTile.isWall()) {
108269
adjacents.add(newTile);
109270
}
110271
}
@@ -113,7 +274,7 @@ private Set<Tile> getAdjacents(Tile parent) {
113274
}
114275

115276
private void paint(){
116-
fillPath();
277+
//fillPath();
117278
for(int row = 0; row < rows; row++) {
118279
for(int col = 0; col < cols; col++) {
119280
if(map[row][col].isPath()) {

src/main/java/com/adventofcode/flashk/day16/Tile.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class Tile implements Comparable<Tile>{
1919
private final char value;
2020

2121
private long score = Long.MAX_VALUE;
22+
private long partialScore;
2223
private Tile parent;
2324
private boolean visited = false;
2425
private Vector2 direction;

src/test/java/com/adventofcode/flashk/day16/Day16Test.java

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void testSolvePart1Sample2() {
5454
}
5555

5656
@Test
57-
@Order(2)
57+
@Order(2)
5858
@Tag(TestTag.PART_1)
5959
@Tag(TestTag.INPUT)
6060
@DisplayName(TestDisplayName.PART_1_INPUT)
@@ -68,6 +68,86 @@ public void testSolvePart1Input() {
6868

6969
}
7070

71+
/*
72+
Hay varios mejores caminos (el mejor camino no es único).
73+
Por lo tanto, se trata de encontrar todos los posibles mejores caminos diferentes y contar
74+
cuantas celdas diferentes hay en todos esos caminos solapados entre si.
75+
76+
Por ejemplo, en el primer caso de ejemplo hay 3 posibles caminos con la misma puntuación:
77+
78+
Camino 1:
79+
###############
80+
#.......#....E#
81+
#.#.###.#.###^#
82+
#.....#.#...#^#
83+
#.###.#####.#^#
84+
#.#.#.......#^#
85+
#.#.#####.###^#
86+
#..>>>>>>>>v#^#
87+
###^#.#####v#^#
88+
#>>^#.....#v#^#
89+
#^#.#.###.#v#^#
90+
#^....#...#v#^#
91+
#^###.#.#.#v#^#
92+
#S..#.....#>>^#
93+
###############
94+
95+
Camino 2:
96+
###############
97+
#.......#....E#
98+
#.#.###.#.###^#
99+
#.....#.#...#^#
100+
#.###.#####.#^#
101+
#.#.#.......#^#
102+
#.#.#####.###^#
103+
#..>>>>>>>>v#^#
104+
###^#.#####v#^#
105+
#..^#.....#v#^#
106+
#.#^#.###.#v#^#
107+
#>>^..#...#v#^#
108+
#^###.#.#.#v#^#
109+
#S..#.....#>>^#
110+
###############
111+
112+
Camino 3:
113+
###############
114+
#.......#....E#
115+
#.#.###.#.###^#
116+
#.....#.#...#^#
117+
#.###.#####.#^#
118+
#.#.#.......#^#
119+
#.#.#####.###^#
120+
#....>>>>>>v#^#
121+
###.#^#####v#^#
122+
#...#^....#v#^#
123+
#.#.#^###.#v#^#
124+
#>>>>^#...#v#^#
125+
#^###.#.#.#v#^#
126+
#S..#.....#>>^#
127+
###############
128+
129+
Si nos fijamos en el punto en el cuál todos estos caminos coinciden,
130+
para llegar a dicho punto, todos los caminos hacen:
131+
- 4 giros
132+
- 7 avances
133+
134+
###############
135+
#.......#....O#
136+
#.#.###.#.###O#
137+
#.....#.#...#O#
138+
#.###.#####.#O#
139+
#.#.#.......#O#
140+
#.#.#####.###O#
141+
#..OOOOOOOOO#O#
142+
###O#O#####O#O#
143+
#OOO#O....#O#O#
144+
#O#O#O###.#O#O#
145+
#OOOOO#...#O#O#
146+
#O###.#.#.#O#O#
147+
#O..#.....#OOO#
148+
###############
149+
150+
*/
71151
@Test
72152
@Order(3)
73153
@Tag(TestTag.PART_2)
@@ -77,21 +157,40 @@ public void testSolvePart2Sample() {
77157

78158
// Read input file
79159
char[][] inputs = Input.read2DCharArray(INPUT_FOLDER, TestFilename.INPUT_FILE_SAMPLE);
160+
ReindeerMaze reindeerMaze = new ReindeerMaze(inputs);
80161

81-
assertEquals(0L,0L);
162+
// Me da
163+
assertEquals(45L, reindeerMaze.solveB());
82164
}
83165

84166
@Test
85167
@Order(4)
86168
@Tag(TestTag.PART_2)
169+
@Tag(TestTag.SAMPLE)
170+
@DisplayName(TestDisplayName.PART_2_SAMPLE)
171+
public void testSolvePart2Sample2() {
172+
173+
// Read input file
174+
char[][] inputs = Input.read2DCharArray(INPUT_FOLDER, TestFilename.INPUT_FILE_SINGLE_SAMPLE_2);
175+
ReindeerMaze reindeerMaze = new ReindeerMaze(inputs);
176+
// Me da
177+
assertEquals(64L, reindeerMaze.solveB());
178+
}
179+
180+
@Test
181+
@Order(5)
182+
@Tag(TestTag.PART_2)
87183
@Tag(TestTag.INPUT)
88184
@DisplayName(TestDisplayName.PART_2_INPUT)
89185
public void testSolvePart2Input() {
90186

91187
// Read input file
92188
char[][] inputs = Input.read2DCharArray(INPUT_FOLDER, TestFilename.INPUT_FILE);
189+
ReindeerMaze reindeerMaze = new ReindeerMaze(inputs);
190+
System.out.println("Solution: "+reindeerMaze.solveB());
93191

94-
System.out.println("Solution: ");
192+
// 512 -> too low
193+
95194
assertEquals(0L,0L);
96195

97196
}

0 commit comments

Comments
 (0)