use std::fmt; #[derive(PartialEq, Debug, Clone)] pub struct Playfield { pub size: usize, pub fields: Vec>, pub 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); 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 index = row * self.size + col; let field = &mut self.fields[row][col]; let char_field = chars.get(index).unwrap(); if *char_field == "0" { self.open_fields.push(index); 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)] pub struct Field { pub possible_values: Vec, pub 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); } } }