11package com .adventofcode .flashk .day17 ;
22
33import com .adventofcode .flashk .common .Vector2 ;
4- import org .apache .commons .lang3 .tuple .Pair ;
4+ import org .apache .commons .lang3 .tuple .ImmutablePair ;
55
6+ import java .util .LinkedList ;
67import java .util .List ;
7- import java .util .Optional ;
88import java .util .PriorityQueue ;
99
1010public class ClumsyCrucibleRefactor {
11- private Tile destination ;
12- private Tile [][] map ;
11+
12+ public static final Vector2 RIGHT = Vector2 .right ();
13+ public static final Vector2 LEFT = Vector2 .left ();
14+ public static final Vector2 UP = Vector2 .down ();
15+ public static final Vector2 DOWN = Vector2 .up ();
16+
17+ private final Tile destination ;
18+ private final Tile [][] map ;
1319 private final int rows ;
1420 private final int cols ;
1521
@@ -29,75 +35,118 @@ public ClumsyCrucibleRefactor(int[][] inputs) {
2935 public long solveA () {
3036 PriorityQueue <TileStatus > queue = new PriorityQueue <>();
3137
32- Vector2 startPosition = new Vector2 (0 ,0 );
33- int startingTravelDistance = 0 ;
34- Tile startingTile = map [startPosition .getY ()][startPosition .getX ()];
35- startingTile .setTotalHeatloss (0 );
38+ Tile root = map [0 ][0 ];
39+ root .setTotalHeatloss (0 );
3640
37- queue .add (new TileStatus (startingTile , new Vector2 (1 ,0 ), startingTravelDistance ));
38- //queue.add(new TileStatus(startingTile, new Vector2(0,1), startingTravelDistance));
41+ queue .add (new TileStatus (root , new Vector2 (0 ,0 ), 0 ));
3942
4043 // Start algorithm
4144 while (!queue .isEmpty ()) {
4245
4346 // Get a vertex+direction+travel distance combination
44- TileStatus currentTileTriple = queue .poll ();
45- Tile currentTile = currentTileTriple .getTile ();
46- Vector2 currentDirection = currentTileTriple .getDirection ();
47- int currentTravelDistance = currentTileTriple .getLength ();
48- //Pair<Vector2, Integer> visitedPair = ImmutablePair.of(currentDirection, currentTravelDistance);
49- //currentTile.visit(visitedPair);
47+ TileStatus minTileStatus = queue .poll ();
48+
49+ // Mark as visited
50+ Tile minTile = minTileStatus .getTile ();
51+ Vector2 direction = minTileStatus .getDirection ();
52+ int steps = minTileStatus .getLength ();
53+ minTile .visit (ImmutablePair .of (direction , steps ));
5054
5155 // Obtain candidates for Tile
52- List <Pair <Vector2 ,Integer >> nextDirections = currentTile .nextDirections (currentDirection , currentTravelDistance );
53-
54- for (Pair <Vector2 , Integer > nextDirection : nextDirections ) {
55- Optional <Tile > nextTile = nextTile (nextDirection , currentTile );
56- if (nextTile .isPresent ()) {
57- nextTile .get ().visit (nextDirection );
58- TileStatus nextTileTriple = new TileStatus (nextTile .get (), nextDirection .getLeft (), nextDirection .getRight ());
59- queue .add (nextTileTriple );
56+ List <TileStatus > adjacentTiles = getAdjacentTiles (minTileStatus );
57+
58+ for (TileStatus nextTileStatus : adjacentTiles ) {
59+ Tile adjacentTile = nextTileStatus .getTile ();
60+ direction = nextTileStatus .getDirection ();
61+ steps = nextTileStatus .getLength ();
62+
63+ if (!adjacentTile .isVisited (ImmutablePair .of (direction , steps ))) {
64+
65+ // Cost of moving to the adjacent node
66+ int heatloss = adjacentTile .getHeatloss ();
67+
68+ // Cost of moving to the adjacent node + total cost to reach to this node
69+ int estimatedHeatloss = minTile .getTotalHeatloss () + heatloss ;
70+
71+ if (adjacentTile .getTotalHeatloss () > estimatedHeatloss ) {
72+ adjacentTile .setTotalHeatloss (estimatedHeatloss );
73+ queue .add (nextTileStatus );
74+ }
75+
6076 }
6177 }
6278 }
6379
6480 return destination .getTotalHeatloss ();
6581 }
6682
67- private Optional < Tile > nextTile ( Pair < Vector2 , Integer > nextDirection , Tile currentTile ) {
83+ private List < TileStatus > getAdjacentTiles ( TileStatus currentTileStatus ) {
6884
85+ List <TileStatus > tileStatuses = new LinkedList <>();
86+
87+ Tile currentTile = currentTileStatus .getTile ();
6988 Vector2 currentTilePos = new Vector2 (currentTile .getCol (), currentTile .getRow ());
70- Vector2 nextDirectionVector2 = nextDirection .getLeft ();
71- Vector2 nextPosition = Vector2 .transform (nextDirectionVector2 , currentTilePos );
89+ Vector2 currentDirection = currentTileStatus .getDirection ();
90+ int currentDirectionSteps = currentTileStatus .getLength ();
91+
92+ // Filter reversed direction
93+ Vector2 reversedDirection = new Vector2 (currentDirection );
94+ reversedDirection .multiply (-1 );
95+
96+ // Right
97+ Vector2 nextDirection = RIGHT ;
98+ Vector2 nextPosition = Vector2 .transform (currentTilePos , nextDirection );
99+ int nextDirectionSteps = nextSteps (nextDirection , currentDirection , currentDirectionSteps );
100+
101+ if (isNotOutOfBounds (nextPosition ) && !nextDirection .equals (reversedDirection ) && nextDirectionSteps < 4 ) {
102+ tileStatuses .add (createTileStatus (nextPosition , nextDirection , nextDirectionSteps ));
103+ }
104+
105+ // Left
106+ nextDirection = LEFT ;
107+ nextPosition = Vector2 .transform (currentTilePos , nextDirection );
108+ nextDirectionSteps = nextSteps (nextDirection , currentDirection , currentDirectionSteps );
109+
110+ if (isNotOutOfBounds (nextPosition ) && !nextDirection .equals (reversedDirection ) && nextDirectionSteps < 4 ) {
111+ tileStatuses .add (createTileStatus (nextPosition , nextDirection , nextDirectionSteps ));
112+ }
72113
73- // Exclude out of bounds tiles
74- if (nextPosition .getX () >= 0 &&
75- nextPosition .getX () < cols &&
76- nextPosition .getY () >= 0 &&
77- nextPosition .getY () < rows ) {
114+ // Down
115+ nextDirection = DOWN ;
116+ nextPosition = Vector2 .transform (currentTilePos , nextDirection );
117+ nextDirectionSteps = nextSteps (nextDirection , currentDirection , currentDirectionSteps );
78118
119+ if (isNotOutOfBounds (nextPosition ) && !nextDirection .equals (reversedDirection ) && nextDirectionSteps < 4 ) {
120+ tileStatuses .add (createTileStatus (nextPosition , nextDirection , nextDirectionSteps ));
121+ }
79122
80- Tile nextTile = map [nextPosition .getY ()][nextPosition .getX ()];
123+ // Up
124+ nextDirection = UP ;
125+ nextPosition = Vector2 .transform (currentTilePos , nextDirection );
126+ nextDirectionSteps = nextSteps (nextDirection , currentDirection , currentDirectionSteps );
81127
82- // Cost of moving to the adjacent tile
83- int heatloss = nextTile .getHeatloss ();
128+ if (isNotOutOfBounds (nextPosition ) && !nextDirection .equals (reversedDirection ) && nextDirectionSteps < 4 ) {
129+ tileStatuses .add (createTileStatus (nextPosition , nextDirection , nextDirectionSteps ));
130+ }
84131
85- // Cost of moving to the adjacent tile + total cost to reach to this tile
86- int estimatedHeatloss = heatloss + currentTile . getTotalHeatloss ();
132+ return tileStatuses ;
133+ }
87134
88- // Dijkstra condition Include only if next direction is not visited and it is promising.
89- if (!nextTile .isVisited (nextDirection ) && nextTile .getTotalHeatloss () > estimatedHeatloss ) {
90- nextTile .setTotalHeatloss (estimatedHeatloss );
91- return Optional .of (nextTile );
92- }
93135
136+ private TileStatus createTileStatus (Vector2 nextPosition , Vector2 nextDirection , int nextDirectionSteps ) {
137+ Tile nextTile = map [nextPosition .getY ()][nextPosition .getX ()];
138+ return new TileStatus (nextTile , nextDirection , nextDirectionSteps );
139+ }
94140
141+ private int nextSteps (Vector2 nextDirection , Vector2 currentDirection , int currentSteps ) {
142+ if (nextDirection .equals (currentDirection )) {
143+ return currentSteps + 1 ;
95144 }
96-
97- return Optional .empty ();
145+ return 1 ;
98146 }
99147
100-
101-
148+ private boolean isNotOutOfBounds (Vector2 position ) {
149+ return (position .getY () >= 0 && position .getY () < rows ) && (position .getX () >= 0 && position .getX () < cols );
150+ }
102151
103152}
0 commit comments