11use std:: cmp:: { max, min} ;
2- use std:: collections:: HashSet ;
3- use std:: iter:: { once , successors} ;
2+ use std:: collections:: { BTreeSet , HashSet } ;
3+ use std:: iter:: successors;
44
55use aoclp:: positioning:: direction:: four_points:: Direction4 ;
66use aoclp:: positioning:: pt:: { rectangular_area, Pt } ;
77use aoclp:: solvers_impl:: input:: safe_get_input_as_many;
88use itertools:: Itertools ;
9- use aoclp:: positioning:: turtle :: Turtle ;
9+ use aoclp:: positioning:: direction :: Direction ;
1010
1111pub fn part_1 ( ) -> i64 {
1212 input ( )
@@ -20,74 +20,108 @@ pub fn part_1() -> i64 {
2020pub fn part_2 ( ) -> i64 {
2121 let red_tiles = input ( ) ;
2222
23- let red_zone = build_red_zone ( & red_tiles) ;
24- let rectangle_points = |a : Pt , b : Pt | {
25- let ( left, right, top, bottom) = ( min ( a. x , b. x ) , max ( a. x , b. x ) , min ( a. y , b. y ) , max ( a. y , b. y ) ) ;
26- ( left..=right) . flat_map ( move |x| ( top..=bottom) . map ( move |y| Pt :: new ( x, y) ) )
27- } ;
28- let safe_rectangle = |a, b| {
29- rectangle_points ( a, b) . all ( |p| !red_zone. contains ( & p) )
23+ let red_zone: BTreeSet < _ > = build_red_zone ( & red_tiles) . collect ( ) ;
24+ let safe_rectangle = |a : Pt , b : Pt | {
25+ let corners = vec ! [
26+ Pt :: new( min( a. x, b. x) , min( a. y, b. y) ) ,
27+ Pt :: new( max( a. x, b. x) , min( a. y, b. y) ) ,
28+ Pt :: new( max( a. x, b. x) , max( a. y, b. y) ) ,
29+ Pt :: new( max( a. x, b. x) , min( a. y, b. y) ) ,
30+ Pt :: new( min( a. x, b. x) , min( a. y, b. y) ) ,
31+ ] ;
32+ let edges: BTreeSet < _ > = corners
33+ . into_iter ( )
34+ . tuple_windows ( )
35+ . flat_map ( |( a, b) | {
36+ let displacement = Pt :: new ( ( b. x - a. x ) . signum ( ) , ( b. y - a. y ) . signum ( ) ) ;
37+ successors ( Some ( a) , move |& p| ( p != b) . then_some ( p + displacement) )
38+ } )
39+ . collect ( ) ;
40+ edges. is_disjoint ( & red_zone)
3041 } ;
3142
32- red_tiles
43+ let ( a , b , area ) = red_tiles
3344 . into_iter ( )
3445 . array_combinations ( )
3546 . map ( |[ a, b] | ( a, b, rectangular_area ( a, b) ) )
3647 . sorted_unstable_by ( |( _, _, area_a) , ( _, _, area_b) | area_b. cmp ( area_a) )
37- . filter ( |& ( a, b, _) | safe_rectangle ( a, b) )
38- . map ( |( _, _, area) | area)
39- . next ( )
40- . unwrap ( )
41- }
48+ . find ( |& ( a, b, _) | safe_rectangle ( a, b) )
49+ . unwrap ( ) ;
50+ println ! ( "Largest rectangle is ({a}, {b}) area: {area}" ) ;
4251
43- fn build_red_zone ( red_tiles : & [ Pt ] ) -> HashSet < Pt > {
44- let path_tiles: HashSet < _ > = red_tiles
45- . iter ( )
46- . copied ( )
47- . chain ( once ( red_tiles[ 0 ] ) )
48- . tuple_windows ( )
49- . flat_map ( |( a, b) | {
50- let displacement = Pt :: new ( ( b. x - a. x ) . signum ( ) , ( b. y - a. y ) . signum ( ) ) ;
51- successors ( Some ( a) , move |& p| ( p != b) . then_some ( p + displacement) )
52- . chain ( once ( b) )
53- } )
54- . collect ( ) ;
55- let path_tiles = & path_tiles;
52+ {
53+ let red_tiles = input ( ) ;
54+ let min_x = red_tiles. iter ( ) . map ( |a| a. x ) . min ( ) . unwrap ( ) - 2 ;
55+ let max_x = red_tiles. iter ( ) . map ( |a| a. x ) . max ( ) . unwrap ( ) - 2 ;
56+ let min_y = red_tiles. iter ( ) . map ( |a| a. y ) . min ( ) . unwrap ( ) + 2 ;
57+ let max_y = red_tiles. iter ( ) . map ( |a| a. y ) . max ( ) . unwrap ( ) + 2 ;
58+ let red_tiles: HashSet < _ > = red_tiles. iter ( ) . copied ( ) . collect ( ) ;
59+ let corners = vec ! [
60+ Pt :: new( min( a. x, b. x) , min( a. y, b. y) ) ,
61+ Pt :: new( max( a. x, b. x) , min( a. y, b. y) ) ,
62+ Pt :: new( max( a. x, b. x) , max( a. y, b. y) ) ,
63+ Pt :: new( max( a. x, b. x) , min( a. y, b. y) ) ,
64+ Pt :: new( min( a. x, b. x) , min( a. y, b. y) ) ,
65+ ] ;
66+ let edges: BTreeSet < _ > = corners
67+ . into_iter ( )
68+ . tuple_windows ( )
69+ . flat_map ( |( a, b) | {
70+ let displacement = Pt :: new ( ( b. x - a. x ) . signum ( ) , ( b. y - a. y ) . signum ( ) ) ;
71+ successors ( Some ( a) , move |& p| ( p != b) . then_some ( p + displacement) )
72+ } )
73+ . collect ( ) ;
5674
57- println ! ( "Path tiles count: {}" , path_tiles. len( ) ) ;
75+ for y in min_x..=max_y {
76+ for x in min_y..=max_x {
77+ let pt = Pt :: new ( x, y) ;
78+ if red_tiles. contains ( & pt) {
79+ print ! ( "#" ) ;
80+ } else if red_zone. contains ( & pt) {
81+ print ! ( "!" ) ;
82+ } else if edges. contains ( & pt) {
83+ print ! ( "O" ) ;
84+ } else {
85+ print ! ( "." ) ;
86+ }
87+ }
88+ println ! ( ) ;
89+ }
90+ println ! ( ) ;
91+ }
5892
93+ area
94+ }
95+
96+ fn build_red_zone ( red_tiles : & [ Pt ] ) -> impl Iterator < Item = Pt > + use < ' _ > {
5997 let starting_point = red_tiles
6098 . iter ( )
6199 . sorted_by ( |a, b| a. x . cmp ( & b. x ) . then ( a. y . cmp ( & b. y ) ) )
62100 . copied ( )
63101 . next ( )
64102 . unwrap ( ) ;
65103
66- println ! ( "Starting point: {starting_point}" ) ;
67-
68- let starting_turtle = Turtle :: new ( starting_point, Direction4 :: Right ) ;
69- let turtle_path = successors ( Some ( ( starting_turtle, 0usize ) ) , move |& ( t, i) | {
70- if t == starting_turtle && i != 0 {
71- return None ;
72- }
73- Some ( [ t, t. turn_left ( ) , t. turn_right ( ) ]
74- . iter ( )
75- . map ( |next| ( next. advance ( ) , i + 1 ) )
76- . find ( |( next, _) | path_tiles. contains ( & next. position ) )
77- . unwrap ( ) )
78- } ) ;
79-
80- let red_zone: HashSet < _ > = turtle_path
81- . map ( |( turtle, _) | turtle. turn_left ( ) . advance ( ) )
82- . filter ( |turtle| !path_tiles. contains ( & turtle. position ) )
83- . map ( |turtle| turtle. position )
84- . collect ( ) ;
85-
86- if !red_zone. is_empty ( ) {
87- println ! ( "Red zone tiles count: {}" , red_zone. len( ) ) ;
88- }
89-
90- red_zone
104+ red_tiles
105+ . iter ( )
106+ . copied ( )
107+ . cycle ( )
108+ . skip_while ( move |& p| p != starting_point)
109+ . enumerate ( )
110+ . take_while ( move |& ( i, p) | i == 0 || p != starting_point)
111+ . map ( |( _, p) | p)
112+ . tuple_windows ( )
113+ . flat_map ( |( a, b) | {
114+ let direction = match ( ( b. x - a. x ) . signum ( ) , ( b. y - a. y ) . signum ( ) ) {
115+ ( 1 , 0 ) => Direction4 :: Right ,
116+ ( 0 , 1 ) => Direction4 :: Down ,
117+ ( -1 , 0 ) => Direction4 :: Left ,
118+ ( 0 , -1 ) => Direction4 :: Up ,
119+ _ => unreachable ! ( ) ,
120+ } ;
121+ successors ( Some ( a) , move |& p| ( p != b) . then_some ( p + direction) )
122+ . skip ( 1 )
123+ . map ( move |p| p + ( direction. turn_left ( ) ) )
124+ } )
91125}
92126
93127fn input ( ) -> Vec < Pt > {
0 commit comments