day12: optimization and cleanup
This commit is contained in:
		
							
								
								
									
										59
									
								
								src/day12.rs
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								src/day12.rs
									
									
									
									
									
								
							@@ -18,26 +18,28 @@ impl From<&[u8]> for Farm {
 | 
				
			|||||||
impl Farm {
 | 
					impl Farm {
 | 
				
			||||||
    fn compute_region(&self, pos: &Coord2d, visited: &mut Grid<bool>) -> (u64, u64) {
 | 
					    fn compute_region(&self, pos: &Coord2d, visited: &mut Grid<bool>) -> (u64, u64) {
 | 
				
			||||||
        let our_plant = self.map.get(pos).unwrap();
 | 
					        let our_plant = self.map.get(pos).unwrap();
 | 
				
			||||||
        let mut perimeter = 0;
 | 
					 | 
				
			||||||
        let mut area = 1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        visited.set(pos, true);
 | 
					        visited.set(pos, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for adj in [(-1i64, 0i64), (1, 0), (0, -1), (0, 1)].map(|ofs| pos + ofs) {
 | 
					        [(-1i64, 0i64), (1, 0), (0, -1), (0, 1)]
 | 
				
			||||||
            match self.map.get(&adj) {
 | 
					            .map(|ofs| pos + ofs)
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .fold((1, 0), |(area, perimeter), adj| {
 | 
				
			||||||
 | 
					                match self.map.get(adj) {
 | 
				
			||||||
                    Some(plant) if plant == our_plant => {
 | 
					                    Some(plant) if plant == our_plant => {
 | 
				
			||||||
                    if visited.get(&adj) == Some(false) {
 | 
					                        if visited.get(adj) == Some(false) {
 | 
				
			||||||
                            // add the perimeter of the growth from there if not visited yet
 | 
					                            // add the perimeter of the growth from there if not visited yet
 | 
				
			||||||
                        let (n_area, n_perimeter) = self.compute_region(&adj, visited);
 | 
					                            let (add_area, add_perimeter) = self.compute_region(&adj, visited);
 | 
				
			||||||
                        area += n_area;
 | 
					                            (area + add_area, perimeter + add_perimeter)
 | 
				
			||||||
                        perimeter += n_perimeter;
 | 
					                        } else {
 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                Some(_) | None => perimeter += 1,
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
                            (area, perimeter)
 | 
					                            (area, perimeter)
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    Some(_) | None => (area, perimeter + 1),
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn regions_cost(&self) -> u64 {
 | 
					    fn regions_cost(&self) -> u64 {
 | 
				
			||||||
        let mut visited = Grid::with_shape(self.map.width(), self.map.height(), false);
 | 
					        let mut visited = Grid::with_shape(self.map.width(), self.map.height(), false);
 | 
				
			||||||
        let mut cost = 0;
 | 
					        let mut cost = 0;
 | 
				
			||||||
@@ -61,9 +63,10 @@ impl Farm {
 | 
				
			|||||||
        cost
 | 
					        cost
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn count_corners(&self, pos: &Coord2d) -> u64 {
 | 
					    fn count_corners(&self, pos: &Coord2d) -> u64 {
 | 
				
			||||||
        //  A
 | 
					        // NOTE: Iterating twice is faster than combining conditions in one pass
 | 
				
			||||||
        // AAA has 4 inside corners (pos at centre). check that  AA A's exist and B doesn't for each rotation
 | 
					        // BAB
 | 
				
			||||||
        //  A                                                    AB
 | 
					        // AAA has 4 inside corners (pos at centre). check that for AA A's exist and B doesn't for each rotation
 | 
				
			||||||
 | 
					        // BAB                                                      AB
 | 
				
			||||||
        let our_plant = self.map.get(pos);
 | 
					        let our_plant = self.map.get(pos);
 | 
				
			||||||
        let inside_corners = [(1i64, 1i64), (-1, 1), (1, -1), (-1, -1)]
 | 
					        let inside_corners = [(1i64, 1i64), (-1, 1), (1, -1), (-1, -1)]
 | 
				
			||||||
            .iter()
 | 
					            .iter()
 | 
				
			||||||
@@ -73,6 +76,9 @@ impl Farm {
 | 
				
			|||||||
                    && self.map.get(&(pos + (0, inside_corner.1))) == our_plant
 | 
					                    && self.map.get(&(pos + (0, inside_corner.1))) == our_plant
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
            .count();
 | 
					            .count();
 | 
				
			||||||
 | 
					        // BBB
 | 
				
			||||||
 | 
					        // BAB has 4 outside corners (pos at centre). check that for AB the  B are both not equal to A for each rot
 | 
				
			||||||
 | 
					        // BBB                                                       BB     B
 | 
				
			||||||
        let outside_corners = [(1i64, 1i64), (-1, 1), (1, -1), (-1, -1)]
 | 
					        let outside_corners = [(1i64, 1i64), (-1, 1), (1, -1), (-1, -1)]
 | 
				
			||||||
            .iter()
 | 
					            .iter()
 | 
				
			||||||
            .filter(|outside_corner| {
 | 
					            .filter(|outside_corner| {
 | 
				
			||||||
@@ -84,25 +90,24 @@ impl Farm {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    fn region_corners(&self, pos: &Coord2d, visited: &mut Grid<bool>) -> (u64, u64) {
 | 
					    fn region_corners(&self, pos: &Coord2d, visited: &mut Grid<bool>) -> (u64, u64) {
 | 
				
			||||||
        let our_plant = self.map.get(pos).unwrap();
 | 
					        let our_plant = self.map.get(pos).unwrap();
 | 
				
			||||||
        let mut area = 1;
 | 
					 | 
				
			||||||
        let mut corners = self.count_corners(pos);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        visited.set(pos, true);
 | 
					        visited.set(pos, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for adj in [(-1i64, 0i64), (1, 0), (0, -1), (0, 1)].map(|ofs| pos + ofs) {
 | 
					        [(-1i64, 0i64), (1, 0), (0, -1), (0, 1)]
 | 
				
			||||||
            match self.map.get(&adj) {
 | 
					            .map(|ofs| pos + ofs)
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .fold((1, self.count_corners(pos)), |(area, corners), adj| {
 | 
				
			||||||
 | 
					                match self.map.get(adj) {
 | 
				
			||||||
                    Some(plant) if plant == our_plant => {
 | 
					                    Some(plant) if plant == our_plant => {
 | 
				
			||||||
                    if visited.get(&adj) == Some(false) {
 | 
					                        if visited.get(adj) == Some(false) {
 | 
				
			||||||
                            // add the perimeter of the growth from there if not visited yet
 | 
					                            // add the perimeter of the growth from there if not visited yet
 | 
				
			||||||
                            let (n_area, n_corners) = self.region_corners(&adj, visited);
 | 
					                            let (n_area, n_corners) = self.region_corners(&adj, visited);
 | 
				
			||||||
                        area += n_area;
 | 
					                            (area+n_area, corners+n_corners)
 | 
				
			||||||
                        corners += n_corners;
 | 
					                        } else { (area, corners) }
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    Some(_) | None => { (area, corners) }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                Some(_) | None => {}
 | 
					            })
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        (area, corners)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn regions_discount_cost(&self) -> u64 {
 | 
					    fn regions_discount_cost(&self) -> u64 {
 | 
				
			||||||
        let mut visited = Grid::with_shape(self.map.width(), self.map.height(), false);
 | 
					        let mut visited = Grid::with_shape(self.map.width(), self.map.height(), false);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user