22
33import lombok .Getter ;
44import 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 ;
75import org .apache .commons .lang3 .StringUtils ;
8- import org .apache .commons .numbers . core . Precision ;
6+ import org .apache .commons .math3 . stat . regression . SimpleRegression ;
97
108public class Hailstone {
119
12- private Vector3D position ;
13- private Vector3D speed ;
14-
1510 @ Getter
16- private Line3D trajectory ;
11+ private final Vector3D position ;
1712
13+ @ Getter
14+ private final Vector3D speed ;
15+
16+ private final double slope ; // m
17+ private final double intercept ; // b
18+
1819 public Hailstone (String input , boolean isPartOne ) {
1920 String [] inputParts = input .split ("@" );
2021 String [] posCoords = StringUtils .deleteWhitespace (inputParts [0 ]).split ("," );
@@ -28,69 +29,63 @@ public Hailstone(String input, boolean isPartOne) {
2829 position = createVector3D (posCoords );
2930 speed = createVector3D (speedCoords );
3031
31- //Precision.DoubleEquivalence equivalence = Precision.doubleEquivalenceOfEpsilon(1e-6);
32- Precision .DoubleEquivalence equivalence = Precision .doubleEquivalenceOfEpsilon (1e-10 );
32+ // Initialize slope and intercept
33+ Vector3D position2 = position .add (speed );
34+
35+ SimpleRegression simpleRegression = new SimpleRegression ();
36+ simpleRegression .addData (position .getX (), position .getY ());
37+ simpleRegression .addData (position2 .getX (), position2 .getY ());
3338
34- trajectory = Lines3D .fromPointAndDirection (position , speed , equivalence );
39+ slope = simpleRegression .getSlope ();
40+ intercept = simpleRegression .getIntercept ();
3541
3642 }
3743
3844 public boolean intersectsInFuture (Hailstone other , long min , long max ) {
39- Vector3D intersection = trajectory .intersection (other .trajectory );
4045
41- // Parallel line
42- if (intersection == null ) {
43- System .out .println ("Hailstones's paths are parallel; they never intersect." );
44- return false ;
46+ if (slope == other .slope ) {
47+ return false ; // Hailstones' paths are parallel; they never intersect.
4548 }
4649
47- // Check intersection in time
48- boolean isInFutureA = isInFuture ( intersection );
49- boolean isInFutureB = other . isInFuture ( intersection ) ;
50+ // Calculate intersection
51+ double intersectX = ( other . intercept - intercept ) / ( slope - other . slope );
52+ double intersectY = slope * intersectX + intercept ;
5053
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- }
54+ Vector3D intersection = Vector3D .of (intersectX , intersectY , 0 );
6155
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 ()+")." );
56+ // Intersection might have 4 different cases:
57+ // - Hailstones' paths crossed in the past for both hailstones. (false)
58+ // - Hailstones' paths crossed in the past for hailstone A. (false)
59+ // - Hailstones' paths crossed in the past for hailstone B. (false)
60+ // - Hailstones' paths cross in the future (true)
61+ if (isNotInFuture (intersection ) || other .isNotInFuture (intersection )) {
62+ return false ;
6763 }
6864
69- return isInArea ;
65+ // Two cases:
66+ // - Hailstones' paths cross inside the test area
67+ // - Hailstones' paths cross outisde the test area
68+ return isInArea (intersection , min , max );
7069 }
7170
7271 private Vector3D createVector3D (String [] coords ) {
73- return Vector3D .of (Double .valueOf (coords [0 ]), Double .valueOf (coords [1 ]), Double .valueOf (coords [2 ]));
72+ return Vector3D .of (Double .parseDouble (coords [0 ]), Double .parseDouble (coords [1 ]), Double .parseDouble (coords [2 ]));
7473 }
7574
76- private boolean isInFuture (Vector3D intersection ) {
75+ private boolean isNotInFuture (Vector3D intersection ) {
7776
7877 double deltaX = intersection .getX () - position .getX ();
7978 if ((deltaX > 0 && speed .getX () < 0 ) || (deltaX < 0 && speed .getX () > 0 )){
80- return false ;
79+ return true ;
8180 }
8281
8382 double deltaY = intersection .getY () - position .getY ();
8483 if ((deltaY > 0 && speed .getY () < 0 ) || (deltaY < 0 && speed .getY () > 0 )){
85- return false ;
84+ return true ;
8685 }
8786
8887 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 ;
88+ return (deltaZ > 0 && speed .getZ () < 0 ) || (deltaZ < 0 && speed .getZ () > 0 );
9489 }
9590
9691 private boolean isInArea (Vector3D intersection , long min , long max ){
@@ -99,9 +94,4 @@ private boolean isInArea(Vector3D intersection, long min, long max){
9994 intersection .getY () >= min &&
10095 intersection .getY () <= max ;
10196 }
102-
103- public boolean samePosition (Hailstone other ) {
104- return position .equals (other .position );
105- }
106-
10797}
0 commit comments