DEV Community

Discussion on: AoC Day 11: Chronal Charge

Collapse
 
rpalo profile image
Ryan Palo

Finished just in time for the next day!

The first part was not too bad, mostly just making sure my code lined up with the algorithm provided and then checking all the squares.

The second part was super duper slow. I think you could probably cache the calculations or use previous calculations of smaller size to speed up calculating the bigger sizes. However, I'm sleepy, and I noticed that the example problems both had maximum totals at relatively low numbers (12 and 16), so I just checked squares with sizes up to 30 in the hopes that I'd get lucky. I did, since my answer was in that range! So, high five for optimization-by-laziness!

I'm also really really proud of my sum-calculating code inside the nested loop. It feels very Rust-like, making use of iterators, take, skip, and flat_map. I did a little wiggle when I finally got it to compile. :)

/// Day 11: Chronal Charge
/// 
/// Figure out the power contained in power cells

/// A Grid of powercells with variable power levels
pub struct Grid {
    cells: [[i32; 300]; 300],
    serial: isize,
}

impl Grid {
    pub fn new(serial: isize) -> Self {
        let mut grid = Self { serial, cells: [[0; 300]; 300] };
        grid.generate_values();
        grid
    }

    /// Each cell has a location/serial number-based checksum that
    /// determines its power level.  Calculates all cells.
    fn generate_values(&mut self) {
        for (i, row) in self.cells.iter_mut().enumerate() {
            for (j, value) in row.iter_mut().enumerate() {
                *value = Grid::power_level(self.serial, (i + 1) as i32, (j + 1) as i32);
            }
        }
    }

    /// The checksum power level calculation on a cell basis.
    /// 
    /// Depends on the grid's serial number and on the location of the cell
    fn power_level(serial: isize, x: i32, y: i32) -> i32 {
        let mut result = (x as isize + 10) * (y as isize) + serial;
        result *= x as isize + 10;
        result = (result / 100) % 10;
        (result - 5) as i32
    }

    /// Finds the cell that is at the top left of the 3x3 with the highest
    /// total in the grid.
    pub fn best_cell(&self) -> (usize, usize) {
        let mut max_value = 0;
        let mut max_location = (0, 0);
        for i in 0..298 {
            for j in 0..298 {
                let value = self.cells.iter()
                    .skip(i).take(3)
                    .flat_map(|row| row.iter().skip(j).take(3) )
                    .sum();
                if value > max_value {
                    max_value = value;
                    max_location = (i + 1, j + 1);
                }
            }
        }
        max_location
    }

    /// Finds the cell that is at the top left of the N x N grid with
    /// the highest total power level, where N can be any size between
    /// 1 and 300.
    pub fn best_cell_sized(&self) -> (usize, usize, usize) {
        let mut max_value = 0;
        let mut max_location = (0, 0, 0);
        for size in 1..=30 {
            println!("Doing iteration: {}", size);
            for i in 0..=(300 - size) {
                for j in 0..=(300 - size) {
                    let value = self.cells.iter()
                        .skip(i).take(size)
                        .flat_map(|row| row.iter().skip(j).take(size) )
                        .sum();
                    if value > max_value {
                        max_value = value;
                        max_location = (i + 1, j + 1, size);
                    }
                }
            }
        }
        max_location
    }
}