1
1
package com .sbaars .adventofcode .year23 .days ;
2
2
3
+ import com .sbaars .adventofcode .common .Pair ;
4
+ import com .sbaars .adventofcode .common .location .Loc ;
3
5
import com .sbaars .adventofcode .common .location .Loc3D ;
4
6
import com .sbaars .adventofcode .year23 .Day2023 ;
5
7
8
+ import java .util .List ;
9
+ import java .util .TreeMap ;
10
+ import java .util .function .Function ;
11
+
6
12
import static com .sbaars .adventofcode .util .DataMapper .readString ;
13
+ import static java .util .stream .Collectors .toMap ;
14
+ import static java .util .stream .IntStream .range ;
7
15
8
16
public class Day24 extends Day2023 {
9
17
@@ -15,20 +23,89 @@ public static void main(String[] args) {
15
23
new Day24 ().printParts ();
16
24
}
17
25
18
- public record Input (Loc3D pos , Loc3D vel ) {
19
- public Input (long posX , long posY , long posZ , long velX , long velY , long velZ ) {
26
+ public record Rock (Loc3D p , Loc3D v ) {
27
+ private static final long min = 200000000000000L ;
28
+ private static final long max = 400000000000000L ;
29
+
30
+ public Rock (long posX , long posY , long posZ , long velX , long velY , long velZ ) {
20
31
this (new Loc3D (posX , posY , posZ ), new Loc3D (velX , velY , velZ ));
21
32
}
33
+
34
+ public Rock positionAt (long t ) {
35
+ return new Rock (p .move (v .multiply (t )), v );
36
+ }
37
+
38
+ boolean willReach (double x , double y ) {
39
+ double dx = x - p .x ;
40
+ double dy = y - p .y ;
41
+ return switch (dx > 0 ? 1 : dx < 0 ? -1 : 0 ) {
42
+ case 0 -> switch (dy > 0 ? 1 : dy < 0 ? -1 : 0 ) {
43
+ case 0 -> false ;
44
+ case 1 -> v .y > 0 ;
45
+ default -> v .y < 0 ;
46
+ };
47
+ case 1 -> v .x > 0 ;
48
+ default -> v .x < 0 ;
49
+ };
50
+ }
51
+
52
+ boolean intersectsXY (Rock o ) {
53
+ double d = -v .y * o .v .x + o .v .y * v .x ;
54
+ if (d != 0 ) {
55
+ double a = v .y * p .x - v .x * p .y ;
56
+ double b = o .v .y * o .p .x - o .v .x * o .p .y ;
57
+ double x = (-o .v .x * a + v .x * b ) / d ;
58
+ double y = (-o .v .y * a + v .y * b ) / d ;
59
+ if (willReach (x , y ) && o .willReach (x , y )) {
60
+ return x >= min && x <= max && y >= min && y <= max ;
61
+ }
62
+ }
63
+ return false ;
64
+ }
65
+
66
+ public Loc x () {
67
+ return new Loc (p .x , v .x );
68
+ }
69
+
70
+ public Loc y () {
71
+ return new Loc (p .y , v .y );
72
+ }
73
+
74
+ public Loc z () {
75
+ return new Loc (p .z , v .z );
76
+ }
77
+
22
78
}
23
79
24
80
@ Override
25
81
public Object part1 () {
26
- var in = dayStream ().map (s -> readString (s , "%n, %n, %n @ %n, %n, %n" , Input .class )).toList ();
27
- return "" ;
82
+ var in = dayStream ().map (s -> readString (s , "%n, %n, %n @ %n, %n, %n" , Rock .class )).toList ();
83
+ return range (0 , in .size ())
84
+ .mapToLong (i -> range (i + 1 , in .size ())
85
+ .filter (j -> in .get (i ).intersectsXY (in .get (j )))
86
+ .count ())
87
+ .sum ();
28
88
}
29
89
30
90
@ Override
31
91
public Object part2 () {
32
- return "" ;
92
+ var in = dayStream ().map (s -> readString (s , "%n, %n, %n @ %n, %n, %n" , Rock .class )).toList ();
93
+ List <Function <Rock , Loc >> slicers = List .of (Rock ::x , Rock ::y , Rock ::z );
94
+ var collisionRecords = slicers .stream ().flatMap (slicer -> in .stream ().filter (
95
+ candidate -> in .stream ().filter (h -> !h .equals (candidate )).allMatch (h -> {
96
+ var differenceInPosition = slicer .apply (h ).x - slicer .apply (candidate ).x ;
97
+ var differenceInVelocity = slicer .apply (h ).y - slicer .apply (candidate ).y ;
98
+ return differenceInVelocity != 0 && differenceInPosition % differenceInVelocity == 0 && differenceInPosition / differenceInVelocity < 0 ;
99
+ }
100
+ )).map (candidate ->
101
+ in .stream ().filter (h -> !h .equals (candidate )).map (h -> {
102
+ var collisionTime = (slicer .apply (h ).x - slicer .apply (candidate ).x ) / (slicer .apply (candidate ).y - slicer .apply (h ).y );
103
+ return new Pair <>(collisionTime , h .positionAt (collisionTime ));
104
+ }).collect (toMap (Pair ::a , Pair ::b , (a , b ) -> a , TreeMap ::new )))
105
+ ).toList ();
106
+ var result = collisionRecords .get (0 ).entrySet ().stream ().limit (2 ).toList ();
107
+ var velocity = result .get (1 ).getValue ().p ().move (result .get (0 ).getValue ().p ().multiply (-1 )).divide (result .get (1 ).getKey () - result .get (0 ).getKey ());
108
+ var magic = result .get (0 ).getValue ().p ().move (velocity .multiply (-result .get (0 ).getKey ()));
109
+ return magic .x + magic .y + magic .z ;
33
110
}
34
111
}
0 commit comments