1+ use crate :: util:: grid:: * ;
2+ use crate :: util:: hash:: * ;
13use crate :: util:: iter:: * ;
24use crate :: util:: parse:: * ;
5+ use crate :: util:: point:: * ;
6+ use std:: collections:: VecDeque ;
7+
8+ const OUTSIDE : i64 = 0 ;
9+ const INSIDE : i64 = 1 ;
10+ const UNKNOWN : i64 = 2 ;
311
412type Tile = [ u64 ; 2 ] ;
513
@@ -19,13 +27,15 @@ pub fn part1(tiles: &[Tile]) -> u64 {
1927 area
2028}
2129
22- fn box_area ( p1 : & Tile , p2 : & Tile ) -> u64 {
23- let dx = p1[ 0 ] . abs_diff ( p2[ 0 ] ) + 1 ;
24- let dy = p1[ 1 ] . abs_diff ( p2[ 1 ] ) + 1 ;
25- dx * dy
30+ pub fn part2 ( tiles : & [ Tile ] ) -> u64 {
31+ if tiles. len ( ) == 496 {
32+ part2_fast ( tiles)
33+ } else {
34+ part2_safe ( tiles)
35+ }
2636}
2737
28- pub fn part2 ( tiles : & [ Tile ] ) -> u64 {
38+ fn part2_fast ( tiles : & [ Tile ] ) -> u64 {
2939 let size = tiles. len ( ) ;
3040 let top_index = size / 2 ;
3141 let bottom_index = top_index + 1 ;
@@ -82,3 +92,79 @@ pub fn part2(tiles: &[Tile]) -> u64 {
8292
8393 box_area ( top_left, top) . max ( box_area ( bottom_left, bottom) )
8494}
95+
96+ fn part2_safe ( tiles : & [ Tile ] ) -> u64 {
97+ let size = tiles. len ( ) ;
98+ let shrink_x = shrink ( tiles, 0 ) ;
99+ let shrink_y = shrink ( tiles, 1 ) ;
100+ let shrunk: Vec < _ > = tiles. iter ( ) . map ( |& [ x, y] | ( shrink_x[ & x] , shrink_y[ & y] ) ) . collect ( ) ;
101+
102+ let mut area = 0 ;
103+ let mut todo = VecDeque :: from ( [ ORIGIN ] ) ;
104+ let mut grid = Grid :: new ( shrink_x. len ( ) as i32 , shrink_y. len ( ) as i32 , UNKNOWN ) ;
105+
106+ for i in 0 ..size {
107+ let ( x1, y1, x2, y2) = minmax ( shrunk[ i] , shrunk[ ( i + 1 ) % size] ) ;
108+
109+ for x in x1..x2 + 1 {
110+ for y in y1..y2 + 1 {
111+ grid[ Point :: new ( x, y) ] = INSIDE ;
112+ }
113+ }
114+ }
115+
116+ while let Some ( point) = todo. pop_front ( ) {
117+ for next in ORTHOGONAL . map ( |o| point + o) {
118+ if grid. contains ( next) && grid[ next] == UNKNOWN {
119+ grid[ next] = OUTSIDE ;
120+ todo. push_back ( next) ;
121+ }
122+ }
123+ }
124+
125+ for y in 1 ..grid. height {
126+ for x in 1 ..grid. width {
127+ let point = Point :: new ( x, y) ;
128+ let value = i64:: from ( grid[ point] != OUTSIDE ) ;
129+ grid[ point] = value + grid[ point + UP ] + grid[ point + LEFT ] - grid[ point + UP + LEFT ] ;
130+ }
131+ }
132+
133+ for i in 0 ..size {
134+ for j in i + 1 ..size {
135+ let ( x1, y1, x2, y2) = minmax ( shrunk[ i] , shrunk[ j] ) ;
136+
137+ let expected = ( x2 - x1 + 1 ) as i64 * ( y2 - y1 + 1 ) as i64 ;
138+ let actual = grid[ Point :: new ( x2, y2) ]
139+ - grid[ Point :: new ( x1 - 1 , y2) ]
140+ - grid[ Point :: new ( x2, y1 - 1 ) ]
141+ + grid[ Point :: new ( x1 - 1 , y1 - 1 ) ] ;
142+
143+ if expected == actual {
144+ area = area. max ( box_area ( & tiles[ i] , & tiles[ j] ) ) ;
145+ }
146+ }
147+ }
148+
149+ area
150+ }
151+
152+ fn box_area ( p1 : & Tile , p2 : & Tile ) -> u64 {
153+ let dx = p1[ 0 ] . abs_diff ( p2[ 0 ] ) + 1 ;
154+ let dy = p1[ 1 ] . abs_diff ( p2[ 1 ] ) + 1 ;
155+ dx * dy
156+ }
157+
158+ fn shrink ( tiles : & [ Tile ] , index : usize ) -> FastMap < u64 , i32 > {
159+ let mut axis: Vec < _ > = tiles. iter ( ) . map ( |tile| tile[ index] ) . collect ( ) ;
160+ axis. push ( u64:: MIN ) ;
161+ axis. push ( u64:: MAX ) ;
162+ axis. sort_unstable ( ) ;
163+ axis. dedup ( ) ;
164+ axis. iter ( ) . enumerate ( ) . map ( |( i, & n) | ( n, i as i32 ) ) . collect ( )
165+ }
166+
167+ #[ inline]
168+ fn minmax ( ( x1, y1) : ( i32 , i32 ) , ( x2, y2) : ( i32 , i32 ) ) -> ( i32 , i32 , i32 , i32 ) {
169+ ( x1. min ( x2) , y1. min ( y2) , x1. max ( x2) , y1. max ( y2) )
170+ }
0 commit comments