11package org .ck .adventofcode .year2025 ;
22
3- import java .util .Scanner ;
3+ import java .util .* ;
44import org .ck .adventofcode .util .AOCSolution ;
55import org .ck .codechallengelib .annotation .Solution ;
66
@@ -20,15 +20,212 @@ public class Day09 extends AOCSolution {
2020
2121 @ Override
2222 protected void runPartOne (final Scanner in ) {
23- run (in );
23+ run (in , ( _ , _ , _ ) -> true );
2424 }
2525
2626 @ Override
2727 protected void runPartTwo (final Scanner in ) {
28- run (in );
28+ run (
29+ in ,
30+ (current , other , boundingLines ) -> {
31+ final long minX = Math .min (current .x , other .x );
32+ final long maxX = Math .max (current .x , other .x );
33+ final long minY = Math .min (current .y , other .y );
34+ final long maxY = Math .max (current .y , other .y );
35+
36+ final Line topLine = new Line (new Coordinate (minX , minY ), new Coordinate (maxX , minY ));
37+ final Line bottomLine = new Line (new Coordinate (minX , maxY ), new Coordinate (maxX , maxY ));
38+ final Line leftLine = new Line (new Coordinate (minX , minY ), new Coordinate (minX , maxY ));
39+ final Line rightLine = new Line (new Coordinate (maxX , minY ), new Coordinate (maxX , maxY ));
40+
41+ return boundingLines .stream ()
42+ .anyMatch (
43+ line ->
44+ topLine .intersectsTopLine (line )
45+ || bottomLine .intersectsBottomLine (line )
46+ || leftLine .intersectsLeftLine (line )
47+ || rightLine .intersectsRightLine (line ));
48+
49+ /*
50+ final Coordinate topCorner =
51+ current.y < other.y
52+ ? new Coordinate(other.x, current.y)
53+ : new Coordinate(current.x, other.y);
54+ final Coordinate bottomCorner =
55+ current.y >= other.y
56+ ? new Coordinate(other.x, current.y)
57+ : new Coordinate(current.x, other.y);
58+
59+ final boolean allPointsInside =
60+ isInsideBelow(topCorner, boundingLines) && isInsideAbove(bottomCorner, boundingLines);
61+
62+ if (!allPointsInside) {
63+ return false;
64+ }
65+
66+ return true;
67+
68+ /*
69+ for (long x = Math.min(current.x, other.x) + 1; x < Math.max(current.x, other.x); ++x) {
70+ if (!isInside(new Coordinate(x, current.y), boundingLines)
71+ || !isInside(new Coordinate(x, other.y), boundingLines)) {
72+ return false;
73+ }
74+ }
75+
76+ for (long y = Math.min(current.y, other.y) + 1; y < Math.max(current.y, other.y); ++y) {
77+ if (!isInside(new Coordinate(current.x, y), boundingLines)
78+ || !isInside(new Coordinate(other.x, y), boundingLines)) {
79+ return false;
80+ }
81+ }
82+
83+ return true;
84+
85+ /*final Set<Line> rectangle =
86+ Set.of(
87+ new Line(current, corner1),
88+ new Line(current, corner2),
89+ new Line(other, corner1),
90+ new Line(other, corner2));
91+
92+ for (final Line side : rectangle) {
93+ for (final Line boundingLine : boundingLines) {
94+ if (side.reallyIntersects(boundingLine)) {
95+ return false;
96+ }
97+ }
98+ }
99+
100+ return true;*/
101+ });
102+ }
103+
104+ private void run (final Scanner in , final TriPredicate validityChecker ) {
105+ final List <Coordinate > tiles = new ArrayList <>();
106+ long maxArea = 0 ;
107+
108+ while (in .hasNextLine ()) {
109+ final String [] line = in .nextLine ().split ("," );
110+ tiles .add (new Coordinate (Long .parseLong (line [0 ]), Long .parseLong (line [1 ])));
111+ }
112+
113+ final List <Line > lines = new ArrayList <>();
114+ for (int i = 0 ; i < tiles .size (); i ++) {
115+ lines .add (new Line (tiles .get (i ), tiles .get ((i + 1 ) % tiles .size ())));
116+ }
117+
118+ for (int i = 0 ; i < tiles .size (); ++i ) {
119+ final Coordinate current = tiles .get (i );
120+
121+ for (int j = i + 1 ; j < tiles .size (); ++j ) {
122+ final Coordinate other = tiles .get (j );
123+
124+ final long area = (1 + Math .abs (other .x - current .x )) * (1 + Math .abs (other .y - current .y ));
125+ if (area > maxArea && validityChecker .apply (current , other , lines )) {
126+ maxArea = area ;
127+ }
128+ }
129+ }
130+
131+ print (maxArea );
132+ }
133+
134+ private boolean isInsideBelow (final Coordinate point , final List <Line > boundingLines ) {
135+ final Line ray = new Line (point , new Coordinate (100000 , point .y ));
136+
137+ return boundingLines .stream ().filter (ray ::intersectsRayBelow ).count () % 2 == 1 ;
29138 }
30139
31- private void run (final Scanner in ) {
32- // not yet implemented
140+ private boolean isInsideAbove (final Coordinate point , final List <Line > boundingLines ) {
141+ final Line ray = new Line (point , new Coordinate (100000 , point .y ));
142+
143+ return boundingLines .stream ().filter (ray ::intersectsRayAbove ).count () % 2 == 1 ;
144+ }
145+
146+ private interface TriPredicate {
147+ boolean apply (Coordinate tile1 , Coordinate tile2 , List <Line > lines );
148+ }
149+
150+ private record Coordinate (long x , long y ) {}
151+
152+ private record Line (Coordinate start , Coordinate end ) {
153+ public boolean intersectsTopLine (final Line other ) {
154+ final boolean otherIsVertical = other .start .x == other .end .x ;
155+
156+ if (!otherIsVertical ) {
157+ return false ;
158+ }
159+
160+ return Math .min (start .x , end .x ) < other .start .x
161+ && other .start .x < Math .max (start .x , end .x )
162+ && Math .min (other .start .y , other .end .y ) <= start .y
163+ && start .y < Math .max (other .start .y , other .end .y );
164+ }
165+
166+ public boolean intersectsBottomLine (final Line other ) {
167+ final boolean otherIsVertical = other .start .x == other .end .x ;
168+
169+ if (!otherIsVertical ) {
170+ return false ;
171+ }
172+
173+ return Math .min (start .x , end .x ) < other .start .x
174+ && other .start .x < Math .max (start .x , end .x )
175+ && Math .min (other .start .y , other .end .y ) < start .y
176+ && start .y <= Math .max (other .start .y , other .end .y );
177+ }
178+
179+ public boolean intersectsLeftLine (final Line other ) {
180+ final boolean otherIsVertical = other .start .x == other .end .x ;
181+
182+ if (otherIsVertical ) {
183+ return false ;
184+ }
185+
186+ return Math .min (start .x , end .x ) <= other .start .x
187+ && other .start .x < Math .max (start .x , end .x )
188+ && Math .min (other .start .y , other .end .y ) < start .y
189+ && start .y < Math .max (other .start .y , other .end .y );
190+ }
191+
192+ public boolean intersectsRightLine (final Line other ) {
193+ final boolean otherIsVertical = other .start .x == other .end .x ;
194+
195+ if (otherIsVertical ) {
196+ return false ;
197+ }
198+
199+ return Math .min (start .x , end .x ) < other .start .x
200+ && other .start .x <= Math .max (start .x , end .x )
201+ && Math .min (other .start .y , other .end .y ) < start .y
202+ && start .y < Math .max (other .start .y , other .end .y );
203+ }
204+
205+ public boolean intersectsRayBelow (final Line other ) {
206+ final boolean otherIsVertical = other .start .x == other .end .x ;
207+
208+ if (!otherIsVertical ) {
209+ return false ;
210+ }
211+
212+ return Math .min (start .x , end .x ) < other .start .x
213+ && other .start .x <= Math .max (start .x , end .x )
214+ && Math .min (other .start .y , other .end .y ) <= start .y
215+ && start .y < Math .max (other .start .y , other .end .y );
216+ }
217+
218+ public boolean intersectsRayAbove (final Line other ) {
219+ final boolean otherIsVertical = other .start .x == other .end .x ;
220+
221+ if (!otherIsVertical ) {
222+ return false ;
223+ }
224+
225+ return Math .min (start .x , end .x ) < other .start .x
226+ && other .start .x <= Math .max (start .x , end .x )
227+ && Math .min (other .start .y , other .end .y ) < start .y
228+ && start .y <= Math .max (other .start .y , other .end .y );
229+ }
33230 }
34231}
0 commit comments