Solution for 2021 day 9 part 1

[?]
Dec 12, 2021, 10:24 PM
E5UDZGDTQH4K24S5DGGXSH3DVDOV745VWKNIEXE6JGSEUSDU36CAC

Dependencies

Change contents

  • file addition: day9.rs (----------)
    [4.16]
    fn main() {
    use std::io::BufRead;
    let mut grid: Grid<u8> = Grid::with_outside(u8::MAX);
    let filename = std::env::args().nth(1).expect("Expected filename");
    let file = std::io::BufReader::new(
    std::fs::File::open(<String as AsRef<std::path::Path>>::as_ref(
    &filename,
    ))
    .unwrap(),
    );
    for (y, line) in file.lines().enumerate() {
    for (x, c) in line.unwrap().chars().enumerate() {
    grid[(x, y)] = c.to_digit(10).unwrap_or(u8::MAX as u32) as u8;
    }
    }
    println!(
    "risk level: {}",
    grid.minima().map(|p| grid[p] as u16 + 1).sum::<u16>()
    );
    }
    #[derive(Debug)]
    struct Grid<T> {
    inner: Vec<T>,
    outside: T,
    width: usize,
    }
    impl<T> Grid<T> {
    fn with_outside(outside: T) -> Self {
    Self {
    inner: Vec::new(),
    outside,
    width: 0,
    }
    }
    fn height(&self) -> usize {
    self.inner.len() / self.width.max(1)
    }
    fn width(&self) -> usize {
    self.width
    }
    fn neighbours(&self, point: (usize, usize)) -> Neighbours {
    Neighbours::new(point, (self.width(), self.height()))
    }
    fn points(&self) -> GridPoints {
    GridPoints::new(self.width, self.height())
    }
    }
    impl<T: Ord> Grid<T> {
    fn minima(&self) -> impl Iterator<Item = (usize, usize)> + '_ {
    self.points().filter(move |p| {
    let c = &self[*p];
    let mut r = false;
    for n in self.neighbours(*p).map(|n| &self[n]) {
    match c.cmp(n) {
    std::cmp::Ordering::Less => {
    r = true;
    }
    std::cmp::Ordering::Equal => {}
    std::cmp::Ordering::Greater => {
    r = false;
    break;
    }
    }
    }
    r
    })
    }
    }
    impl<T> std::ops::Index<(usize, usize)> for Grid<T> {
    type Output = T;
    fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
    if x >= self.width {
    &self.outside
    } else {
    let i = y * self.width + x;
    self.inner.get(i).unwrap_or(&self.outside)
    }
    }
    }
    impl<T: Clone> std::ops::IndexMut<(usize, usize)> for Grid<T> {
    fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output {
    let new_width = self.width().max(x + 1);
    let new_height = self.height().max(y + 1);
    if new_width > self.width() || new_height > self.height() {
    self.inner = (0..new_width * new_height)
    .map(|i| self[(i % new_width, i / new_width)].clone())
    .collect();
    self.width = new_width;
    }
    self.inner.index_mut(y * self.width + x)
    }
    }
    struct GridPoints {
    width: usize,
    height: usize,
    x: usize,
    y: usize,
    }
    impl GridPoints {
    fn new(width: usize, height: usize) -> Self {
    Self {
    width,
    height,
    x: 0,
    y: 0,
    }
    }
    }
    impl Iterator for GridPoints {
    type Item = (usize, usize);
    fn next(&mut self) -> Option<Self::Item> {
    let x = self.x;
    let y = self.y;
    if y < self.height {
    let x_n = x + 1;
    if x_n >= self.width {
    self.x = 0;
    self.y = y + 1;
    } else {
    self.x = x_n;
    }
    Some((x, y))
    } else {
    None
    }
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
    let n = self.width * (self.height - self.y) - self.x;
    (n, Some(n))
    }
    }
    struct Neighbours {
    centre: (usize, usize),
    dimensions: (usize, usize),
    i: u8,
    }
    impl Neighbours {
    fn new(centre: (usize, usize), dimensions: (usize, usize)) -> Self {
    Self {
    centre,
    dimensions,
    i: 0,
    }
    }
    }
    impl Iterator for Neighbours {
    type Item = (usize, usize);
    fn next(&mut self) -> Option<Self::Item> {
    match self.i {
    0 => {
    self.i = 1;
    if self.centre.1 > 0 {
    Some((self.centre.0, self.centre.1 - 1))
    } else {
    self.next()
    }
    }
    1 => {
    self.i = 2;
    let x = self.centre.0 + 1;
    if x < self.dimensions.0 {
    Some((x, self.centre.1))
    } else {
    self.next()
    }
    }
    2 => {
    self.i = 3;
    let y = self.centre.1 + 1;
    if y < self.dimensions.1 {
    Some((self.centre.0, self.centre.1 + 1))
    } else {
    self.next()
    }
    }
    3 => {
    self.i = 4;
    if self.centre.0 > 0 {
    Some((self.centre.0 - 1, self.centre.1))
    } else {
    self.next()
    }
    }
    _ => None,
    }
    }
    fn size_hint(&self) -> (usize, Option<usize>) {
    (0, Some((4 - self.i).into()))
    }
    }
  • edit in 2021/Cargo.toml at line 33
    [2.1171]
    [[bin]]
    name = "day9"
    path = "day9.rs"