11package com .adventofcode .flashk .day16 ;
22
33import com .adventofcode .flashk .common .Vector2 ;
4+ import org .jetbrains .annotations .NotNull ;
45
56import java .util .HashSet ;
67import 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 ()) {
0 commit comments