@@ -4,122 +4,97 @@ use utils::prelude::*;
44/// Counting area, perimeter and sides of shapes in a grid.
55#[ derive( Clone , Debug ) ]
66pub struct Day12 {
7- grid : Vec < u8 > ,
8- offsets : [ isize ; 4 ] ,
7+ part1 : u32 ,
8+ part2 : u32 ,
99}
1010
1111impl Day12 {
1212 pub fn new ( input : & str , _: InputType ) -> Result < Self , InputError > {
1313 let ( _, cols, grid) =
14- grid:: from_str_padded ( input, 2 , 0 , |b| b. is_ascii_uppercase ( ) . then_some ( b) ) ?;
14+ grid:: from_str_padded ( input, 1 , 0 , |b| b. is_ascii_uppercase ( ) . then_some ( b) ) ?;
1515 let offsets = [ -( cols as isize ) , 1 , cols as isize , -1 ] ;
16- Ok ( Self { grid, offsets } )
17- }
1816
19- #[ must_use]
20- pub fn part1 ( & self ) -> u64 {
21- let mut visited = vec ! [ false ; self . grid. len( ) ] ;
22- let mut total = 0 ;
23- for i in 0 ..self . grid . len ( ) {
24- if self . grid [ i] == 0 || visited[ i] {
17+ let mut visited = vec ! [ false ; grid. len( ) ] ;
18+ let ( mut part1, mut part2) = ( 0 , 0 ) ;
19+ for i in 0 ..grid. len ( ) {
20+ if grid[ i] == 0 || visited[ i] {
2521 continue ;
2622 }
2723
28- let ( area, perimeter) = self . flood_fill ( i, & mut visited) ;
29- total += area * perimeter;
30- }
31- total
32- }
33-
34- fn flood_fill ( & self , i : usize , visited : & mut [ bool ] ) -> ( u64 , u64 ) {
35- let plant = self . grid [ i] ;
36- visited[ i] = true ;
37-
38- let ( mut area, mut perimeter) = ( 1 , 0 ) ;
39- for & offset in & self . offsets {
40- let next = i. wrapping_add_signed ( offset) ;
41- if self . grid [ next] == plant {
42- if !visited[ next] {
43- let ( a, p) = self . flood_fill ( next, visited) ;
44- area += a;
45- perimeter += p;
46- }
47- } else {
48- perimeter += 1 ;
49- }
24+ let ( area, perimeter, corners) = FloodFill :: fill_shape ( & grid, offsets, & mut visited, i) ;
25+ part1 += area * perimeter;
26+ part2 += area * corners;
5027 }
5128
52- ( area , perimeter )
29+ Ok ( Self { part1 , part2 } )
5330 }
5431
5532 #[ must_use]
56- pub fn part2 ( & self ) -> u64 {
57- let mut visited = vec ! [ false ; self . grid. len( ) ] ;
58- let mut edges = vec ! [ [ false ; 4 ] ; self . grid. len( ) ] ;
59- let mut total = 0 ;
60- for i in 0 ..self . grid . len ( ) {
61- if self . grid [ i] == 0 || visited[ i] {
62- continue ;
63- }
33+ pub fn part1 ( & self ) -> u32 {
34+ self . part1
35+ }
6436
65- let ( area, min_idx, max_idx) = self . edge_fill ( i, & mut visited, & mut edges) ;
37+ #[ must_use]
38+ pub fn part2 ( & self ) -> u32 {
39+ self . part2
40+ }
41+ }
6642
67- let mut sides = 0 ;
68- for dir in 0 ..4 {
69- for j in min_idx..=max_idx {
70- if edges[ j] [ dir] {
71- sides += 1 ;
72- self . edge_unset ( j, dir, & mut edges) ;
73- }
74- }
75- }
43+ struct FloodFill < ' a > {
44+ grid : & ' a [ u8 ] ,
45+ offsets : [ isize ; 4 ] ,
46+ visited : & ' a mut [ bool ] ,
47+ area : u32 ,
48+ perimeter : u32 ,
49+ corners : u32 ,
50+ }
7651
77- total += area * sides;
78- }
79- total
52+ impl < ' a > FloodFill < ' a > {
53+ fn fill_shape (
54+ grid : & ' a [ u8 ] ,
55+ offsets : [ isize ; 4 ] ,
56+ visited : & ' a mut [ bool ] ,
57+ i : usize ,
58+ ) -> ( u32 , u32 , u32 ) {
59+ let mut instance = Self {
60+ grid,
61+ offsets,
62+ visited,
63+ area : 0 ,
64+ perimeter : 0 ,
65+ corners : 0 ,
66+ } ;
67+ instance. visit ( i) ;
68+ ( instance. area , instance. perimeter , instance. corners )
8069 }
8170
82- fn edge_fill (
83- & self ,
84- i : usize ,
85- visited : & mut [ bool ] ,
86- edges : & mut [ [ bool ; 4 ] ] ,
87- ) -> ( u64 , usize , usize ) {
71+ fn visit ( & mut self , i : usize ) {
8872 let plant = self . grid [ i] ;
89- visited[ i] = true ;
90-
91- let ( mut area, mut min_idx, mut max_idx) = ( 1 , usize:: MAX , 0 ) ;
92- for dir in 0 ..4 {
93- let next = i. wrapping_add_signed ( self . offsets [ dir] ) ;
94- if self . grid [ next] == plant {
95- if !visited[ next] {
96- let r = self . edge_fill ( next, visited, edges) ;
97- area += r. 0 ;
98- min_idx = min_idx. min ( r. 1 ) ;
99- max_idx = max_idx. max ( r. 2 ) ;
73+ self . visited [ i] = true ;
74+ self . area += 1 ;
75+
76+ for d in 0 ..4 {
77+ let neighbour1 = i. wrapping_add_signed ( self . offsets [ d] ) ;
78+ if self . grid [ neighbour1] == plant {
79+ if !self . visited [ neighbour1] {
80+ self . visit ( neighbour1) ;
10081 }
10182 } else {
102- edges[ next] [ dir] = true ;
103- min_idx = min_idx. min ( next) ;
104- max_idx = max_idx. max ( next) ;
83+ self . perimeter += 1 ;
10584 }
106- }
107-
108- ( area, min_idx, max_idx)
109- }
11085
111- fn edge_unset ( & self , i : usize , dir : usize , edges : & mut [ [ bool ; 4 ] ] ) {
112- edges [ i ] [ dir ] = false ;
113- for offset in [ self . offsets [ ( dir + 1 ) % 4 ] , self . offsets [ ( dir + 3 ) % 4 ] ] {
114- let next = i . wrapping_add_signed ( offset ) ;
115- if edges [ next ] [ dir ] {
116- self . edge_unset ( next , dir , edges ) ;
86+ let neighbour2 = i . wrapping_add_signed ( self . offsets [ ( d + 1 ) % 4 ] ) ;
87+ let between = i . wrapping_add_signed ( self . offsets [ d ] + self . offsets [ ( d + 1 ) % 4 ] ) ;
88+ if ( ( self . grid [ neighbour1 ] == plant ) == ( self . grid [ neighbour2 ] == plant ) )
89+ && ( self . grid [ neighbour1 ] != plant || self . grid [ between ] != plant )
90+ {
91+ self . corners += 1 ;
11792 }
11893 }
11994 }
12095}
12196
122- examples ! ( Day12 -> ( u64 , u64 ) [
97+ examples ! ( Day12 -> ( u32 , u32 ) [
12398 { file: "day12_example0.txt" , part1: 140 , part2: 80 } ,
12499 { file: "day12_example1.txt" , part1: 772 } ,
125100 { file: "day12_example2.txt" , part1: 1930 , part2: 1206 } ,
0 commit comments