2020-10-20 12:48:28 +02:00
|
|
|
use clap::{App, Arg};
|
2020-10-20 15:38:03 +02:00
|
|
|
use queues::*;
|
2020-10-13 10:31:50 +02:00
|
|
|
use std::fs;
|
|
|
|
use std::io;
|
|
|
|
|
2020-10-19 12:23:38 +02:00
|
|
|
/// Struct to store the world.
|
|
|
|
struct World {
|
|
|
|
x: u32,
|
|
|
|
y: u32,
|
2020-10-19 12:32:14 +02:00
|
|
|
map: Vec<char>,
|
2020-10-19 12:23:38 +02:00
|
|
|
}
|
|
|
|
|
2020-10-20 13:42:32 +02:00
|
|
|
impl World {
|
|
|
|
/// Create a new map full of dots.
|
2020-10-20 21:39:45 +02:00
|
|
|
fn create(&mut self) {
|
2020-10-20 13:42:32 +02:00
|
|
|
self.map = vec!['.'; (self.x * self.y) as usize];
|
|
|
|
}
|
2020-10-20 13:57:23 +02:00
|
|
|
/// 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 {
|
2020-10-20 14:10:47 +02:00
|
|
|
Orientation::N => '↑',
|
|
|
|
Orientation::S => '↓',
|
|
|
|
Orientation::E => '→',
|
|
|
|
Orientation::W => '←',
|
2020-10-20 13:57:23 +02:00
|
|
|
}
|
|
|
|
}
|
2020-10-20 16:57:51 +02:00
|
|
|
/// Check if a position is free.
|
|
|
|
fn empty_position(&mut self, p: Position) -> bool {
|
|
|
|
self.map[(p.x * p.y) as usize] == '.'
|
|
|
|
}
|
2020-10-20 13:42:32 +02:00
|
|
|
}
|
|
|
|
|
2020-10-19 12:23:38 +02:00
|
|
|
/// Struct to store robot position.
|
2020-10-16 09:11:28 +02:00
|
|
|
struct Position {
|
2020-10-26 13:32:14 +01:00
|
|
|
x: i32,
|
|
|
|
y: i32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Position {
|
|
|
|
/// Check if position is in the map.
|
|
|
|
fn is_valid(self, w: World) -> Result<(), String> {
|
|
|
|
if (self.x, self.y) > (0, 0) && (self.x, self.y) < (w.x as i32, w.y as i32) {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(String::from("Invalid position."))
|
|
|
|
}
|
|
|
|
}
|
2020-10-16 09:11:28 +02:00
|
|
|
}
|
|
|
|
|
2020-10-17 18:16:40 +02:00
|
|
|
/// A Robot *aka droid* is represented here.
|
|
|
|
/// Each robot must have a unique id.
|
2020-10-16 09:11:28 +02:00
|
|
|
struct Robot {
|
2020-10-16 12:59:40 +02:00
|
|
|
id: u32,
|
2020-10-16 09:11:28 +02:00
|
|
|
o: Orientation,
|
|
|
|
p: Position,
|
2020-10-20 15:38:03 +02:00
|
|
|
q: Queue<char>,
|
2020-10-16 09:11:28 +02:00
|
|
|
}
|
|
|
|
|
2020-10-20 11:53:53 +02:00
|
|
|
impl Robot {
|
2020-10-26 13:00:30 +01:00
|
|
|
/// Create a empty Robot.
|
|
|
|
fn new() -> Robot {
|
|
|
|
Robot {
|
|
|
|
id: 0,
|
|
|
|
o: Orientation::N,
|
|
|
|
p: Position { x: 0, y: 0 },
|
|
|
|
q: queue![],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// Initialize a new Robot.
|
|
|
|
fn create(&mut self, id: u32, o: Orientation, p: Position, s: String) {
|
|
|
|
let mut q: Queue<char> = queue![];
|
|
|
|
for c in s.chars() {
|
|
|
|
q.add(c);
|
|
|
|
}
|
|
|
|
self.id = id;
|
|
|
|
self.o = o;
|
|
|
|
self.p = p;
|
|
|
|
self.q = q;
|
|
|
|
}
|
2020-10-20 11:53:53 +02:00
|
|
|
/// 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.
|
2020-10-20 21:39:45 +02:00
|
|
|
fn set_north(&mut self) {
|
2020-10-20 11:53:53 +02:00
|
|
|
self.o = Orientation::N
|
|
|
|
}
|
|
|
|
/// Apply South orientation to the robot.
|
2020-10-20 21:39:45 +02:00
|
|
|
fn set_south(&mut self) {
|
2020-10-20 11:53:53 +02:00
|
|
|
self.o = Orientation::S
|
|
|
|
}
|
|
|
|
/// Apply East orientation to the robot.
|
2020-10-20 21:39:45 +02:00
|
|
|
fn set_east(&mut self) {
|
2020-10-20 11:53:53 +02:00
|
|
|
self.o = Orientation::E
|
|
|
|
}
|
|
|
|
/// Apply West orientation to the robot.
|
2020-10-20 21:39:45 +02:00
|
|
|
fn set_west(&mut self) {
|
2020-10-20 11:53:53 +02:00
|
|
|
self.o = Orientation::W
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-17 18:16:40 +02:00
|
|
|
/// Enum to store all possible orientations.
|
2020-10-11 18:25:42 +02:00
|
|
|
enum Orientation {
|
2020-10-06 23:25:17 +02:00
|
|
|
N,
|
|
|
|
E,
|
|
|
|
S,
|
|
|
|
W,
|
2020-10-06 20:34:48 +02:00
|
|
|
}
|
2020-10-06 23:25:17 +02:00
|
|
|
|
2020-10-17 18:16:40 +02:00
|
|
|
/// Enum to store all possible instructions.
|
2020-10-11 18:25:42 +02:00
|
|
|
enum Instruction {
|
2020-10-06 23:28:59 +02:00
|
|
|
L,
|
|
|
|
R,
|
|
|
|
F,
|
|
|
|
}
|
|
|
|
|
2020-10-17 18:16:40 +02:00
|
|
|
/// Parse char and return corresponding orientation.
|
2020-10-11 21:45:56 +02:00
|
|
|
fn parse_orientation(c: char) -> Result<Orientation, &'static str> {
|
2020-10-11 18:27:39 +02:00
|
|
|
match c {
|
2020-10-11 20:10:17 +02:00
|
|
|
'N' => Ok(Orientation::N),
|
|
|
|
'E' => Ok(Orientation::E),
|
|
|
|
'S' => Ok(Orientation::S),
|
|
|
|
'W' => Ok(Orientation::W),
|
|
|
|
_ => Err("Invalid character, does not match any orientations"),
|
2020-10-11 18:27:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-17 18:16:40 +02:00
|
|
|
/// Parse char and return corresponding instruction.
|
2020-10-11 21:45:56 +02:00
|
|
|
fn parse_instruction(c: char) -> Result<Instruction, &'static str> {
|
2020-10-11 18:31:56 +02:00
|
|
|
match c {
|
2020-10-11 20:10:17 +02:00
|
|
|
'L' => Ok(Instruction::L),
|
|
|
|
'R' => Ok(Instruction::R),
|
|
|
|
'F' => Ok(Instruction::F),
|
|
|
|
_ => Err("Invalid character, does not match any instructions"),
|
2020-10-11 18:31:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-17 18:16:40 +02:00
|
|
|
/// Retrieve the content of a file and return it as a string.
|
2020-10-13 10:19:34 +02:00
|
|
|
fn open_file(filename: &str) -> io::Result<String> {
|
|
|
|
let content = fs::read_to_string(filename)?;
|
|
|
|
Ok(content)
|
|
|
|
}
|
|
|
|
|
2020-10-19 12:50:48 +02:00
|
|
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
2020-10-20 13:42:32 +02:00
|
|
|
// We handle CLI flags here.
|
2020-10-20 12:48:28 +02:00
|
|
|
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();
|
|
|
|
|
2020-10-20 13:17:50 +02:00
|
|
|
let raw_conf = open_file(matches.value_of("file").unwrap_or("two_robots.txt"))?;
|
2020-10-20 14:06:10 +02:00
|
|
|
|
|
|
|
// We store all the robots inside a pool O_o
|
|
|
|
let mut robot_pool: Vec<Robot> = Vec::new();
|
|
|
|
|
2020-10-19 12:50:48 +02:00
|
|
|
Ok(())
|
2020-10-11 15:14:20 +02:00
|
|
|
}
|
2020-10-13 12:07:47 +02:00
|
|
|
|
|
|
|
#[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());
|
|
|
|
}
|
2020-10-13 12:15:04 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_open_file() {
|
|
|
|
assert!(open_file("two_robots.txt").is_ok());
|
|
|
|
assert!(open_file("test_unexisting_file.extension").is_err());
|
|
|
|
}
|
2020-10-20 17:33:57 +02:00
|
|
|
|
|
|
|
#[test]
|
2020-10-20 21:39:45 +02:00
|
|
|
fn test_create() {
|
2020-10-20 17:33:57 +02:00
|
|
|
let mut w: World = World {
|
|
|
|
x: 5,
|
|
|
|
y: 5,
|
|
|
|
map: Vec::new(),
|
|
|
|
};
|
2020-10-20 21:39:45 +02:00
|
|
|
w.create();
|
2020-10-20 17:33:57 +02:00
|
|
|
assert_eq!(w.map, vec!['.'; 25]);
|
|
|
|
}
|
|
|
|
|
2020-10-26 13:14:44 +01:00
|
|
|
#[test]
|
|
|
|
fn test_new_robot() {
|
|
|
|
let mut r: Robot = Robot::new();
|
|
|
|
assert_eq!(r.id, 0);
|
|
|
|
assert!(matches!(r.o, Orientation::N));
|
|
|
|
|
|
|
|
assert_eq!(r.p.x, 0);
|
|
|
|
assert_eq!(r.p.y, 0);
|
|
|
|
|
|
|
|
assert_eq!(r.q.size(), 0);
|
|
|
|
}
|
|
|
|
|
2020-10-26 13:00:30 +01:00
|
|
|
#[test]
|
|
|
|
fn test_create_robot() {
|
|
|
|
let mut r: Robot = Robot::new();
|
|
|
|
r.create(1, Orientation::N, Position { x: 1, y: 1 }, "FF".to_string());
|
|
|
|
assert_eq!(r.id, 1);
|
|
|
|
assert!(matches!(r.o, Orientation::N));
|
|
|
|
|
|
|
|
assert_eq!(r.p.x, 1);
|
|
|
|
assert_eq!(r.p.y, 1);
|
|
|
|
|
|
|
|
assert_eq!(r.q.peek(), Ok('F'));
|
|
|
|
assert_eq!(r.q.peek(), Ok('F'));
|
|
|
|
}
|
|
|
|
|
2020-10-20 17:33:57 +02:00
|
|
|
#[test]
|
|
|
|
fn test_set_robot() {
|
|
|
|
let r = Robot {
|
|
|
|
id: 0,
|
|
|
|
o: Orientation::N,
|
|
|
|
p: Position { x: 0, y: 0 },
|
|
|
|
q: Queue::new(),
|
|
|
|
};
|
|
|
|
let mut w: World = World {
|
|
|
|
x: 2,
|
|
|
|
y: 2,
|
|
|
|
map: Vec::new(),
|
|
|
|
};
|
2020-10-20 21:39:45 +02:00
|
|
|
w.create();
|
2020-10-20 17:33:57 +02:00
|
|
|
w.set_robot(r);
|
|
|
|
assert_eq!(w.map, vec!['↑', '.', '.', '.']);
|
|
|
|
}
|
|
|
|
|
2020-10-26 13:32:14 +01:00
|
|
|
#[test]
|
|
|
|
fn test_move_robot() {
|
|
|
|
let mut r: Robot = Robot {
|
|
|
|
id: 0,
|
|
|
|
o: Orientation::N,
|
|
|
|
p: Position { x: 1, y: 1 },
|
|
|
|
q: Queue::new(),
|
|
|
|
};
|
|
|
|
r.move_forward();
|
|
|
|
assert_eq!(0, r.p.y);
|
|
|
|
r.move_right();
|
|
|
|
assert_eq!(2, r.p.x);
|
|
|
|
r.move_left();
|
|
|
|
assert_eq!(1, r.p.x);
|
|
|
|
}
|
|
|
|
|
2020-10-20 17:33:57 +02:00
|
|
|
#[test]
|
|
|
|
fn test_empty_position() {
|
|
|
|
let mut w: World = World {
|
|
|
|
x: 2,
|
|
|
|
y: 2,
|
|
|
|
map: Vec::new(),
|
|
|
|
};
|
2020-10-20 21:39:45 +02:00
|
|
|
w.create();
|
2020-10-20 17:33:57 +02:00
|
|
|
assert!(w.empty_position(Position { x: 0, y: 0 }));
|
|
|
|
}
|
2020-10-13 12:07:47 +02:00
|
|
|
}
|