diff --git a/src/main.rs b/src/main.rs index 690742a..097c868 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,31 +46,147 @@ fn check_collisions( } /// Parse the config file, generate the world and robot pool. -fn parse_config(conf: String, pool: &mut Vec) -> Result { +fn parse_config(conf: String, pool: &mut Vec) -> Result { let mut lines = conf.lines(); // The first line of the config file should be the World. let raw_line: &str = match lines.next() { Some(raw) => raw, - None => return Err("Could not read the first line of the config file !"), + None => { + return Err(String::from( + "Could not read the first line of the config file !", + )) + } }; let mut tokens = raw_line.split_whitespace(); let token1 = match tokens.next() { Some(raw) => raw, - None => return Err("Could not read the first token of the first line !"), + None => { + return Err(String::from( + "Could not read the first token of the first line !", + )) + } }; let token2 = match tokens.next() { Some(raw) => raw, - None => return Err("Could not read the second token of the first line !"), + None => { + return Err(String::from( + "Could not read the second token of the first line !", + )) + } }; let x: i32 = match token1.parse::() { Ok(x) => x, - Err(_) => return Err("Could not convert token one from the first string to i32"), + Err(_) => { + return Err(String::from( + "Could not convert token one from the first string to i32", + )) + } }; let y: i32 = match token2.parse::() { Ok(x) => x, - Err(_) => return Err("Could not convert token two from the first string to i32"), + Err(_) => { + return Err(String::from( + "Could not convert token two from the first string to i32", + )) + } }; - Ok(world::World { x, y }) + let w = world::World { x, y }; + let mut r_id: u32 = 0; + loop { + r_id += 1; + // This line should be empty. + let empty_line = match lines.next() { + None => break, + Some(x) => x, + }; + if !empty_line.is_empty() { + return Err(String::from("This line should be empty !")); + } + let raw_setup = match lines.next() { + None => return Err(String::from("This line should be the config !")), + Some(raw) => raw, + }; + if raw_setup.is_empty() { + return Err(String::from("This line should not be empty !")); + } + let raw_inst = match lines.next() { + None => return Err(String::from("This line should be the instruction !")), + Some(raw) => raw, + }; + if raw_inst.is_empty() { + return Err(String::from("This line should not be empty !")); + } + // Parse the setup line of the robot. + let mut setup = raw_setup.split_whitespace(); + let pos_x = match setup.next() { + None => { + return Err(String::from( + "Could not read the first token of the setup line !", + )) + } + Some(raw) => raw, + }; + let pos_y = match setup.next() { + None => { + return Err(String::from( + "Could not read the second token of the setup line !", + )) + } + Some(raw) => raw, + }; + let orientation = match setup.next() { + None => { + return Err(String::from( + "Could not read the third token of the setup line !", + )) + } + Some(raw) => raw, + }; + // Convert values of the setup line + let r_x = match pos_x.parse::() { + Err(_) => { + return Err(String::from( + "Could not convert the first token of the setup ligne to i32 !", + )) + } + Ok(raw) => raw, + }; + let r_y = match pos_y.parse::() { + Err(_) => { + return Err(String::from( + "Could not convert the second token of the setup ligne to i32 !", + )) + } + Ok(raw) => raw, + }; + let r_o = match orientation { + "N" => robot::Orientation::N, + "E" => robot::Orientation::E, + "S" => robot::Orientation::S, + "W" => robot::Orientation::W, + _ => { + return Err(String::from( + "The third token of the setup line do not match any orientations !", + )) + } + }; + + // Convert instructions line. + let inst: Vec = raw_inst.chars().collect(); + if !world::is_instructions(&inst) { + return Err(String::from("Invalid instructions !")); + } + + let r = robot::Robot::new(r_id, r_o, robot::Position { x: r_x, y: r_y }, inst); + + // Load robot inside the pool. + match check_map(&r, &w) { + Ok(()) => pool.push(r), + Err(err) => return Err(err), + } + } + + Ok(w) } /// Retrieve the content of a file and return it as a string. diff --git a/src/robot.rs b/src/robot.rs index a06e218..7ab8c5a 100644 --- a/src/robot.rs +++ b/src/robot.rs @@ -56,6 +56,19 @@ pub struct Position { pub y: i32, } +/// Check if instructions list is valid. +pub fn is_instructions(v: &Vec) -> bool { + for c in v { + match c { + 'F' => continue, + 'R' => continue, + 'L' => continue, + _ => return false, + } + } + true +} + #[cfg(test)] mod tests { use super::*; @@ -95,4 +108,17 @@ mod tests { assert_eq!(r.p.x, 0); assert_eq!(r.p.y, 3); } + + #[test] + fn is_instructions_test() { + let v = vec!['F', 'R', 'L', 'F']; + assert!(is_instructions(&v)); + } + + #[test] + #[should_panic] + fn is_instructions_test_fail() { + let v = vec!['F', 'R', 'L', 'Z']; + assert!(is_instructions(&v)); + } }