Skip to content

Commit

Permalink
Solve day 24 puzzle part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
Flashky committed Dec 29, 2023
1 parent 977923d commit 675bda2
Show file tree
Hide file tree
Showing 6 changed files with 285 additions and 3 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@
<artifactId>commons-math3</artifactId>
<version>3.6.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-geometry-euclidean</artifactId>
<version>1.0</version>
</dependency>

</dependencies>

Expand Down
107 changes: 107 additions & 0 deletions src/main/java/com/adventofcode/flashk/day24/Hailstone.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.adventofcode.flashk.day24;

import lombok.Getter;
import org.apache.commons.geometry.euclidean.threed.Vector3D;
import org.apache.commons.geometry.euclidean.threed.line.Line3D;
import org.apache.commons.geometry.euclidean.threed.line.Lines3D;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.numbers.core.Precision;

public class Hailstone {

private Vector3D position;
private Vector3D speed;

@Getter
private Line3D trajectory;

public Hailstone(String input, boolean isPartOne) {
String[] inputParts = input.split("@");
String[] posCoords = StringUtils.deleteWhitespace(inputParts[0]).split(",");
String[] speedCoords = StringUtils.deleteWhitespace(inputParts[1]).split(",");

if(isPartOne) {
posCoords[2] = "0";
speedCoords[2] = "0";
}

position = createVector3D(posCoords);
speed = createVector3D(speedCoords);

//Precision.DoubleEquivalence equivalence = Precision.doubleEquivalenceOfEpsilon(1e-6);
Precision.DoubleEquivalence equivalence = Precision.doubleEquivalenceOfEpsilon(1e-10);

trajectory = Lines3D.fromPointAndDirection(position, speed, equivalence);

}

public boolean intersectsInFuture(Hailstone other, long min, long max) {
Vector3D intersection = trajectory.intersection(other.trajectory);

// Parallel line
if(intersection == null) {
System.out.println("Hailstones's paths are parallel; they never intersect.");
return false;
}

// Check intersection in time
boolean isInFutureA = isInFuture(intersection);
boolean isInFutureB = other.isInFuture(intersection);

if(!isInFutureA && !isInFutureB) {
System.out.println("Hailstones' paths crossed in the past for both hailstones.");
return false;
} else if(!isInFutureA) {
System.out.println("Hailstones' paths crossed in the past for hailstone A.");
return false;
} else if(!isInFutureB) {
System.out.println("Hailstones' paths crossed in the past for hailstone B.");
return false;
}

boolean isInArea = isInArea(intersection, min, max);
if(isInArea) {
System.out.println("Hailstones' paths will cross inside the test area (at x="+intersection.getX()+", y="+intersection.getY()+").");
} else {
System.out.println("Hailstones' paths will cross outside the test area (at x="+intersection.getX()+", y="+intersection.getY()+").");
}

return isInArea;
}

private Vector3D createVector3D(String[] coords) {
return Vector3D.of(Double.valueOf(coords[0]), Double.valueOf(coords[1]), Double.valueOf(coords[2]));
}

private boolean isInFuture(Vector3D intersection) {

double deltaX = intersection.getX() - position.getX();
if((deltaX > 0 && speed.getX() < 0) || (deltaX < 0 && speed.getX() > 0)){
return false;
}

double deltaY = intersection.getY() - position.getY();
if((deltaY > 0 && speed.getY() < 0) || (deltaY < 0 && speed.getY() > 0)){
return false;
}

double deltaZ = intersection.getZ() - position.getZ();
if((deltaZ > 0 && speed.getZ() < 0) || (deltaZ < 0 && speed.getZ() > 0)){
return false;
}

return true;
}

private boolean isInArea(Vector3D intersection, long min, long max){
return intersection.getX() >= min &&
intersection.getX() <= max &&
intersection.getY() >= min &&
intersection.getY() <= max;
}

public boolean samePosition(Hailstone other) {
return position.equals(other.position);
}

}
107 changes: 107 additions & 0 deletions src/main/java/com/adventofcode/flashk/day24/HailstoneRefactor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.adventofcode.flashk.day24;

import org.apache.commons.geometry.euclidean.threed.Vector3D;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.math3.stat.regression.SimpleRegression;
public class HailstoneRefactor {

private Vector3D position;
private Vector3D speed;

private double slope; // m
private double intercept; // b

public HailstoneRefactor(String input, boolean isPartOne) {
String[] inputParts = input.split("@");
String[] posCoords = StringUtils.deleteWhitespace(inputParts[0]).split(",");
String[] speedCoords = StringUtils.deleteWhitespace(inputParts[1]).split(",");

if(isPartOne) {
posCoords[2] = "0";
speedCoords[2] = "0";
}

position = createVector3D(posCoords);
speed = createVector3D(speedCoords);

// Initialize slope and intercept
Vector3D position2 = position.add(speed);

SimpleRegression simpleRegression = new SimpleRegression();
simpleRegression.addData(position.getX(), position.getY());
simpleRegression.addData(position2.getX(), position2.getY());

slope = simpleRegression.getSlope();
intercept = simpleRegression.getIntercept();

}

public boolean intersectsInFuture(HailstoneRefactor other, long min, long max) {

// Parallel trajectories
if(slope == other.slope) {
System.out.println("Hailstones's paths are parallel; they never intersect.");
return false;
}

// Calculate intersection
double intersectX = (other.intercept - intercept) / (slope - other.slope);
double intersectY = slope * intersectX + intercept;

Vector3D intersection = Vector3D.of(intersectX, intersectY, 0);

boolean isInFutureA = isInFuture(intersection);
boolean isInFutureB = other.isInFuture(intersection);

if(!isInFutureA && !isInFutureB) {
System.out.println("Hailstones' paths crossed in the past for both hailstones.");
return false;
} else if(!isInFutureA) {
System.out.println("Hailstones' paths crossed in the past for hailstone A.");
return false;
} else if(!isInFutureB) {
System.out.println("Hailstones' paths crossed in the past for hailstone B.");
return false;
}

boolean isInArea = isInArea(intersection, min, max);
if(isInArea) {
System.out.println("Hailstones' paths will cross inside the test area (at x="+intersection.getX()+", y="+intersection.getY()+").");
} else {
System.out.println("Hailstones' paths will cross outside the test area (at x="+intersection.getX()+", y="+intersection.getY()+").");
}

return isInArea;
}

private Vector3D createVector3D(String[] coords) {
return Vector3D.of(Double.valueOf(coords[0]), Double.valueOf(coords[1]), Double.valueOf(coords[2]));
}

private boolean isInFuture(Vector3D intersection) {

double deltaX = intersection.getX() - position.getX();
if((deltaX > 0 && speed.getX() < 0) || (deltaX < 0 && speed.getX() > 0)){
return false;
}

double deltaY = intersection.getY() - position.getY();
if((deltaY > 0 && speed.getY() < 0) || (deltaY < 0 && speed.getY() > 0)){
return false;
}

double deltaZ = intersection.getZ() - position.getZ();
if((deltaZ > 0 && speed.getZ() < 0) || (deltaZ < 0 && speed.getZ() > 0)){
return false;
}

return true;
}

private boolean isInArea(Vector3D intersection, long min, long max){
return intersection.getX() >= min &&
intersection.getX() <= max &&
intersection.getY() >= min &&
intersection.getY() <= max;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.adventofcode.flashk.day24;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class NeverTellMeTheOdds {

private List<HailstoneRefactor> hailstones;
public NeverTellMeTheOdds(List<String> inputs, boolean isPartOne) {

if(isPartOne) {
hailstones = inputs.stream().map(s -> new HailstoneRefactor(s, true)).toList();
} else {
hailstones = inputs.stream().map(s -> new HailstoneRefactor(s, false)).toList();
}

int a = 3;


}

public long solveA(long min, long max) {

// Compare all hailstones combinations
long result = 0;

List<HailstoneRefactor> hailstonesCopy = new ArrayList<>(hailstones);

while(!hailstonesCopy.isEmpty()) {
Iterator<HailstoneRefactor> hailstoneIterator = hailstonesCopy.iterator();
HailstoneRefactor hailstoneA = hailstoneIterator.next();
while(hailstoneIterator.hasNext()) {
HailstoneRefactor hailstoneB = hailstoneIterator.next();
if(hailstoneA.intersectsInFuture(hailstoneB, min, max)) {
result++;
}
}
hailstonesCopy.remove(0);
}

return result;
}

}
22 changes: 20 additions & 2 deletions src/test/java/com/adventofcode/flashk/day24/Day24Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
import com.adventofcode.flashk.common.test.utils.Timer;
import com.adventofcode.flashk.common.test.utils.Input;

import static org.junit.jupiter.api.Assertions.assertEquals;

@DisplayName(TestDisplayName.DAY_24)
@TestMethodOrder(OrderAnnotation.class)
@Disabled // TODO Remove comment when implemented
public class Day24Test extends PuzzleTest {

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

// Read input file
List<String> inputs = Input.readStringLines(INPUT_FOLDER, TestFilename.INPUT_FILE_SAMPLE);


NeverTellMeTheOdds neverTellMeTheOdds = new NeverTellMeTheOdds(inputs, true);
long result = neverTellMeTheOdds.solveA(7, 27);

assertEquals(2, result);

}

@Test
Expand All @@ -57,6 +63,18 @@ public void testSolvePart1Input() {

// Read input file
List<String> inputs = Input.readStringLines(INPUT_FOLDER, TestFilename.INPUT_FILE);

NeverTellMeTheOdds neverTellMeTheOdds = new NeverTellMeTheOdds(inputs, true);
long result = neverTellMeTheOdds.solveA(200000000000000L, 400000000000000L);

//System.out.println("R: "+result);
assertEquals(17244, result);

// Con el algoritmo de Hailstone:
// 683 -> That's not the right answer; your answer is too low.

// Con el algoritmo de HailstoneRefactor:
// 17244 -> OK

}

Expand Down
2 changes: 1 addition & 1 deletion src/test/resources/inputs

0 comments on commit 675bda2

Please sign in to comment.