1
+ package com .macasaet ;
2
+
3
+ import java .util .function .Predicate ;
4
+ import java .util .stream .Collectors ;
5
+ import java .util .stream .Stream ;
6
+ import java .util .stream .StreamSupport ;
7
+
8
+ import org .junit .jupiter .api .Test ;
9
+
10
+ /**
11
+ * --- Day 5: Hydrothermal Venture ---
12
+ */
13
+ public class Day05 {
14
+
15
+ /**
16
+ * A point on the ocean floor
17
+ */
18
+ public static record Point (int x , int y ) {
19
+ public static Point parse (final String string ) {
20
+ final var components = string .split ("," );
21
+ return new Point (Integer .parseInt (components [0 ]), Integer .parseInt (components [1 ]));
22
+ }
23
+
24
+ }
25
+
26
+ /**
27
+ * A portion of the ocean floor on which there are hydrothermal vents, which produce large, opaque clouds
28
+ */
29
+ public static record LineSegment (Point start , Point end ) {
30
+ public static LineSegment parse (final String string ) {
31
+ final var components = string .split (" -> " );
32
+ return new LineSegment (Point .parse (components [0 ]), Point .parse (components [1 ]));
33
+ }
34
+
35
+ /**
36
+ * Highlight the location of this line segment on the diagram. Each cell that this segment covers will have its
37
+ * value incremented. The higher the number, the more vents cover the cell.
38
+ *
39
+ * @param diagram A map of the ocean floor which will be updated by this call.
40
+ */
41
+ public void update (final int [][] diagram ) {
42
+ /*
43
+ "Because of the limits of the hydrothermal vent mapping system, the lines in your list will only ever be
44
+ horizontal, vertical, or a diagonal line at exactly 45 degrees."
45
+ */
46
+ final int horizontalStep = start ().x () == end ().x ()
47
+ ? 0
48
+ : start ().x () < end ().x ()
49
+ ? 1
50
+ : -1 ;
51
+ final int verticalStep = start ().y () == end ().y ()
52
+ ? 0
53
+ : start ().y () < end ().y ()
54
+ ? 1
55
+ : -1 ;
56
+ final Predicate <Integer > xTester = start ().x () == end ().x ()
57
+ ? x -> true
58
+ : start ().x () < end ().x ()
59
+ ? x -> x <= end ().x ()
60
+ : x -> x >= end ().x ();
61
+ final Predicate <Integer > yTester = start ().y () == end ().y ()
62
+ ? y -> true
63
+ : start ().y () < end ().y ()
64
+ ? y -> y <= end ().y ()
65
+ : y -> y >= end ().y ();
66
+
67
+ for (int i = start ().x (), j = start ().y ();
68
+ xTester .test (i ) && yTester .test (j );
69
+ i += horizontalStep , j += verticalStep ) {
70
+ diagram [i ][j ]++;
71
+ }
72
+ }
73
+
74
+ public int lowestX () {
75
+ return Math .min (start ().x (), end ().x ());
76
+ }
77
+
78
+ public int highestX () {
79
+ return Math .max (start ().x (), end ().x ());
80
+ }
81
+
82
+ public int lowestY () {
83
+ return Math .min (start ().y (), end ().y ());
84
+ }
85
+
86
+ public int highestY () {
87
+ return Math .max (start ().y (), end ().y ());
88
+ }
89
+
90
+ public String toString () {
91
+ return start () + " -> " + end ();
92
+ }
93
+ }
94
+
95
+ protected Stream <LineSegment > getInput () {
96
+ return StreamSupport
97
+ .stream (new LineSpliterator ("day-05.txt" ),
98
+ false )
99
+ .map (LineSegment ::parse );
100
+ }
101
+
102
+ protected record Extremes (int lowestX , int lowestY , int highestX , int highestY ) {
103
+ public Extremes combine (final LineSegment segment ) {
104
+ return new Extremes (Math .min (lowestX (), segment .lowestX ()),
105
+ Math .min (lowestY (), segment .lowestY ()),
106
+ Math .max (highestX (), segment .highestX ()),
107
+ Math .max (highestY (), segment .highestY ()));
108
+ }
109
+
110
+ public Extremes combine (final Extremes other ) {
111
+ return new Extremes (Math .min (lowestX (), other .lowestX ()),
112
+ Math .min (lowestY (), other .lowestY ()),
113
+ Math .max (highestX (), other .highestX ()),
114
+ Math .max (highestY (), other .highestY ()));
115
+ }
116
+
117
+ public int [][] createBlankDiagram () {
118
+ final int [][] result = new int [highestX () + 1 ][];
119
+ for (int i = result .length ; --i >= 0 ; result [i ] = new int [highestY () + 1 ]) ;
120
+ return result ;
121
+ }
122
+ }
123
+
124
+ @ Test
125
+ public final void part1 () {
126
+ final var segments = getInput ()
127
+ // "For now, only consider horizontal and vertical lines: lines where either x1 = x2 or y1 = y2."
128
+ .filter (segment -> segment .start ().x () == segment .end ().x () || segment .start ().y () == segment .end ().y ())
129
+ .collect (Collectors .toList ());
130
+
131
+ final var extremes = segments
132
+ .stream ()
133
+ .reduce (new Extremes (0 , 0 , 0 , 0 ),
134
+ Extremes ::combine ,
135
+ Extremes ::combine );
136
+ // there are no negative values
137
+ // Note, we could save a little bit of space and time by using a smaller map since none of the line segments
138
+ // need point 0,0. However, the savings are likely negligible.
139
+ final int [][] diagram = extremes .createBlankDiagram ();
140
+
141
+ for (final var segment : segments ) {
142
+ segment .update (diagram );
143
+ }
144
+ int sum = 0 ;
145
+ for (int i = diagram .length ; --i >= 0 ; ) {
146
+ final var row = diagram [i ];
147
+ for (int j = row .length ; --j >= 0 ; ) {
148
+ if (row [j ] >= 2 ) {
149
+ sum ++;
150
+ }
151
+ }
152
+ }
153
+ System .out .println ("Part 1: " + sum );
154
+ }
155
+
156
+ @ Test
157
+ public final void part2 () {
158
+ /*
159
+ "Unfortunately, considering only horizontal and vertical lines doesn't give you the full picture; you need to
160
+ also consider diagonal lines."
161
+ */
162
+ final var segments = getInput ()
163
+ .collect (Collectors .toList ());
164
+ final var extremes = segments
165
+ .stream ()
166
+ .reduce (new Extremes (0 , 0 , 0 , 0 ),
167
+ Extremes ::combine ,
168
+ Extremes ::combine );
169
+ // there are no negative values
170
+ // Note, we could save a little bit of space and time by using a smaller map since none of the line segments
171
+ // need point 0,0. However, the savings are likely negligible.
172
+ final int [][] diagram = extremes .createBlankDiagram ();
173
+ for (final var segment : segments ) {
174
+ segment .update (diagram );
175
+ }
176
+ int sum = 0 ;
177
+ for (int i = diagram .length ; --i >= 0 ; ) {
178
+ final var row = diagram [i ];
179
+ for (int j = row .length ; --j >= 0 ; ) {
180
+ if (row [j ] >= 2 ) {
181
+ sum ++;
182
+ }
183
+ }
184
+ }
185
+ System .out .println ("Part 2: " + sum );
186
+ }
187
+
188
+ }
0 commit comments