From 333e414d81257db3b39597a62210f716cc795d3e Mon Sep 17 00:00:00 2001 From: "Dr. Matthias Ratajczak" Date: Fri, 19 Aug 2022 14:39:05 +0200 Subject: [PATCH] finish 11 --- src/euler11/src/coordinate.rs | 39 +++++++ src/euler11/src/direction.rs | 19 ++++ src/euler11/src/grid.rs | 37 +++++++ src/euler11/src/main.rs | 191 +--------------------------------- src/euler11/src/neighbours.rs | 107 +++++++++++++++++++ 5 files changed, 207 insertions(+), 186 deletions(-) create mode 100644 src/euler11/src/coordinate.rs create mode 100644 src/euler11/src/direction.rs create mode 100644 src/euler11/src/grid.rs create mode 100644 src/euler11/src/neighbours.rs diff --git a/src/euler11/src/coordinate.rs b/src/euler11/src/coordinate.rs new file mode 100644 index 0000000..f5f9bc3 --- /dev/null +++ b/src/euler11/src/coordinate.rs @@ -0,0 +1,39 @@ +use std::fmt::Debug; + +#[derive(PartialEq)] +pub struct Coordinate { + pub x: usize, + pub y: usize, +} + +impl Coordinate { + pub fn new(x: usize, y: usize) -> Self { + Self { x, y } + } + + pub fn from_coordinate_pairs(x_idxs: [usize; 4], y_idxs: [usize; 4]) -> [Self; 4] { + let result: Vec<_> = x_idxs + .iter() + .zip(y_idxs) + .map(|(x, y)| Self::new(*x, y)) + .collect(); + result.try_into().unwrap() + } +} + +impl Debug for Coordinate { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let inner = &format!("{},{}", self.x, self.y); + f.write_str(inner) + } +} + +pub trait Show { + fn show(&self) -> String; +} + +impl Show for [Coordinate; 4] { + fn show(&self) -> String { + self.iter().map(|c| format!("{},{} --", c.x, c.y)).collect() + } +} diff --git a/src/euler11/src/direction.rs b/src/euler11/src/direction.rs new file mode 100644 index 0000000..ee902f8 --- /dev/null +++ b/src/euler11/src/direction.rs @@ -0,0 +1,19 @@ +#[derive(Debug)] +pub enum Direction { + Down, + Right, + DiagonalUp, + DiagonalDown, +} + +impl Iterator for Direction { + type Item = (Self, bool); + fn next(&mut self) -> Option { + match self { + Direction::Down => Some((Direction::Right, false)), + Direction::Right => Some((Direction::DiagonalUp, false)), + Direction::DiagonalUp => Some((Direction::DiagonalDown, false)), + Direction::DiagonalDown => Some((Direction::Down, true)), + } + } +} diff --git a/src/euler11/src/grid.rs b/src/euler11/src/grid.rs new file mode 100644 index 0000000..59a1dd3 --- /dev/null +++ b/src/euler11/src/grid.rs @@ -0,0 +1,37 @@ +use crate::neighbours::Neighbours; + +type Data = u32; + +pub struct Grid { + grid: Vec>, + neighbours: Neighbours, +} + +impl Grid { + pub fn from_file(filename: &str) -> Self { + let grid: Vec> = std::fs::read_to_string(filename) + .unwrap() + .split_terminator('\n') + .map(|line| { + line.split_whitespace() + .map(|cell| cell.parse::().unwrap() as Data) + .collect() + }) + .collect(); + let ny = grid.len(); + let nx = grid[0].len(); + let neighbours = Neighbours::new(nx, ny); + Grid { grid, neighbours } + } + + pub fn run(&mut self) { + let mut largest = 0; + while let Some(coordinates) = self.neighbours.next() { + let value = coordinates.iter().map(|c| self.grid[c.y][c.x]).product(); + if value > largest { + largest = value; + } + } + println!("{largest}"); + } +} diff --git a/src/euler11/src/main.rs b/src/euler11/src/main.rs index 39de157..0698182 100644 --- a/src/euler11/src/main.rs +++ b/src/euler11/src/main.rs @@ -1,190 +1,9 @@ -use std::{fmt::Debug, fs}; +mod coordinate; +mod direction; +mod grid; +mod neighbours; -const LENGTH: usize = 4; - -type Data = u32; -type Neighbours = Vec; - -struct Coordinate { - x: usize, - y: usize, -} - -impl Coordinate { - fn new(x: usize, y: usize) -> Self { - Self { x, y } - } -} - -impl Debug for Coordinate { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let inner = &format!("{},{}", self.x, self.y); - f.write_str(inner) - } -} - -struct Grid { - grid: Vec>, - nx: usize, - ny: usize, - curr_x: usize, - curr_y: usize, - curr_direction: Direction, - done: bool, -} - -impl Grid { - fn from_file(filename: &str) -> Self { - let grid: Vec> = fs::read_to_string(filename) - .unwrap() - .split_terminator('\n') - .map(|line| { - line.split_whitespace() - .map(|cell| cell.parse::().unwrap() as Data) - .collect() - }) - .collect(); - let ny = grid.len(); - let nx = grid[0].len(); - Grid { - grid, - nx, - ny, - curr_x: 0, - curr_y: 0, - curr_direction: Direction::None, - done: false, - } - } - - fn run(&mut self) { - let mut largest = 0; - loop { - if let Some(coordinates) = self.next() { - let value = coordinates.iter().map(|c| self.grid[c.y][c.x]).product(); - if value > largest { - largest = value; - } - } - if self.done { - break; - } - } - println!("{largest}"); - } - - fn advance_index(&mut self) { - if self.curr_x == self.nx - 1 { - self.curr_x = 0; - self.curr_y += 1; - if self.curr_y == self.ny { - self.done = true; - } - } else { - self.curr_x += 1; - } - } - - fn get_neighbours(&self) -> Option { - match self.curr_direction { - Direction::Down => self.get_neighbours_down(), - Direction::Right => self.get_neighbours_right(), - Direction::DiagonalUp => self.get_neighbours_diag_up(), - Direction::DiagonalDown => self.get_neighbours_diag_down(), - Direction::None => unreachable!(), - } - } - - fn get_neighbours_down(&self) -> Option { - let max_y = self.curr_y + LENGTH; - if max_y > self.ny { - None - } else { - Some( - (self.curr_y..max_y) - .map(|y| Coordinate::new(self.curr_x, y)) - .collect(), - ) - } - } - - fn get_neighbours_right(&self) -> Option { - let max_x = self.curr_x + LENGTH; - if max_x > self.nx { - None - } else { - Some( - (self.curr_x..max_x) - .map(|x| Coordinate::new(x, self.curr_y)) - .collect(), - ) - } - } - - fn get_neighbours_diag_up(&self) -> Option { - let max_x = self.curr_x + LENGTH; - let min_y = self.curr_y.wrapping_sub(LENGTH); - if max_x > self.nx || min_y > self.ny { - None - } else { - Some( - (self.curr_x..max_x) - .zip(self.curr_y..min_y) - .map(|(x, y)| Coordinate::new(x, y)) - .collect(), - ) - } - } - - fn get_neighbours_diag_down(&self) -> Option { - let max_x = self.curr_x + LENGTH; - let max_y = self.curr_y + LENGTH; - if max_x > self.nx || max_y > self.ny { - None - } else { - Some( - (self.curr_x..max_x) - .zip(self.curr_y..max_y) - .map(|(x, y)| Coordinate::new(x, y)) - .collect(), - ) - } - } -} - -impl Iterator for Grid { - type Item = Neighbours; - - fn next(&mut self) -> Option { - let has_wrapped; - (self.curr_direction, has_wrapped) = self.curr_direction.next(); - if has_wrapped { - self.advance_index(); - }; - self.get_neighbours() - } -} - -#[derive(Debug)] -enum Direction { - None, - Down, - Right, - DiagonalUp, - DiagonalDown, -} - -impl Direction { - fn next(&self) -> (Self, bool) { - match self { - Direction::None => (Direction::Down, false), - Direction::Down => (Direction::Right, false), - Direction::Right => (Direction::DiagonalUp, false), - Direction::DiagonalUp => (Direction::DiagonalDown, false), - Direction::DiagonalDown => (Direction::Down, true), - } - } -} +use grid::Grid; fn main() { let mut grid = Grid::from_file("grid.txt"); diff --git a/src/euler11/src/neighbours.rs b/src/euler11/src/neighbours.rs new file mode 100644 index 0000000..da24584 --- /dev/null +++ b/src/euler11/src/neighbours.rs @@ -0,0 +1,107 @@ +use crate::coordinate::Coordinate; +use crate::direction::Direction; + +const LENGTH: usize = 4; + +pub struct Neighbours { + nx: usize, + ny: usize, + x: usize, + y: usize, + current_direction: Direction, + done: bool, +} + +impl Neighbours { + pub fn new(nx: usize, ny: usize) -> Self { + Self { + nx, + ny, + x: 0, + y: 0, + current_direction: Direction::Down, + done: false, + } + } + + fn iterate_direction(&mut self) { + let (new_direction, has_wrapped) = self.current_direction.next().unwrap(); + self.current_direction = new_direction; + if has_wrapped { + self.x += 1; + if self.x == self.nx { + self.x = 0; + self.y += 1; + if self.y == self.ny { + self.done = true; + } + } + } + } +} + +impl Iterator for Neighbours { + type Item = [Coordinate; 4]; + + fn next(&mut self) -> Option { + if self.done { + return None; + } + + let x = self.x; + let y = self.y; + + let x_idxs; + let y_idxs; + + match self.current_direction { + Direction::Down => { + x_idxs = [x; 4]; + y_idxs = [y, y + 1, y + 2, y + 3]; + } + Direction::Right => { + x_idxs = [x, x + 1, x + 2, x + 3]; + y_idxs = [y; 4]; + } + Direction::DiagonalUp => { + if y < LENGTH { + self.iterate_direction(); + return self.next(); + } + x_idxs = [x, x + 1, x + 2, x + 3]; + y_idxs = [y, y - 1, y - 2, y - 3]; + } + Direction::DiagonalDown => { + x_idxs = [x, x + 1, x + 2, x + 3]; + y_idxs = [y, y + 1, y + 2, y + 3]; + } + } + + if x_idxs.iter().any(|x| *x >= self.nx) || y_idxs.iter().any(|y| *y >= self.ny) { + self.iterate_direction(); + return self.next(); + } + + let result = Coordinate::from_coordinate_pairs(x_idxs, y_idxs); + + self.iterate_direction(); + + Some(result) + } +} + +#[cfg(test)] +mod test { + use super::Neighbours; + use crate::coordinate::Coordinate as C; + + #[test] + fn neighbours() { + let mut n = Neighbours::new(20, 20); + n.next() + .unwrap() + .iter() + .zip([C::new(0, 0), C::new(0, 1), C::new(0, 2), C::new(0, 3)]) + .for_each(|(c1, c2)| assert_eq!(*c1, c2)); + } +}