diff --git a/src/main.rs b/src/main.rs index dc85fbc..46aa477 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,9 @@ use clap::Parser; +mod playfield; + +use playfield::Playfield; + #[derive(Parser)] #[command(version, about, long_about = None)] struct Cli { @@ -12,157 +16,10 @@ struct Cli { field_size: usize, } -#[derive(PartialEq, Debug, Clone)] -struct Playfield { - fields: Vec>, - open_fields: Vec, -} - -#[derive(Clone, PartialEq, Debug)] -struct Field { - possible_values: Vec, - value: Option, -} - -use std::fmt; -impl Playfield { - fn new(size: usize) -> Playfield { - Self { - fields: vec![vec![Field::default(); size]; size], - open_fields: Vec::::new(), - } - } -} - -impl fmt::Display for Playfield { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut result = String::new(); - for row in &self.fields { - for field in row { - result += &field.value.unwrap_or_else(|| 0).to_string(); - result += " "; - } - result += "\n"; - } - write!(f, "{}", result) - } -} - -impl Field { - fn default() -> Field { - Self { - possible_values: Vec::::new(), - value: None, - } - } -} - fn main() { let cli = Cli::parse(); - let playfield = parse_playfield(&cli.field, cli.field_size); + let playfield = Playfield::new(&cli.field, cli.field_size); println!("Input:\n{}", playfield) } - -fn parse_playfield(field: &String, field_size: usize) -> Playfield { - let mut playfield = Playfield::new(field_size); - - let chars = field.split(" ").collect::>(); - - if !is_right_field_size(&chars, field_size) { - panic!( - "Input must have dimension of size {size}x{size}", - size = field_size - ); - } - - for row in 0..field_size { - for col in 0..field_size { - let field = &mut playfield.fields[row][col]; - let char_field = chars.get(row * field_size + col).unwrap(); - - if *char_field == "0" { - continue; - } - - field.value = Some(char_field.parse().unwrap_or_else(|char_field| { - panic!( - "Input must contain only digits followed by space. Disallowed character: {}", - char_field - ) - })); - } - } - - return playfield; -} - -fn is_right_field_size(field: &Vec<&str>, field_size: usize) -> bool { - return field.len() == field_size * field_size; -} - -#[cfg(test)] -mod tests { - use super::*; - - impl Field { - fn new(value: u32) -> Field { - Self { - possible_values: Vec::::new(), - value: Some(value), - } - } - } - - mod parse_field { - use super::super::*; - - #[test] - fn simple() { - let input = "1 2 3 0 0 0 3 2 1"; - let field_size = 3; - - let playfield = parse_playfield(&input.to_string(), field_size); - - assert_eq!( - playfield, - Playfield { - fields: vec![ - vec![Field::new(1), Field::new(2), Field::new(3)], - vec![Field::default(), Field::default(), Field::default()], - vec![Field::new(3), Field::new(2), Field::new(1)] - ], - open_fields: vec![] - } - ) - } - - #[test] - #[should_panic(expected = "Input must have dimension of size 2x2")] - fn too_long_input() { - let input = "1 2 3 0 0 0 3 2 1"; - let field_size = 2; - - let _ = parse_playfield(&input.to_string(), field_size); - } - - #[test] - #[should_panic(expected = "Input must have dimension of size 3x3")] - fn too_short_input() { - let input = "1 2 3"; - let field_size = 3; - - let _ = parse_playfield(&input.to_string(), field_size); - } - - #[test] - #[should_panic(expected = "Input must contain only digits followed by space")] - fn wrong_character() { - let input = "1 2 3 0 0 0 3 2 a"; - let field_size = 3; - - let _ = parse_playfield(&input.to_string(), field_size); - } - } -} diff --git a/src/playfield.rs b/src/playfield.rs new file mode 100644 index 0000000..e48fa08 --- /dev/null +++ b/src/playfield.rs @@ -0,0 +1,148 @@ +use std::fmt; +#[derive(PartialEq, Debug)] +pub struct Playfield { + size: usize, + fields: Vec>, + open_fields: Vec, +} + +impl Playfield { + pub fn default(size: usize) -> Playfield { + Self { + size, + fields: vec![vec![Field::default(); size]; size], + open_fields: Vec::::new(), + } + } + pub fn new(field: &String, size: usize) -> Playfield { + let mut playfield = Playfield::default(size); + + playfield.parse(field); + + return playfield; + } + + fn parse(&mut self, field: &String) { + let chars = field.split(" ").collect::>(); + + if chars.len() != self.size * self.size { + panic!( + "Input must have dimension of size {size}x{size}", + size = self.size + ); + } + + for row in 0..self.size { + for col in 0..self.size { + let field = &mut self.fields[row][col]; + let char_field = chars.get(row * self.size + col).unwrap(); + + if *char_field == "0" { + continue; + } + + field.value = Some(char_field.parse().unwrap_or_else(|char_field| { + panic!( + "Input must contain only digits followed by space. Disallowed character: {}", + char_field + ) + })); + } + } + } +} + +impl fmt::Display for Playfield { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut result = String::new(); + for row in &self.fields { + for field in row { + result += &field.value.unwrap_or_else(|| 0).to_string(); + result += " "; + } + result += "\n"; + } + write!(f, "{}", result) + } +} + +#[derive(Clone, PartialEq, Debug)] +struct Field { + possible_values: Vec, + value: Option, +} + +impl Field { + fn default() -> Field { + Self { + possible_values: Vec::::new(), + value: None, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + impl Field { + fn new(value: u32) -> Field { + Self { + possible_values: Vec::::new(), + value: Some(value), + } + } + } + + mod parse { + use super::super::*; + + #[test] + fn simple() { + let input = "1 2 3 0 0 0 3 2 1"; + let field_size = 3; + + let playfield = Playfield::new(&input.to_string(), field_size); + + assert_eq!( + playfield, + Playfield { + size: 3, + fields: vec![ + vec![Field::new(1), Field::new(2), Field::new(3)], + vec![Field::default(), Field::default(), Field::default()], + vec![Field::new(3), Field::new(2), Field::new(1)] + ], + open_fields: vec![] + } + ) + } + + #[test] + #[should_panic(expected = "Input must have dimension of size 2x2")] + fn too_long_input() { + let input = "1 2 3 0 0 0 3 2 1"; + let field_size = 2; + + let _ = Playfield::new(&input.to_string(), field_size); + } + + #[test] + #[should_panic(expected = "Input must have dimension of size 3x3")] + fn too_short_input() { + let input = "1 2 3"; + let field_size = 3; + + let _ = Playfield::new(&input.to_string(), field_size); + } + + #[test] + #[should_panic(expected = "Input must contain only digits followed by space")] + fn wrong_character() { + let input = "1 2 3 0 0 0 3 2 a"; + let field_size = 3; + + let _ = Playfield::new(&input.to_string(), field_size); + } + } +}