Last active
February 2, 2022 16:26
-
-
Save bjjb/0b4c6744c0ce609abcdc9f3b8a7bd968 to your computer and use it in GitHub Desktop.
A Rust implementation of the Mars Rover exercise.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use rover::Rover; | |
use std::{env, io}; | |
fn main() { | |
let mut r = match Rover::from_args(env::args()) { | |
Ok(r) => r, | |
Err(e) => return eprintln!("{}", e), | |
}; | |
println!("{}", r.report()); | |
loop { | |
let mut cmd = String::new(); | |
match io::stdin().read_line(&mut cmd) { | |
Ok(_) => match r.send(&cmd.trim()) { | |
Ok(position) => println!("{}", position), | |
Err(error) => eprintln!("error! {}", error), | |
}, | |
Err(_) => eprintln!("error reading input"), | |
}; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::env; | |
const COMPASS: [&str; 4] = [ "NORTH", "EAST", "SOUTH", "WEST" ]; | |
const NORTH: &str = COMPASS[0]; | |
const EAST: &str = COMPASS[1]; | |
const SOUTH: &str = COMPASS[2]; | |
const WEST: &str = COMPASS[3]; | |
#[derive(Clone)] | |
#[derive(Debug)] | |
pub struct Rover { | |
x: i64, | |
y: i64, | |
h: &'static str, | |
obstacles: Vec<(i64, i64)>, | |
stopped: bool, | |
} | |
impl Rover { | |
pub fn new(x: i64, y: i64, h: &str) -> Rover { | |
let h = COMPASS.iter().find(|&x| *x == h).unwrap(); | |
let obstacles = vec![]; | |
let stopped = false; | |
Rover { x, y, h, obstacles, stopped } | |
} | |
pub fn from_args(mut args: env::Args) -> Result<Rover, &'static str> { | |
args.next(); | |
let x = match args.next() { | |
Some(x) => x, | |
None => return Err("no x provided"), | |
}; | |
let y = match args.next() { | |
Some(y) => y, | |
None => return Err("no y provided"), | |
}; | |
let h = match args.next() { | |
Some(h) => h, | |
None => return Err("no h provided"), | |
}; | |
let x = match x.parse::<i64>() { | |
Ok(x) => x, | |
Err(_) => return Err("invalid value for x"), | |
}; | |
let y = match y.parse::<i64>() { | |
Ok(y) => y, | |
Err(_) => return Err("invalid value for y"), | |
}; | |
let h = match COMPASS.iter().find(|s| **s == h) { | |
Some(h) => h, | |
None => return Err("invalid heading"), | |
}; | |
Ok(Rover::new(x, y, h)) | |
} | |
pub fn report(&self) -> String { | |
let mut s = format!("({}, {}) {}", self.x, self.y, self.h); | |
if self.stopped { | |
s = s + " STOPPED"; | |
} | |
s | |
} | |
pub fn send(&mut self, commands: &str) -> Result<String, &'static str>{ | |
for c in commands.chars() { | |
match c { | |
'F' => self.mv(1), | |
'B' => self.mv(-1), | |
'L' => self.turn(-1), | |
'R' => self.turn(1), | |
_ => return Err("invalid command"), | |
}; | |
}; | |
Ok(self.report()) | |
} | |
fn mv(&mut self, steps: i64) { | |
self.stopped = false; | |
let (mut x, mut y) = (self.x, self.y); | |
match self.h { | |
NORTH => y += steps, | |
SOUTH => y -= steps, | |
EAST => x += steps, | |
WEST => x -= steps, | |
_ => panic!("rover has an invalid direction: {}", self.h), | |
} | |
for (ox, oy) in self.obstacles.iter() { | |
if *ox == x && *oy == y { | |
self.stopped = true; | |
return | |
} | |
} | |
self.x = x; | |
self.y = y; | |
} | |
fn turn(&mut self, amount: i8) { | |
let i = COMPASS.iter().position(|&x| x == self.h).unwrap() as i8; | |
let h = (i + 4 + amount) % 4; | |
self.h = COMPASS[h as usize]; | |
} | |
} | |
#[test] | |
fn it_can_be_initialized() { | |
let r = Rover::new(0, 0, NORTH); | |
assert_eq!("(0, 0) NORTH", r.report()); | |
} | |
#[test] | |
fn it_can_receive_commands() { | |
let mut r = Rover::new(4, 2, EAST); | |
r.send("FLFFFRFLB"); | |
assert_eq!("(6, 4) NORTH", r.report()); | |
r.send("BBLL"); | |
assert_eq!("(6, 2) SOUTH", r.report()); | |
} | |
#[test] | |
fn it_can_stop_at_abstacles() { | |
let mut r = Rover::new(0, 0, NORTH); | |
r.obstacles = vec![(-2, 7), (1, 1)]; | |
r.send("FRF"); | |
assert_eq!("(0, 1) EAST STOPPED", r.report()); | |
r.send("FFF"); | |
assert_eq!("(0, 1) EAST STOPPED", r.report()); | |
r.send("LFRFFRFRF"); | |
assert_eq!("(2, 1) WEST STOPPED", r.report()); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment