From bfbdb6a20e674a7578b20312250440621e2854e1 Mon Sep 17 00:00:00 2001 From: Fabian Schmidt Date: Thu, 5 Dec 2024 07:50:46 +0100 Subject: [PATCH] added some grid stuff --- src/grid.rs | 244 +++++++++++++++++++++++++++++++++++++++++++-- src/permutation.rs | 29 +++--- 2 files changed, 252 insertions(+), 21 deletions(-) diff --git a/src/grid.rs b/src/grid.rs index ff76b51..8eda11c 100644 --- a/src/grid.rs +++ b/src/grid.rs @@ -1,7 +1,11 @@ +use core::panic; use std::error::Error; -#[derive(Debug)] -pub struct Grid(pub Vec>); +#[derive(Debug, PartialEq, Eq)] +pub struct Grid { + pub rows: Vec>, + pub width: u32, +} impl Grid { pub fn new(grid: Vec>) -> Result> { @@ -11,23 +15,245 @@ impl Grid { return Err(Box::from("Rows need to all be equal in length")); } } - Ok(Grid(grid)) + Ok(Grid { + rows: grid, + width: row_length as u32, + }) } - pub fn invert(&mut self) -> Self { - let height = self.0.len(); - let width = self.0[0].len(); + pub fn rotate_90(&mut self) -> Self { + let height = self.rows.len(); + let width = self.rows[0].len(); let mut new_grid = Vec::with_capacity(width); for col_idx in 0..width { let mut new_row = Vec::with_capacity(height); for row_idx in 0..height { - new_row.push(self.0[row_idx][col_idx].clone()); + new_row.push(self.rows[row_idx][col_idx].clone()); } new_grid.push(new_row); } - self.0 = new_grid; - Grid(self.0.clone()) + self.rows = new_grid; + self.width = height as u32; + Grid { + rows: self.rows.clone(), + width: height as u32, + } + } + + pub fn get_diagonals_aigu(&self) -> Vec> { + let mut diagonals = Vec::new(); + // col_idx == starting column of this diagonal + for col_idx in 0..self.width { + diagonals.push(self.get_diagonal_aigu(col_idx, 0)); + if col_idx == self.width - 1 { + // row_idx == starting row of this diagonal + for row_idx in 1..self.rows.len() as u32 { + diagonals.push(self.get_diagonal_aigu(col_idx, row_idx)); + } + } + } + diagonals + } + + fn get_diagonal_aigu(&self, starting_col: u32, starting_row: u32) -> Vec { + if starting_col != self.width - 1 && starting_row != 0 { + panic!("Start of diagonal needs to be valid. Start at top row or rightmost column"); + } + // col_idx == current col_idx of this diagonal + let mut col_idx = starting_col as usize; + // row_idx == current row_idx of this diagonal + let mut row_idx = starting_row as usize; + + let mut diagonal = Vec::new(); + + while let Some(row) = self.rows.get(row_idx) { + if let Some(element) = row.get(col_idx) { + diagonal.push(element.clone()); + if let Some(sub) = col_idx.checked_sub(1) { + col_idx = sub; + } else { + break; + } + row_idx += 1; + } else { + break; + } + } + + diagonal.reverse(); + diagonal + } + + pub fn get_diagonals_grave(&self) -> Vec> { + let mut diagonals = Vec::new(); + // col_idx == starting column of this diagonal + for col_idx in (0..self.width).rev() { + diagonals.push(self.get_diagonal_grave(col_idx, 0)); + if col_idx == 0 { + // row_idx == starting row of this diagonal + for row_idx in 1..self.rows.len() as u32 { + diagonals.push(self.get_diagonal_grave(col_idx, row_idx)); + } + } + } + diagonals + } + + fn get_diagonal_grave(&self, starting_col: u32, starting_row: u32) -> Vec { + if starting_col != 0 && starting_row != 0 { + panic!("Start of diagonal needs to be valid. Start at top row or leftmost column"); + } + // col_idx == current col_idx of this diagonal + let mut col_idx = starting_col as usize; + // row_idx == current row_idx of this diagonal + let mut row_idx = starting_row as usize; + + let mut diagonal = Vec::new(); + + while let Some(row) = self.rows.get(row_idx) { + if let Some(element) = row.get(col_idx) { + diagonal.push(element.clone()); + col_idx += 1; + row_idx += 1; + } else { + break; + } + } + + diagonal + } +} + +#[cfg(test)] +mod test { + use super::Grid; + + #[test] + fn diag_aigu_4x4() { + let grid = Grid::new(vec![ + vec!["a", "b", "c", "d"], + vec!["e", "f", "g", "h"], + vec!["i", "j", "k", "l"], + vec!["m", "n", "o", "p"], + ]) + .unwrap(); + let res = vec![ + vec!["a"], + vec!["e", "b"], + vec!["i", "f", "c"], + vec!["m", "j", "g", "d"], + vec!["n", "k", "h"], + vec!["o", "l"], + vec!["p"], + ]; + assert_eq!(res, grid.get_diagonals_aigu()); + } + + #[test] + fn diag_aigu_4x3() { + let grid = Grid::new(vec![ + vec!["a", "b", "c", "d"], + vec!["e", "f", "g", "h"], + vec!["i", "j", "k", "l"], + ]) + .unwrap(); + let res = vec![ + vec!["a"], + vec!["e", "b"], + vec!["i", "f", "c"], + vec!["j", "g", "d"], + vec!["k", "h"], + vec!["l"], + ]; + assert_eq!(res, grid.get_diagonals_aigu()); + } + + #[test] + fn diag_aigu_3x4() { + let grid = Grid::new(vec![ + vec!["a", "b", "c"], + vec!["d", "e", "f"], + vec!["g", "h", "i"], + vec!["j", "k", "l"], + ]) + .unwrap(); + let res = vec![ + vec!["a"], + vec!["d", "b"], + vec!["g", "e", "c"], + vec!["j", "h", "f"], + vec!["k", "i"], + vec!["l"], + ]; + assert_eq!(res, grid.get_diagonals_aigu()); + } + + #[test] + fn diag_grave_4x4() { + let grid = Grid::new(vec![ + vec!["a", "b", "c", "d"], + vec!["e", "f", "g", "h"], + vec!["i", "j", "k", "l"], + vec!["m", "n", "o", "p"], + ]) + .unwrap(); + let res = vec![ + vec!["d"], + vec!["c", "h"], + vec!["b", "g", "l"], + vec!["a", "f", "k", "p"], + vec!["e", "j", "o"], + vec!["i", "n"], + vec!["m"], + ]; + assert_eq!(res, grid.get_diagonals_grave()); + } + + #[test] + fn diag_grave_4x3() { + let grid = Grid::new(vec![ + vec!["a", "b", "c", "d"], + vec!["e", "f", "g", "h"], + vec!["i", "j", "k", "l"], + ]) + .unwrap(); + let res = vec![ + vec!["d"], + vec!["c", "h"], + vec!["b", "g", "l"], + vec!["a", "f", "k"], + vec!["e", "j"], + vec!["i"], + ]; + assert_eq!(res, grid.get_diagonals_grave()); + } + + #[test] + fn diag_grave_3x4() { + let grid = Grid::new(vec![ + vec!["a", "b", "c"], + vec!["d", "e", "f"], + vec!["g", "h", "i"], + vec!["j", "k", "l"], + ]) + .unwrap(); + let res = vec![ + vec!["c"], + vec!["b", "f"], + vec!["a", "e", "i"], + vec!["d", "h", "l"], + vec!["g", "k"], + vec!["j"], + ]; + assert_eq!(res, grid.get_diagonals_grave()); + } + + #[test] + fn rotate() { + let mut grid = Grid::new(vec![vec!["a", "b"], vec!["c", "d"]]).unwrap(); + let res = Grid::new(vec![vec!["a", "c"], vec!["b", "d"]]).unwrap(); + assert_eq!(res, grid.rotate_90()) } } diff --git a/src/permutation.rs b/src/permutation.rs index 6b66cdd..67424b6 100644 --- a/src/permutation.rs +++ b/src/permutation.rs @@ -1,9 +1,11 @@ use std::error::Error; -fn factorial(num: usize) -> usize { - let mut fact = 1; +use crate::number::Number; + +fn factorial(num: usize) -> Number { + let mut fact = Number::from(1); for n in 1..=num { - fact *= n; + fact *= Number::from(n as isize); } fact } @@ -25,17 +27,19 @@ pub fn nth_lex(mut digits: Vec, nth: usize) -> Result, if nth == 1 { return Ok(digits); } - if nth > factorial(digits.len()) || nth == 0 { + let nth = Number::from(nth as isize); + if nth > factorial(digits.len()) || nth == Number::from(0) { return Err(Box::from("Out of bounds")); } let mut perm = Vec::new(); let num_unique_digits = digits.len(); - let mut remainder = nth - 1; + let mut remainder = nth - 1.into(); for idx in 1..=digits.len() { - let permutations = remainder / factorial(num_unique_digits - idx); + let permutations = remainder.clone() / factorial(num_unique_digits - idx); remainder %= factorial(num_unique_digits - idx); - perm.push(digits[permutations].clone()); - digits.remove(permutations); + let permutations: isize = permutations.try_into().unwrap(); + perm.push(digits[permutations as usize].clone()); + digits.remove(permutations as usize); } Ok(perm) } @@ -65,16 +69,17 @@ impl Iterator for Permutator { return Some(self.elements.clone()); } let num_unique_elements = self.elements.len(); - if self.idx == factorial(num_unique_elements) { + if Number::from(self.idx as isize) == factorial(num_unique_elements) { return None; } let mut elements = self.elements.clone(); let mut perm = Vec::new(); - let mut remainder = self.idx; + let mut remainder = Number::from(self.idx as isize); for idx in 1..=num_unique_elements { - let permutations = remainder / factorial(num_unique_elements - idx); + let permutations = remainder.clone() / factorial(num_unique_elements - idx); remainder %= factorial(num_unique_elements - idx); - perm.push(elements.remove(permutations)); + let permutations: isize = permutations.try_into().unwrap(); + perm.push(elements.remove(permutations as usize)); } self.idx += 1; Some(perm)