Skip to content

Commit 675bda2

Browse files
committed
Solve day 24 puzzle part 1
1 parent 977923d commit 675bda2

File tree

6 files changed

+285
-3
lines changed

6 files changed

+285
-3
lines changed

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@
7979
<artifactId>commons-math3</artifactId>
8080
<version>3.6.1</version>
8181
</dependency>
82+
<dependency>
83+
<groupId>org.apache.commons</groupId>
84+
<artifactId>commons-geometry-euclidean</artifactId>
85+
<version>1.0</version>
86+
</dependency>
8287

8388
</dependencies>
8489

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package com.adventofcode.flashk.day24;
2+
3+
import lombok.Getter;
4+
import org.apache.commons.geometry.euclidean.threed.Vector3D;
5+
import org.apache.commons.geometry.euclidean.threed.line.Line3D;
6+
import org.apache.commons.geometry.euclidean.threed.line.Lines3D;
7+
import org.apache.commons.lang3.StringUtils;
8+
import org.apache.commons.numbers.core.Precision;
9+
10+
public class Hailstone {
11+
12+
private Vector3D position;
13+
private Vector3D speed;
14+
15+
@Getter
16+
private Line3D trajectory;
17+
18+
public Hailstone(String input, boolean isPartOne) {
19+
String[] inputParts = input.split("@");
20+
String[] posCoords = StringUtils.deleteWhitespace(inputParts[0]).split(",");
21+
String[] speedCoords = StringUtils.deleteWhitespace(inputParts[1]).split(",");
22+
23+
if(isPartOne) {
24+
posCoords[2] = "0";
25+
speedCoords[2] = "0";
26+
}
27+
28+
position = createVector3D(posCoords);
29+
speed = createVector3D(speedCoords);
30+
31+
//Precision.DoubleEquivalence equivalence = Precision.doubleEquivalenceOfEpsilon(1e-6);
32+
Precision.DoubleEquivalence equivalence = Precision.doubleEquivalenceOfEpsilon(1e-10);
33+
34+
trajectory = Lines3D.fromPointAndDirection(position, speed, equivalence);
35+
36+
}
37+
38+
public boolean intersectsInFuture(Hailstone other, long min, long max) {
39+
Vector3D intersection = trajectory.intersection(other.trajectory);
40+
41+
// Parallel line
42+
if(intersection == null) {
43+
System.out.println("Hailstones's paths are parallel; they never intersect.");
44+
return false;
45+
}
46+
47+
// Check intersection in time
48+
boolean isInFutureA = isInFuture(intersection);
49+
boolean isInFutureB = other.isInFuture(intersection);
50+
51+
if(!isInFutureA && !isInFutureB) {
52+
System.out.println("Hailstones' paths crossed in the past for both hailstones.");
53+
return false;
54+
} else if(!isInFutureA) {
55+
System.out.println("Hailstones' paths crossed in the past for hailstone A.");
56+
return false;
57+
} else if(!isInFutureB) {
58+
System.out.println("Hailstones' paths crossed in the past for hailstone B.");
59+
return false;
60+
}
61+
62+
boolean isInArea = isInArea(intersection, min, max);
63+
if(isInArea) {
64+
System.out.println("Hailstones' paths will cross inside the test area (at x="+intersection.getX()+", y="+intersection.getY()+").");
65+
} else {
66+
System.out.println("Hailstones' paths will cross outside the test area (at x="+intersection.getX()+", y="+intersection.getY()+").");
67+
}
68+
69+
return isInArea;
70+
}
71+
72+
private Vector3D createVector3D(String[] coords) {
73+
return Vector3D.of(Double.valueOf(coords[0]), Double.valueOf(coords[1]), Double.valueOf(coords[2]));
74+
}
75+
76+
private boolean isInFuture(Vector3D intersection) {
77+
78+
double deltaX = intersection.getX() - position.getX();
79+
if((deltaX > 0 && speed.getX() < 0) || (deltaX < 0 && speed.getX() > 0)){
80+
return false;
81+
}
82+
83+
double deltaY = intersection.getY() - position.getY();
84+
if((deltaY > 0 && speed.getY() < 0) || (deltaY < 0 && speed.getY() > 0)){
85+
return false;
86+
}
87+
88+
double deltaZ = intersection.getZ() - position.getZ();
89+
if((deltaZ > 0 && speed.getZ() < 0) || (deltaZ < 0 && speed.getZ() > 0)){
90+
return false;
91+
}
92+
93+
return true;
94+
}
95+
96+
private boolean isInArea(Vector3D intersection, long min, long max){
97+
return intersection.getX() >= min &&
98+
intersection.getX() <= max &&
99+
intersection.getY() >= min &&
100+
intersection.getY() <= max;
101+
}
102+
103+
public boolean samePosition(Hailstone other) {
104+
return position.equals(other.position);
105+
}
106+
107+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package com.adventofcode.flashk.day24;
2+
3+
import org.apache.commons.geometry.euclidean.threed.Vector3D;
4+
import org.apache.commons.lang3.StringUtils;
5+
import org.apache.commons.math3.stat.regression.SimpleRegression;
6+
public class HailstoneRefactor {
7+
8+
private Vector3D position;
9+
private Vector3D speed;
10+
11+
private double slope; // m
12+
private double intercept; // b
13+
14+
public HailstoneRefactor(String input, boolean isPartOne) {
15+
String[] inputParts = input.split("@");
16+
String[] posCoords = StringUtils.deleteWhitespace(inputParts[0]).split(",");
17+
String[] speedCoords = StringUtils.deleteWhitespace(inputParts[1]).split(",");
18+
19+
if(isPartOne) {
20+
posCoords[2] = "0";
21+
speedCoords[2] = "0";
22+
}
23+
24+
position = createVector3D(posCoords);
25+
speed = createVector3D(speedCoords);
26+
27+
// Initialize slope and intercept
28+
Vector3D position2 = position.add(speed);
29+
30+
SimpleRegression simpleRegression = new SimpleRegression();
31+
simpleRegression.addData(position.getX(), position.getY());
32+
simpleRegression.addData(position2.getX(), position2.getY());
33+
34+
slope = simpleRegression.getSlope();
35+
intercept = simpleRegression.getIntercept();
36+
37+
}
38+
39+
public boolean intersectsInFuture(HailstoneRefactor other, long min, long max) {
40+
41+
// Parallel trajectories
42+
if(slope == other.slope) {
43+
System.out.println("Hailstones's paths are parallel; they never intersect.");
44+
return false;
45+
}
46+
47+
// Calculate intersection
48+
double intersectX = (other.intercept - intercept) / (slope - other.slope);
49+
double intersectY = slope * intersectX + intercept;
50+
51+
Vector3D intersection = Vector3D.of(intersectX, intersectY, 0);
52+
53+
boolean isInFutureA = isInFuture(intersection);
54+
boolean isInFutureB = other.isInFuture(intersection);
55+
56+
if(!isInFutureA && !isInFutureB) {
57+
System.out.println("Hailstones' paths crossed in the past for both hailstones.");
58+
return false;
59+
} else if(!isInFutureA) {
60+
System.out.println("Hailstones' paths crossed in the past for hailstone A.");
61+
return false;
62+
} else if(!isInFutureB) {
63+
System.out.println("Hailstones' paths crossed in the past for hailstone B.");
64+
return false;
65+
}
66+
67+
boolean isInArea = isInArea(intersection, min, max);
68+
if(isInArea) {
69+
System.out.println("Hailstones' paths will cross inside the test area (at x="+intersection.getX()+", y="+intersection.getY()+").");
70+
} else {
71+
System.out.println("Hailstones' paths will cross outside the test area (at x="+intersection.getX()+", y="+intersection.getY()+").");
72+
}
73+
74+
return isInArea;
75+
}
76+
77+
private Vector3D createVector3D(String[] coords) {
78+
return Vector3D.of(Double.valueOf(coords[0]), Double.valueOf(coords[1]), Double.valueOf(coords[2]));
79+
}
80+
81+
private boolean isInFuture(Vector3D intersection) {
82+
83+
double deltaX = intersection.getX() - position.getX();
84+
if((deltaX > 0 && speed.getX() < 0) || (deltaX < 0 && speed.getX() > 0)){
85+
return false;
86+
}
87+
88+
double deltaY = intersection.getY() - position.getY();
89+
if((deltaY > 0 && speed.getY() < 0) || (deltaY < 0 && speed.getY() > 0)){
90+
return false;
91+
}
92+
93+
double deltaZ = intersection.getZ() - position.getZ();
94+
if((deltaZ > 0 && speed.getZ() < 0) || (deltaZ < 0 && speed.getZ() > 0)){
95+
return false;
96+
}
97+
98+
return true;
99+
}
100+
101+
private boolean isInArea(Vector3D intersection, long min, long max){
102+
return intersection.getX() >= min &&
103+
intersection.getX() <= max &&
104+
intersection.getY() >= min &&
105+
intersection.getY() <= max;
106+
}
107+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.adventofcode.flashk.day24;
2+
3+
import java.util.ArrayList;
4+
import java.util.Iterator;
5+
import java.util.List;
6+
7+
public class NeverTellMeTheOdds {
8+
9+
private List<HailstoneRefactor> hailstones;
10+
public NeverTellMeTheOdds(List<String> inputs, boolean isPartOne) {
11+
12+
if(isPartOne) {
13+
hailstones = inputs.stream().map(s -> new HailstoneRefactor(s, true)).toList();
14+
} else {
15+
hailstones = inputs.stream().map(s -> new HailstoneRefactor(s, false)).toList();
16+
}
17+
18+
int a = 3;
19+
20+
21+
}
22+
23+
public long solveA(long min, long max) {
24+
25+
// Compare all hailstones combinations
26+
long result = 0;
27+
28+
List<HailstoneRefactor> hailstonesCopy = new ArrayList<>(hailstones);
29+
30+
while(!hailstonesCopy.isEmpty()) {
31+
Iterator<HailstoneRefactor> hailstoneIterator = hailstonesCopy.iterator();
32+
HailstoneRefactor hailstoneA = hailstoneIterator.next();
33+
while(hailstoneIterator.hasNext()) {
34+
HailstoneRefactor hailstoneB = hailstoneIterator.next();
35+
if(hailstoneA.intersectsInFuture(hailstoneB, min, max)) {
36+
result++;
37+
}
38+
}
39+
hailstonesCopy.remove(0);
40+
}
41+
42+
return result;
43+
}
44+
45+
}

src/test/java/com/adventofcode/flashk/day24/Day24Test.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@
1919
import com.adventofcode.flashk.common.test.utils.Timer;
2020
import com.adventofcode.flashk.common.test.utils.Input;
2121

22+
import static org.junit.jupiter.api.Assertions.assertEquals;
23+
2224
@DisplayName(TestDisplayName.DAY_24)
2325
@TestMethodOrder(OrderAnnotation.class)
24-
@Disabled // TODO Remove comment when implemented
2526
public class Day24Test extends PuzzleTest {
2627

2728
private final static String INPUT_FOLDER = TestFolder.DAY_24;
@@ -43,7 +44,12 @@ public void testSolvePart1Sample() {
4344

4445
// Read input file
4546
List<String> inputs = Input.readStringLines(INPUT_FOLDER, TestFilename.INPUT_FILE_SAMPLE);
46-
47+
48+
NeverTellMeTheOdds neverTellMeTheOdds = new NeverTellMeTheOdds(inputs, true);
49+
long result = neverTellMeTheOdds.solveA(7, 27);
50+
51+
assertEquals(2, result);
52+
4753
}
4854

4955
@Test
@@ -57,6 +63,18 @@ public void testSolvePart1Input() {
5763

5864
// Read input file
5965
List<String> inputs = Input.readStringLines(INPUT_FOLDER, TestFilename.INPUT_FILE);
66+
67+
NeverTellMeTheOdds neverTellMeTheOdds = new NeverTellMeTheOdds(inputs, true);
68+
long result = neverTellMeTheOdds.solveA(200000000000000L, 400000000000000L);
69+
70+
//System.out.println("R: "+result);
71+
assertEquals(17244, result);
72+
73+
// Con el algoritmo de Hailstone:
74+
// 683 -> That's not the right answer; your answer is too low.
75+
76+
// Con el algoritmo de HailstoneRefactor:
77+
// 17244 -> OK
6078

6179
}
6280

src/test/resources/inputs

0 commit comments

Comments
 (0)