77// <https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12>.
88// See the Licence for the specific language governing permissions and limitations under the Licence.
99
10+ use std:: { collections:: HashMap , fmt:: Display } ;
11+
1012use itertools:: Itertools ;
13+ use num:: Integer ;
1114
12- use crate :: { AoCError , BigCoord2D , Coordinate } ;
15+ use crate :: { AoCError , BigCoord2D , CommonGrid , Coordinate , Coordinate2D , symbols } ;
1316
1417pub fn part_1 ( data : crate :: DataIn ) -> crate :: AoCResult < String > {
1518 let coords: Vec < BigCoord2D > = data. map ( |line| line. parse ( ) ) . try_collect ( ) ?;
@@ -33,12 +36,197 @@ pub fn part_1(data: crate::DataIn) -> crate::AoCResult<String> {
3336 Ok ( ret. to_string ( ) )
3437}
3538
39+ /// Adapted from http://web.archive.org/web/20080812141848/http://local.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/
40+ fn inside_polygon ( point : BigCoord2D , polygon : & [ BigCoord2D ] ) -> bool {
41+ polygon
42+ . iter ( )
43+ . tuple_windows ( )
44+ . filter ( |( poly_a, poly_b) | {
45+ let poly_min = poly_a. get_min ( poly_b) ;
46+ let poly_max = poly_a. get_max ( poly_b) ;
47+ if point. y <= poly_min. y {
48+ // why does this only check y coords? who knows.
49+ return false ;
50+ } else if point. x > poly_max. x || point. y > poly_max. y {
51+ return false ;
52+ } else if poly_a. y == poly_b. y {
53+ // ????
54+ return false ;
55+ }
56+ // mystery statement
57+ let xinters =
58+ ( point. y - poly_a. y ) * ( poly_b. x - poly_a. x ) / ( poly_b. y - poly_a. y ) + poly_a. x ;
59+ poly_a. x == poly_b. x || point. x <= xinters
60+ } )
61+ . count ( )
62+ . is_odd ( )
63+ }
64+
65+ fn cached_inside_polygon (
66+ point : BigCoord2D ,
67+ polygon : & [ BigCoord2D ] ,
68+ prechecked : & mut HashMap < BigCoord2D , bool > ,
69+ ) -> bool {
70+ if let Some ( result) = prechecked. get ( & point) {
71+ return * result;
72+ }
73+ let result = inside_polygon ( point, polygon) ;
74+ log:: trace!(
75+ "Magic function says {point} is {} poly" ,
76+ if result { "inside" } else { "outside" }
77+ ) ;
78+ prechecked. insert ( point, result) ;
79+ result
80+ }
81+
82+ fn rectangulate ( a : & BigCoord2D , b : & BigCoord2D ) -> impl Iterator < Item = BigCoord2D > {
83+ log:: trace!( "wtf wtf {a} {b}" ) ;
84+ // I'm moderately sure I've written this code before but I don't know where it is
85+ ( a. x ..=b. x )
86+ . cartesian_product ( a. y ..=b. y )
87+ . map ( BigCoord2D :: from_tuple)
88+ . inspect ( |c| log:: trace!( "wtf {c}" ) )
89+ }
90+
91+ pub fn part_2 ( data : crate :: DataIn ) -> crate :: AoCResult < String > {
92+ let coords = {
93+ let mut coords: Vec < BigCoord2D > = data. map ( |line| line. parse ( ) ) . try_collect ( ) ?;
94+ // Make it into a closed polygon
95+ coords. push ( coords[ 0 ] ) ;
96+ coords
97+ } ;
98+
99+ let mut prechecked: HashMap < BigCoord2D , bool > = coords
100+ . iter ( )
101+ . tuple_windows ( )
102+ . flat_map ( |( a, b) | {
103+ let ( a, b) = ( a. get_min ( b) , a. get_max ( b) ) ;
104+ log:: trace!( "ye {a} {b}" ) ;
105+ if a. y == b. y {
106+ let y = a. y ;
107+ ( a. x ..=b. x ) . map ( |x| BigCoord2D { x, y } ) . collect_vec ( )
108+ } else {
109+ let x = a. x ;
110+ ( a. y ..=b. y ) . map ( |y| BigCoord2D { x, y } ) . collect_vec ( )
111+ }
112+ } )
113+ . map ( |c| ( c, true ) )
114+ . collect ( ) ;
115+
116+ // stupid test grid
117+ log:: debug!( "prechecked:\n {}" , {
118+ use aoc_macros:: VoidState ;
119+
120+ use crate :: SparseGrid ;
121+
122+ #[ derive( Debug , VoidState ) ]
123+ enum GridState {
124+ #[ void]
125+ Void ,
126+ Red ,
127+ Green ,
128+ }
129+
130+ impl Display for GridState {
131+ fn fmt( & self , f: & mut std:: fmt:: Formatter <' _>) -> std:: fmt:: Result {
132+ match self {
133+ Self :: Void => symbols:: SHADE_LIGHT ,
134+ Self :: Red => symbols:: BLOCK ,
135+ Self :: Green => symbols:: SHADE_MID ,
136+ }
137+ . fmt( f)
138+ }
139+ }
140+
141+ let mut grid: SparseGrid <GridState , BigCoord2D > =
142+ prechecked. keys( ) . map( |a| ( * a, GridState :: Green ) ) . collect( ) ;
143+
144+ coords. iter( ) . for_each( |c| {
145+ grid. set( * c, GridState :: Red ) ;
146+ } ) ;
147+
148+ grid
149+ } ) ;
150+
151+ let ret = coords
152+ . iter ( )
153+ . array_combinations ( )
154+ . map ( |[ a, b] | {
155+ let min = a. get_min ( b) ;
156+ let max = a. get_max ( b) ;
157+ ( ( 1 + max. x - min. x ) * ( 1 + max. y - min. y ) , min, max)
158+ } )
159+ . sorted_unstable ( )
160+ . rev ( )
161+ . inspect ( |( dist, a, b) | {
162+ log:: debug!( "Square of area {dist} between {a} and {b}" ) ;
163+ } )
164+ . find ( |( _, a, b) | {
165+ rectangulate ( a, b) . all ( |point| cached_inside_polygon ( point, & coords, & mut prechecked) )
166+ } )
167+ . map ( |( dist, _, _) | dist)
168+ . ok_or ( AoCError :: new ( "No valid rectangles?" ) ) ?;
169+
170+ // stupid test grid v2
171+ log:: debug!( "postchecked:\n {}" , {
172+ use aoc_macros:: VoidState ;
173+
174+ use crate :: SparseGrid ;
175+
176+ #[ derive( Debug , VoidState ) ]
177+ enum GridState {
178+ #[ void]
179+ Void ,
180+ Red ,
181+ Green ,
182+ White ,
183+ }
184+
185+ impl Display for GridState {
186+ fn fmt( & self , f: & mut std:: fmt:: Formatter <' _>) -> std:: fmt:: Result {
187+ match self {
188+ Self :: Void => symbols:: VOID ,
189+ Self :: Red => symbols:: BLOCK ,
190+ Self :: Green => symbols:: SHADE_DARK ,
191+ Self :: White => symbols:: SHADE_LIGHT ,
192+ }
193+ . fmt( f)
194+ }
195+ }
196+
197+ let mut grid: SparseGrid <GridState , BigCoord2D > = prechecked
198+ . iter( )
199+ . map( |( coord, state) | {
200+ (
201+ * coord,
202+ if * state {
203+ GridState :: Green
204+ } else {
205+ GridState :: White
206+ } ,
207+ )
208+ } )
209+ . collect( ) ;
210+
211+ coords. iter( ) . for_each( |c| {
212+ grid. set( * c, GridState :: Red ) ;
213+ } ) ;
214+
215+ grid
216+ } ) ;
217+
218+ Ok ( ret. to_string ( ) )
219+ }
220+
36221inventory:: submit!( crate :: AoCDay {
37222 year: "2025" ,
38223 day: "9" ,
39224 part_1: crate :: AoCPart {
40225 main: part_1,
41226 example: part_1
42227 } ,
43- part_2: None
228+ part_2: Some ( crate :: AoCPart {
229+ main: part_2,
230+ example: part_2,
231+ } )
44232} ) ;
0 commit comments