11use std:: cmp:: { max, min} ;
2- use std:: collections:: { HashSet , VecDeque } ;
2+ use std:: collections:: HashMap ;
33use std:: iter:: { once, successors} ;
4-
54use aoclp:: positioning:: pt:: { rectangular_area, Pt } ;
65use aoclp:: solvers_impl:: input:: safe_get_input_as_many;
76use itertools:: Itertools ;
8- use aoclp:: num :: Zero ;
7+ use aoclp:: positioning :: direction :: four_points :: Direction4 ;
98
109pub fn part_1 ( ) -> i64 {
1110 input ( )
@@ -18,56 +17,84 @@ pub fn part_1() -> i64 {
1817
1918pub fn part_2 ( ) -> i64 {
2019 let red_tiles = input ( ) ;
20+ let path = build_path ( & red_tiles) ;
2121
22- let path: HashSet < _ > = red_tiles
23- . iter ( )
24- . copied ( )
25- . chain ( once ( red_tiles[ 0 ] ) )
26- . enumerate ( )
27- . tuple_windows ( )
28- . flat_map ( |( ( ia, a) , ( ib, b) ) | {
29- let displacement = Pt :: new ( ( b. x - a. x ) . signum ( ) , ( b. y - a. y ) . signum ( ) ) ;
30- if displacement. x != 0 && displacement. y != 0 {
31- panic ! ( "Pair {} (#{ia}), {} (#{ib}) have wrong displacement" , a. to_string( ) , b. to_string( ) )
32- }
33- successors ( Some ( a) , move |& p| ( p != b) . then_some ( p + displacement) )
34- . chain ( once ( b) )
35- } )
36- . collect ( ) ;
37-
38- let floor_width = red_tiles. iter ( ) . map ( |p| p. x ) . max ( ) . unwrap ( ) + 2 ;
39- let floor_height = red_tiles. iter ( ) . map ( |p| p. y ) . max ( ) . unwrap ( ) + 2 ;
40-
41- let mut lava = HashSet :: new ( ) ;
42- let mut q = VecDeque :: new ( ) ;
43- q. push_back ( Pt :: zero ( ) ) ;
44- while let Some ( p) = q. pop_front ( ) {
45- if !p. within ( 0 ..floor_width, 0 ..floor_height) || path. contains ( & p) {
46- continue ;
47- }
48- if lava. insert ( p) {
49- q. extend ( p. four_neighbours ( ) ) ;
22+ let safe_line = red_tiles. iter ( ) . map ( |p| p. y ) . min ( ) . unwrap ( ) - 1 ;
23+ let mut pt_safety = HashMap :: new ( ) ;
24+ let mut safe_pt = |p : Pt | {
25+ if let Some ( & safe) = pt_safety. get ( & p) {
26+ return safe;
5027 }
51- }
5228
53- let safe_rectangle = |a : Pt , b : Pt | -> bool {
54- ( min ( a. y , b. y ) ..=max ( a. y , b. y ) )
55- . into_iter ( )
56- . flat_map ( |y| {
57- ( min ( a. x , b. x ) ..=max ( a. x , b. x ) ) . into_iter ( ) . map ( move |x| Pt :: new ( x, y) )
58- } )
59- . all ( |p| !lava. contains ( & p) )
29+ let safe = successors ( Some ( p) , |& p| ( p. y > safe_line) . then_some ( p + Direction4 :: Up ) )
30+ . filter ( |p| path. get ( p) . is_some_and ( |& step| step == PathStep :: LeftRight ) )
31+ . count ( ) % 2 != 0 ;
32+ pt_safety. insert ( p, safe) ;
33+ safe
34+ } ;
35+ let mut safe_line = |a : Pt , b : Pt | -> bool {
36+ let displacement = Pt :: new ( ( b. x - a. x ) . signum ( ) , ( b. y - a. y ) . signum ( ) ) ;
37+ successors ( Some ( a) , |& p| ( p != b) . then_some ( p + displacement) ) . chain ( Some ( b) )
38+ . all ( |p| safe_pt ( p) )
39+ } ;
40+ let mut safe_rectangle = |a : Pt , b : Pt | {
41+ let corners = [
42+ Pt :: new ( min ( a. x , b. x ) , min ( a. y , b. y ) ) ,
43+ Pt :: new ( min ( a. x , b. x ) , max ( a. y , b. y ) ) ,
44+ Pt :: new ( max ( a. x , b. x ) , max ( a. y , b. y ) ) ,
45+ Pt :: new ( max ( a. x , b. x ) , min ( a. y , b. y ) ) ,
46+ Pt :: new ( min ( a. x , b. x ) , min ( a. y , b. y ) ) ,
47+ ] ;
48+ corners
49+ . iter ( )
50+ . tuple_windows ( )
51+ . all ( |( & a, & b) | safe_line ( a, b) )
6052 } ;
6153
6254 red_tiles
6355 . into_iter ( )
6456 . array_combinations ( )
65- . filter ( |& [ a, b] | safe_rectangle ( a, b) )
66- . map ( |[ a, b] | rectangular_area ( a, b) )
67- . max ( )
57+ . map ( |[ a, b] | ( a, b, rectangular_area ( a, b) ) )
58+ . sorted_unstable_by ( |( _, _, area_a) , ( _, _, area_b) | area_b. cmp ( area_a) )
59+ . filter ( |& ( a, b, _) | safe_rectangle ( a, b) )
60+ . map ( |( _, _, area) | area)
61+ . next ( )
6862 . unwrap ( )
6963}
7064
65+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
66+ enum PathStep {
67+ Corner ,
68+ LeftRight ,
69+ TopDown ,
70+ }
71+
72+ impl PathStep {
73+ fn for_pair ( a : Pt , b : Pt ) -> Self {
74+ if ( a. x - b. x ) . abs ( ) . signum ( ) != 0 {
75+ Self :: LeftRight
76+ } else {
77+ Self :: TopDown
78+ }
79+ }
80+ }
81+
82+ fn build_path ( red_tiles : & [ Pt ] ) -> HashMap < Pt , PathStep > {
83+ red_tiles
84+ . iter ( )
85+ . copied ( )
86+ . chain ( once ( red_tiles[ 0 ] ) )
87+ . tuple_windows ( )
88+ . flat_map ( |( a, b) | {
89+ let step = PathStep :: for_pair ( a, b) ;
90+ let displacement = Pt :: new ( ( b. x - a. x ) . signum ( ) , ( b. y - a. y ) . signum ( ) ) ;
91+ successors ( Some ( ( a, PathStep :: Corner ) ) , move |& ( p, _) | {
92+ ( p != b) . then_some ( ( p + displacement, step) )
93+ } ) . chain ( once ( ( b, PathStep :: Corner ) ) )
94+ } )
95+ . collect ( )
96+ }
97+
7198fn input ( ) -> Vec < Pt > {
7299 safe_get_input_as_many ( 2025 , 9 )
73100}
0 commit comments