dancing_droids/src/main.rs
2020-10-20 16:57:51 +02:00

185 lines
4.7 KiB
Rust

use clap::{App, Arg};
use queues::*;
use std::fs;
use std::io;
/// Struct to store the world.
struct World {
x: u32,
y: u32,
map: Vec<char>,
}
impl World {
/// Create a new map full of dots.
fn create_map(&mut self) {
self.map = vec!['.'; (self.x * self.y) as usize];
}
/// Set robot on the map.
fn set_robot(&mut self, r: Robot) {
self.map[(r.p.x * r.p.y) as usize] = match r.o {
Orientation::N => '↑',
Orientation::S => '↓',
Orientation::E => '→',
Orientation::W => '←',
}
}
/// Check if a position is free.
fn empty_position(&mut self, p: Position) -> bool {
self.map[(p.x * p.y) as usize] == '.'
}
}
/// Struct to store robot position.
struct Position {
x: u32,
y: u32,
}
/// A Robot *aka droid* is represented here.
/// Each robot must have a unique id.
struct Robot {
id: u32,
o: Orientation,
p: Position,
q: Queue<char>,
}
impl Robot {
/// Apply forward instruction to the robot.
fn move_forward(&mut self) {
match self.o {
Orientation::N => self.p.y -= 1,
Orientation::S => self.p.y += 1,
Orientation::E => self.p.x += 1,
Orientation::W => self.p.x -= 1,
}
}
/// Apply right instruction to the robot.
fn move_right(&mut self) {
match self.o {
Orientation::N => self.p.x += 1,
Orientation::S => self.p.x -= 1,
Orientation::E => self.p.y += 1,
Orientation::W => self.p.y -= 1,
}
}
/// Apply left instruction to the robot.
fn move_left(&mut self) {
match self.o {
Orientation::N => self.p.x -= 1,
Orientation::S => self.p.x += 1,
Orientation::E => self.p.y -= 1,
Orientation::W => self.p.y += 1,
}
}
/// Apply North orientation to the robot.
fn turn_north(&mut self) {
self.o = Orientation::N
}
/// Apply South orientation to the robot.
fn turn_south(&mut self) {
self.o = Orientation::S
}
/// Apply East orientation to the robot.
fn turn_east(&mut self) {
self.o = Orientation::E
}
/// Apply West orientation to the robot.
fn turn_west(&mut self) {
self.o = Orientation::W
}
}
/// Enum to store all possible orientations.
enum Orientation {
N,
E,
S,
W,
}
/// Enum to store all possible instructions.
enum Instruction {
L,
R,
F,
}
/// Parse char and return corresponding orientation.
fn parse_orientation(c: char) -> Result<Orientation, &'static str> {
match c {
'N' => Ok(Orientation::N),
'E' => Ok(Orientation::E),
'S' => Ok(Orientation::S),
'W' => Ok(Orientation::W),
_ => Err("Invalid character, does not match any orientations"),
}
}
/// Parse char and return corresponding instruction.
fn parse_instruction(c: char) -> Result<Instruction, &'static str> {
match c {
'L' => Ok(Instruction::L),
'R' => Ok(Instruction::R),
'F' => Ok(Instruction::F),
_ => Err("Invalid character, does not match any instructions"),
}
}
/// Retrieve the content of a file and return it as a string.
fn open_file(filename: &str) -> io::Result<String> {
let content = fs::read_to_string(filename)?;
Ok(content)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
// We handle CLI flags here.
let matches = App::new("DancingDroids")
.version("0.1.0")
.about("When droids dance togethers")
.arg(
Arg::with_name("file")
.short("f")
.long("file")
.takes_value(true)
.help("Configuration file"),
)
.get_matches();
let raw_conf = open_file(matches.value_of("file").unwrap_or("two_robots.txt"))?;
// We store all the robots inside a pool O_o
let mut robot_pool: Vec<Robot> = Vec::new();
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_orientation() {
assert!(parse_orientation('N').is_ok());
assert!(parse_orientation('E').is_ok());
assert!(parse_orientation('S').is_ok());
assert!(parse_orientation('W').is_ok());
assert!(parse_orientation('Z').is_err());
}
#[test]
fn test_parse_instruction() {
assert!(parse_instruction('L').is_ok());
assert!(parse_instruction('R').is_ok());
assert!(parse_instruction('F').is_ok());
assert!(parse_instruction('Z').is_err());
}
#[test]
fn test_open_file() {
assert!(open_file("two_robots.txt").is_ok());
assert!(open_file("test_unexisting_file.extension").is_err());
}
}