1- use std:: cmp:: { max, min} ;
2- use std:: collections:: BTreeSet ;
3- use std:: iter:: successors;
1+ use std:: fmt;
2+ use std:: iter:: once;
43
54use aoclp:: positioning:: direction:: four_points:: Direction4 ;
65use aoclp:: positioning:: direction:: { Direction , MovementDirection } ;
7- use aoclp:: positioning:: pt:: { rectangular_area, Pt } ;
6+ use aoclp:: positioning:: pt:: { min_max , rectangle_corners , rectangular_area, Pt } ;
87use aoclp:: solvers_impl:: input:: safe_get_input_as_many;
98use itertools:: Itertools ;
10- use rayon:: iter:: { IntoParallelIterator , ParallelIterator } ;
119use strum:: IntoEnumIterator ;
1210
1311pub fn part_1 ( ) -> i64 {
@@ -21,40 +19,108 @@ pub fn part_1() -> i64 {
2119
2220pub fn part_2 ( ) -> i64 {
2321 let red_tiles = input ( ) ;
24-
25- let red_zone: BTreeSet < _ > = build_red_zone ( & red_tiles) . collect ( ) ;
26- let safe_rectangle = |a : Pt , b : Pt | {
27- let corners = vec ! [
28- Pt :: new( min( a. x, b. x) , min( a. y, b. y) ) ,
29- Pt :: new( max( a. x, b. x) , min( a. y, b. y) ) ,
30- Pt :: new( max( a. x, b. x) , max( a. y, b. y) ) ,
31- Pt :: new( min( a. x, b. x) , max( a. y, b. y) ) ,
32- Pt :: new( min( a. x, b. x) , min( a. y, b. y) ) ,
33- ] ;
34- let edges: BTreeSet < _ > = corners
35- . into_iter ( )
36- . tuple_windows ( )
37- . flat_map ( |( a, b) | {
38- let displacement = Pt :: new ( ( b. x - a. x ) . signum ( ) , ( b. y - a. y ) . signum ( ) ) ;
39- successors ( Some ( a) , move |& p| ( p != b) . then_some ( p + displacement) )
40- } )
41- . collect ( ) ;
42- edges. is_disjoint ( & red_zone)
43- } ;
22+ let walls = walls ( & red_tiles) . collect_vec ( ) ;
4423
4524 red_tiles
4625 . into_iter ( )
4726 . array_combinations ( )
48- . map ( |[ a, b] | ( a, b, rectangular_area ( a, b) ) )
49- . sorted_unstable_by ( |( _, _, area_a) , ( _, _, area_b) | area_b. cmp ( area_a) )
50- . collect_vec ( )
51- . into_par_iter ( )
52- . find_first ( |( a, b, _) | safe_rectangle ( * a, * b) )
53- . map ( |( _, _, area) | area)
27+ . filter ( |[ a, b] | {
28+ let corners = rectangle_corners ( * a, * b) ;
29+ corners
30+ . into_iter ( )
31+ . chain ( once ( corners[ 0 ] ) )
32+ . tuple_windows ( )
33+ . map ( |( a, b) | GridLine :: from_endpoints ( a, b) )
34+ . all ( |line| !walls. iter ( ) . any ( |w| w. intersects ( line) ) )
35+ } )
36+ . map ( |[ a, b] | rectangular_area ( a, b) )
37+ . max ( )
5438 . unwrap ( )
5539}
5640
57- fn build_red_zone ( red_tiles : & [ Pt ] ) -> impl Iterator < Item = Pt > + use < ' _ > {
41+ #[ derive( Debug , Copy , Clone , PartialEq , Eq ) ]
42+ enum GridLine {
43+ Horizontal {
44+ y : i64 ,
45+ left_x : i64 ,
46+ right_x : i64 ,
47+ } ,
48+ Vertical {
49+ x : i64 ,
50+ top_y : i64 ,
51+ bottom_y : i64 ,
52+ } ,
53+ Point ( Pt ) ,
54+ }
55+
56+ impl GridLine {
57+ fn from_endpoints ( a : Pt , b : Pt ) -> Self {
58+ let ( a, b) = min_max ( a, b) ;
59+ match ( a. x == b. x , a. y == b. y ) {
60+ ( true , true ) => Self :: Point ( a) ,
61+ ( true , false ) => Self :: Vertical { x : a. x , top_y : a. y , bottom_y : b. y } ,
62+ ( false , true ) => Self :: Horizontal { y : a. y , left_x : a. x , right_x : b. x } ,
63+ ( false , false ) => panic ! ( "{a} and {b} do not form a line snapped to the grid" ) ,
64+ }
65+ }
66+
67+ fn extend ( self , direction : Direction4 , len : i64 ) -> Self {
68+ match ( self , direction) {
69+ ( Self :: Horizontal { y, left_x, right_x } , Direction4 :: Left ) => {
70+ Self :: Horizontal { y, left_x : left_x - len, right_x }
71+ } ,
72+ ( Self :: Horizontal { y, left_x, right_x } , Direction4 :: Right ) => {
73+ Self :: Horizontal { y, left_x, right_x : right_x + len}
74+ } ,
75+ ( Self :: Vertical { x, top_y, bottom_y } , Direction4 :: Up ) => {
76+ Self :: Vertical { x, top_y : top_y - len, bottom_y }
77+ } ,
78+ ( Self :: Vertical { x, top_y, bottom_y } , Direction4 :: Down ) => {
79+ Self :: Vertical { x, top_y, bottom_y : bottom_y + len }
80+ } ,
81+ ( Self :: Point ( p) , direction) => {
82+ Self :: from_endpoints ( p, p + ( direction. displacement ( ) * len) )
83+ } ,
84+ ( line, direction) => {
85+ panic ! ( "line {line} cannot be extended {direction}" ) ;
86+ } ,
87+ }
88+ }
89+
90+ fn intersects ( self , rhs : Self ) -> bool {
91+ match ( self , rhs) {
92+ ( Self :: Horizontal { y, left_x, right_x } , Self :: Vertical { x, top_y, bottom_y } ) |
93+ ( Self :: Vertical { x, top_y, bottom_y } , Self :: Horizontal { y, left_x, right_x } ) => {
94+ ( top_y..=bottom_y) . contains ( & y) && ( left_x..=right_x) . contains ( & x)
95+ } ,
96+ ( Self :: Horizontal { y, left_x, right_x } , Self :: Point ( p) ) |
97+ ( Self :: Point ( p) , Self :: Horizontal { y, left_x, right_x } ) => {
98+ p. y == y && ( left_x..=right_x) . contains ( & p. x )
99+ } ,
100+ ( Self :: Vertical { x, top_y, bottom_y } , Self :: Point ( p) ) |
101+ ( Self :: Point ( p) , Self :: Vertical { x, top_y, bottom_y } ) => {
102+ p. x == x && ( top_y..=bottom_y) . contains ( & p. y )
103+ } ,
104+ _ => false ,
105+ }
106+ }
107+ }
108+
109+ impl fmt:: Display for GridLine {
110+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
111+ match * self {
112+ Self :: Horizontal { y, left_x, right_x } => {
113+ write ! ( f, "{} - {}" , Pt :: new( left_x, y) , Pt :: new( right_x, y) )
114+ } ,
115+ Self :: Vertical { x, top_y, bottom_y } => {
116+ write ! ( f, "{} - {}" , Pt :: new( x, top_y) , Pt :: new( x, bottom_y) )
117+ } ,
118+ Self :: Point ( p) => write ! ( f, "{p} - {p}" ) ,
119+ }
120+ }
121+ }
122+
123+ fn walls ( red_tiles : & [ Pt ] ) -> impl Iterator < Item = GridLine > + use < ' _ > {
58124 let starting_point = red_tiles
59125 . iter ( )
60126 . sorted_by ( |a, b| a. x . cmp ( & b. x ) . then ( a. y . cmp ( & b. y ) ) )
@@ -76,27 +142,18 @@ fn build_red_zone(red_tiles: &[Pt]) -> impl Iterator<Item = Pt> + use<'_> {
76142 . skip_while ( move |& p| p != starting_point)
77143 . take ( red_tiles. len ( ) + 2 )
78144 . tuple_windows ( )
79- . flat_map ( move |( a, b, c) | {
145+ . map ( move |( a, b, c) | {
80146 let direction = get_direction ( a, b) ;
81- let turning_left = get_direction ( b, c) == direction. turn_left ( ) ;
82-
83- let tail = if turning_left {
84- vec ! [ ]
85- } else {
86- vec ! [
87- b + direction. turn_left( ) ,
88- b + direction + direction. turn_left( ) ,
89- b + direction,
90- ]
91- } ;
147+ let turning_right = get_direction ( b, c) == direction. turn_right ( ) ;
92148
93- successors ( Some ( a) , move |& p| {
94- let next = p + direction;
95- ( next != b) . then_some ( next)
96- } )
97- . skip ( 1 )
98- . map ( move |p| p + ( direction. turn_left ( ) ) )
99- . chain ( tail)
149+ let mut line = GridLine :: from_endpoints (
150+ a + direction + direction. turn_left ( ) ,
151+ b + direction. turn_around ( ) + direction. turn_left ( ) ,
152+ ) ;
153+ if turning_right {
154+ line = line. extend ( direction, 2 ) ;
155+ }
156+ line
100157 } )
101158}
102159
0 commit comments