Решение на Dungeons and Compilers от Надежда Панделиева
Към профила на Надежда Панделиева
Резултати
- 17 точки от тестове
- 0 бонус точки
- 17 точки общо
- 13 успешни тест(а)
- 2 неуспешни тест(а)
Код
#![allow(non_snake_case)]
#![allow(dead_code)]
use std::collections::HashMap;
use std::collections::VecDeque;
use std::io;
use std::io::prelude::*;
use std::fs::File;
#[derive(Debug)]
pub enum Errors {
DuplicateRoom(String),
UnknownRoom(String),
IoError(std::io::Error),
LineParseError { line_number: usize },
DirectionParseError(String),
}
#[derive(Clone, Copy,Hash,Eq)]
#[derive(PartialEq)]
pub enum Direction {
North,
South,
East,
West,
}
pub struct Room {
pub name: String,
pub directions: HashMap<Direction,String>
}
pub struct Dungeon {
map: HashMap<String,Room>,
}
impl Direction
{
pub fn getOppositeDirection(direction: Direction) -> Direction
{
match direction
{
Direction::North => Direction::South,
Direction::South => Direction::North,
Direction::East => Direction::West,
Direction::West => Direction::East
}
}
pub fn getDataFromString(str: &str) -> Option<Direction>
{
match str
{
"North" => Some(Direction::North),
"South" => Some(Direction::South),
"East" => Some(Direction::East),
"West" => Some(Direction::West),
_ => None
}
}
}
impl Dungeon {
pub fn new() -> Self {
Dungeon {
map: HashMap::new(),
}
}
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
if !self.map.contains_key(name){
let room: Room = Room{
name: name.to_string(),
directions: HashMap::new() ,
};
self.map.insert(name.to_string(), room);
Ok(())
}
else{
Err(Errors::DuplicateRoom(name.to_string()))
}
}
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
match self.map.contains_key(room_name){
true => return Ok(self.map.get(room_name).unwrap()),
false => return Err(Errors::UnknownRoom(room_name.to_string())),
};
}
pub fn set_link(&mut self,room_name: &str,direction: Direction, other_room_name: &str) -> Result<(), Errors> {
if self.map.contains_key(room_name){
if self.map.contains_key(other_room_name){
let opposite_direction: Direction = Direction::getOppositeDirection(direction);
self.map.get_mut(room_name).unwrap().directions.insert(direction,other_room_name.to_string());
self.map.get_mut(other_room_name).unwrap().directions.insert(opposite_direction,room_name.to_string());
Ok(())
}else{
Err(Errors::UnknownRoom(other_room_name.to_string()))
}
}
else{
Err(Errors::UnknownRoom(room_name.to_string()))
}
}
pub fn get_next_room(&self, room_name: &str, direction: Direction) -> Result<Option<&Room>, Errors> {
if self.map.contains_key(room_name){
if self.map.get(room_name).unwrap().directions.contains_key(&direction){
let room: &String = self.map.get(room_name).unwrap().directions.get(&direction).unwrap();
let next_room: &Room = self.map.get(room).unwrap();
Ok(Some(next_room))
}
else{
Ok(None)
}
}
else{
Err(Errors::UnknownRoom(room_name.to_string()))
}
}
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
//save somewhere the line numbers
let mut dungeon: Dungeon = Dungeon::new();
let mut buffer = String::new();
let mut reader = reader;
if reader.read_line(&mut buffer).unwrap() == 0{
return Err(Errors::LineParseError{ line_number: 0});
}
let mut empty_line = 0;
for (index, line) in reader.lines().enumerate(){
if !line.is_err(){
let mut line = line.unwrap();
if line.as_str().chars().next() == Some('#'){
match line.as_str(){
"## Rooms"=> continue,
"## Links" => continue,
_ => return Err(Errors::LineParseError{ line_number: index + 1 }),
}
}
else if line.is_empty(){
empty_line = empty_line + 1;
if empty_line > 1{
return Err(Errors::LineParseError{ line_number: index + 1 })
}
}
else if line.starts_with("- "){
let room = line.split_off(2);
if room.contains("->"){
let data: Vec<&str> = room.split(" -> ").collect();
let direction: Option<Direction> = Direction::getDataFromString(data[1]);
if direction.is_none(){
return Err(Errors::DirectionParseError(String::from(data[1])));
}
if let Err(error) = dungeon.set_link(data[0], direction.unwrap(), data[2]){
return Err(error);
}
}
else{
let x = dungeon.add_room(room.as_str());
if x.is_err() {
return Err(x.unwrap_err());
};
}
} else{
return Err(Errors::LineParseError{ line_number: index + 1 });
}
}
else{
return Err(Errors::IoError(line.err().unwrap()));
}
}
Ok(dungeon)
}
pub fn find_path(&self, start_room_name: &str, end_room_name: &str) -> Result<Option<Vec<&Room>>, Errors> {
let mut visited: HashMap<String, bool> = HashMap::new();
let mut queue: VecDeque<&Room> = VecDeque::new();
let mut parents: HashMap<String, String> = HashMap::new();
let mut path: Vec<&Room> = Vec::new();
if let Err(error) = self.get_room(start_room_name){
return Err(error)
};
if let Err(error) = self.get_room(end_room_name){
return Err(error)
};
//mark all unvisited
for key in self.map.iter() {
visited.insert(key.0.clone(), false);
}
queue.push_back(self.get_room(start_room_name).unwrap());
*visited.get_mut(start_room_name).unwrap() = true;
if start_room_name == end_room_name {
path.push(queue.pop_front().unwrap());
return Ok(Some(path))
}
else{
while !queue.is_empty(){
let current_room: &Room = queue.pop_back().unwrap().clone();
if current_room.name == self.get_room(end_room_name).unwrap().name{
break;
}
for next in current_room.directions.iter(){
if !next.1.is_empty(){
if visited[next.1] == false{
parents.insert(next.1.clone(), current_room.name.clone());
*visited.get_mut(next.1).unwrap() = true;
queue.push_back(self.get_room(next.1).unwrap());
}
}
}
}
if !parents.contains_key(end_room_name) { return Ok(None); }
let end = self.get_room(end_room_name);
if end.is_err() {
return Err(end.err().unwrap());
}
path.push(end.unwrap());
let mut current_room = parents.get(end_room_name).unwrap();
path.push(self.get_room(current_room).unwrap());
while parents.contains_key(current_room){
let parent: &String = parents.get(current_room).unwrap();
let parent_as_room= self.get_room(parent);
if parent_as_room.is_err(){
return Err(parent_as_room.err().unwrap());
}
path.push(parent_as_room.unwrap());
current_room = parents.get(current_room).unwrap();
}
path.reverse();
Ok(Some(path))
}
}
}
/*
const TEST_INPUT: &str = "
## Rooms
- Entrance
- Hallway
## Links
- Entrance -> East -> Hallway
";
const TEST_INPUT_2: &str = "hello";
///raboti ako e mahnat purviq red
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_for_errors() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Hallway").unwrap();
dungeon.set_link("Entrance", Direction::East, "Hallway").unwrap();
assert!(dungeon.get_next_room("Club33", Direction::South).is_err());
assert!(dungeon.get_room("Club33").is_err());
}
#[test]
fn test_basic_2() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Hallway").unwrap();
dungeon.set_link("Entrance", Direction::East, "Hallway").unwrap();
assert!(dungeon.get_next_room("Entrance", Direction::South).unwrap().is_none());
assert_eq!(dungeon.get_room("Entrance").unwrap().name, "Entrance");
assert_eq!(dungeon.get_next_room("Entrance", Direction::East).unwrap().unwrap().name, "Hallway");
}
#[test]
fn test_basic_3() {
let dungeon = Dungeon::from_reader(TEST_INPUT.trim().as_bytes()).unwrap();
assert_eq!(dungeon.get_room("Entrance").unwrap().name, "Entrance");
assert_eq!(dungeon.get_room("Hallway").unwrap().name, "Hallway");
assert_eq!(dungeon.get_next_room("Entrance", Direction::East).unwrap().unwrap().name, "Hallway");
}
#[test]
fn test_basic_5() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Treasure Room").unwrap();
dungeon.add_room("Obshtaka").unwrap();
dungeon.add_room("Fitness").unwrap();
dungeon.set_link("Entrance", Direction::West, "Treasure Room").unwrap();
dungeon.set_link("Treasure Room", Direction::South, "Obshtaka").unwrap();
dungeon.set_link("Obshtaka", Direction::East, "Fitness").unwrap();
let path = dungeon.find_path("Entrance", "Fitness").unwrap().unwrap();
assert!(path.len() > 0);
}
#[test]
fn test_basic_6() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Treasure Room").unwrap();
dungeon.add_room("Obshtaka").unwrap();
dungeon.add_room("Club33").unwrap();
dungeon.add_room("Fitness").unwrap();
dungeon.set_link("Entrance", Direction::West, "Treasure Room").unwrap();
dungeon.set_link("Treasure Room", Direction::South, "Obshtaka").unwrap();
dungeon.set_link("Obshtaka", Direction::East, "Fitness").unwrap();
dungeon.set_link("Entrance", Direction::East, "Club33").unwrap();
let path = dungeon.find_path("Fitness", "Club33").unwrap().unwrap();
assert!(path.len() > 0);
}
}
*/
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20220116-3533338-8s6xik/solution) warning: unused import: `std::io` --> src/lib.rs:7:5 | 7 | use std::io; | ^^^^^^^ | = note: `#[warn(unused_imports)]` on by default warning: unused import: `std::fs::File` --> src/lib.rs:9:5 | 9 | use std::fs::File; | ^^^^^^^^^^^^^ warning: `solution` (lib) generated 2 warnings Finished test [unoptimized + debuginfo] target(s) in 3.97s Running tests/solution_test.rs (target/debug/deps/solution_test-2e292b23ac75572c) running 15 tests test solution_test::test_adding_rooms_1 ... ok test solution_test::test_adding_rooms_2 ... ok test solution_test::test_cyrillic_room_names ... ok test solution_test::test_finding_a_direct_path ... ok test solution_test::test_finding_a_reflexive_path ... ok test solution_test::test_finding_an_indirect_path ... ok test solution_test::test_finding_no_path ... ok test solution_test::test_invalid_parsing ... FAILED test solution_test::test_io_error ... FAILED test solution_test::test_overwriting_a_room_link ... ok test solution_test::test_parsing_cyrillic_rooms ... ok test solution_test::test_parsing_no_rooms_or_links ... ok test solution_test::test_parsing_rooms ... ok test solution_test::test_room_errors ... ok test solution_test::test_room_links ... ok failures: ---- solution_test::test_invalid_parsing stdout ---- thread 'main' panicked at 'assertion failed: matches!(Dungeon :: from_reader(TEST_INPUT_4.trim().as_bytes()),\n Err(Errors :: LineParseError { line_number : 1 }))', tests/solution_test.rs:277:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ---- solution_test::test_io_error stdout ---- thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "fill_buf error!" }', /tmp/d20220116-3533338-8s6xik/solution/src/lib.rs:137:42 thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "fill_buf error!" }', tests/solution_test.rs:194:5 failures: solution_test::test_invalid_parsing solution_test::test_io_error test result: FAILED. 13 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s error: test failed, to rerun pass '--test solution_test'
История (3 версии и 0 коментара)
Надежда качи решение на 11.01.2022 00:40 (преди над 3 години)
#![allow(non_snake_case)]
#![allow(dead_code)]
use std::collections::HashMap;
use std::collections::VecDeque;
use std::io;
use std::io::prelude::*;
use std::fs::File;
#[derive(Debug)]
pub enum Errors {
DuplicateRoom(String),
UnknownRoom(String),
IoError(std::io::Error),
LineParseError { line_number: usize },
DirectionParseError(String),
}
#[derive(Clone, Copy,Hash,Eq)]
#[derive(PartialEq)]
pub enum Direction {
North,
South,
East,
West,
}
pub struct Room {
pub name: String,
pub directions: HashMap<Direction,String>
}
pub struct Dungeon {
map: HashMap<String,Room>,
}
impl Direction
{
pub fn getOppositeDirection(direction: Direction) -> Direction
{
match direction
{
Direction::North => Direction::South,
Direction::South => Direction::North,
Direction::East => Direction::West,
Direction::West => Direction::East
}
}
pub fn getDataFromString(str: &str) -> Option<Direction>
{
match str
{
"North" => Some(Direction::North),
"South" => Some(Direction::South),
"East" => Some(Direction::East),
"West" => Some(Direction::West),
_ => None
}
}
}
impl Dungeon {
pub fn new() -> Self {
Dungeon {
map: HashMap::new(),
}
}
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
if !self.map.contains_key(name){
let room: Room = Room{
name: name.to_string(),
directions: HashMap::new() ,
};
self.map.insert(name.to_string(), room);
Ok(())
}
else{
Err(Errors::DuplicateRoom(name.to_string()))
}
}
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
match self.map.contains_key(room_name){
true => return Ok(self.map.get(room_name).unwrap()),
false => return Err(Errors::UnknownRoom(room_name.to_string())),
};
}
pub fn set_link(&mut self,room_name: &str,direction: Direction, other_room_name: &str) -> Result<(), Errors> {
if self.map.contains_key(room_name){
if self.map.contains_key(other_room_name){
let opposite_direction: Direction = Direction::getOppositeDirection(direction);
self.map.get_mut(room_name).unwrap().directions.insert(direction,other_room_name.to_string());
self.map.get_mut(other_room_name).unwrap().directions.insert(opposite_direction,room_name.to_string());
Ok(())
}else{
Err(Errors::UnknownRoom(other_room_name.to_string()))
}
}
else{
Err(Errors::UnknownRoom(room_name.to_string()))
}
}
pub fn get_next_room(&self, room_name: &str, direction: Direction) -> Result<Option<&Room>, Errors> {
if self.map.contains_key(room_name){
if self.map.get(room_name).unwrap().directions.contains_key(&direction){
let room: &String = self.map.get(room_name).unwrap().directions.get(&direction).unwrap();
let next_room: &Room = self.map.get(room).unwrap();
Ok(Some(next_room))
}
else{
Ok(None)
}
}
else{
Err(Errors::UnknownRoom(room_name.to_string()))
}
}
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
//save somewhere the line numbers
let mut dungeon: Dungeon = Dungeon::new();
-
+ let mut buffer = String::new();
+ let mut reader = reader;
+ if reader.read_line(&mut buffer).unwrap() == 0{
+ return Err(Errors::LineParseError{ line_number: 0});
+ }
let mut empty_line = 0;
for (index, line) in reader.lines().enumerate(){
if !line.is_err(){
let mut line = line.unwrap();
if line.as_str().chars().next() == Some('#'){
match line.as_str(){
"## Rooms"=> continue,
"## Links" => continue,
_ => return Err(Errors::LineParseError{ line_number: index + 1 }),
}
}
else if line.is_empty(){
empty_line = empty_line + 1;
if empty_line > 1{
return Err(Errors::LineParseError{ line_number: index + 1 })
}
}
else if line.starts_with("- "){
let room = line.split_off(2);
if room.contains("->"){
let data: Vec<&str> = room.split(" -> ").collect();
let direction: Option<Direction> = Direction::getDataFromString(data[1]);
if direction.is_none(){
return Err(Errors::DirectionParseError(String::from(data[1])));
}
if let Err(error) = dungeon.set_link(data[0], direction.unwrap(), data[2]){
return Err(error);
}
}
else{
let x = dungeon.add_room(room.as_str());
if x.is_err() {
return Err(x.unwrap_err());
};
}
} else{
return Err(Errors::LineParseError{ line_number: index + 1 });
}
}
else{
return Err(Errors::IoError(line.err().unwrap()));
}
}
Ok(dungeon)
}
pub fn find_path(&self, start_room_name: &str, end_room_name: &str) -> Result<Option<Vec<&Room>>, Errors> {
let mut visited: HashMap<String, bool> = HashMap::new();
let mut queue: VecDeque<&Room> = VecDeque::new();
let mut parents: HashMap<String, String> = HashMap::new();
let mut path: Vec<&Room> = Vec::new();
if let Err(error) = self.get_room(start_room_name){
return Err(error)
};
if let Err(error) = self.get_room(end_room_name){
return Err(error)
};
//mark all unvisited
for key in self.map.iter() {
visited.insert(key.0.clone(), false);
}
queue.push_back(self.get_room(start_room_name).unwrap());
*visited.get_mut(start_room_name).unwrap() = true;
if start_room_name == end_room_name {
path.push(queue.pop_front().unwrap());
return Ok(Some(path))
}
else{
while !queue.is_empty(){
let current_room: &Room = queue.pop_back().unwrap().clone();
if current_room.name == self.get_room(end_room_name).unwrap().name{
break;
}
for next in current_room.directions.iter(){
if !next.1.is_empty(){
if visited[next.1] == false{
parents.insert(next.1.clone(), current_room.name.clone());
*visited.get_mut(next.1).unwrap() = true;
queue.push_back(self.get_room(next.1).unwrap());
}
}
}
}
if !parents.contains_key(end_room_name) { return Ok(None); }
let end = self.get_room(end_room_name);
if end.is_err() {
return Err(end.err().unwrap());
}
path.push(end.unwrap());
let mut current_room = parents.get(end_room_name).unwrap();
while parents.contains_key(current_room){
let parent: &String = parents.get(current_room).unwrap();
let parent_as_room= self.get_room(parent);
if parent_as_room.is_err(){
return Err(parent_as_room.err().unwrap());
}
path.push(parent_as_room.unwrap());
current_room = parents.get(current_room).unwrap();
}
path.reverse();
Ok(Some(path))
}
}
}
/*
const TEST_INPUT: &str = "
## Rooms
- Entrance
- Hallway
## Links
- Entrance -> East -> Hallway
";
const TEST_INPUT_2: &str = "hello";
///raboti ako e mahnat purviq red
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_for_errors() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Hallway").unwrap();
dungeon.set_link("Entrance", Direction::East, "Hallway").unwrap();
assert!(dungeon.get_next_room("Club33", Direction::South).is_err());
assert!(dungeon.get_room("Club33").is_err());
}
#[test]
fn test_basic_2() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Hallway").unwrap();
dungeon.set_link("Entrance", Direction::East, "Hallway").unwrap();
assert!(dungeon.get_next_room("Entrance", Direction::South).unwrap().is_none());
assert_eq!(dungeon.get_room("Entrance").unwrap().name, "Entrance");
assert_eq!(dungeon.get_next_room("Entrance", Direction::East).unwrap().unwrap().name, "Hallway");
}
#[test]
fn test_basic_3() {
let dungeon = Dungeon::from_reader(TEST_INPUT.trim().as_bytes()).unwrap();
assert_eq!(dungeon.get_room("Entrance").unwrap().name, "Entrance");
assert_eq!(dungeon.get_room("Hallway").unwrap().name, "Hallway");
assert_eq!(dungeon.get_next_room("Entrance", Direction::East).unwrap().unwrap().name, "Hallway");
}
#[test]
fn test_basic_5() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Treasure Room").unwrap();
dungeon.add_room("Obshtaka").unwrap();
dungeon.add_room("Fitness").unwrap();
dungeon.set_link("Entrance", Direction::West, "Treasure Room").unwrap();
dungeon.set_link("Treasure Room", Direction::South, "Obshtaka").unwrap();
dungeon.set_link("Obshtaka", Direction::East, "Fitness").unwrap();
let path = dungeon.find_path("Entrance", "Fitness").unwrap().unwrap();
assert!(path.len() > 0);
}
#[test]
fn test_basic_6() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Treasure Room").unwrap();
dungeon.add_room("Obshtaka").unwrap();
dungeon.add_room("Club33").unwrap();
dungeon.add_room("Fitness").unwrap();
dungeon.set_link("Entrance", Direction::West, "Treasure Room").unwrap();
dungeon.set_link("Treasure Room", Direction::South, "Obshtaka").unwrap();
dungeon.set_link("Obshtaka", Direction::East, "Fitness").unwrap();
dungeon.set_link("Entrance", Direction::East, "Club33").unwrap();
let path = dungeon.find_path("Fitness", "Club33").unwrap().unwrap();
assert!(path.len() > 0);
}
}
*/
Надежда качи решение на 11.01.2022 01:18 (преди над 3 години)
#![allow(non_snake_case)]
#![allow(dead_code)]
use std::collections::HashMap;
use std::collections::VecDeque;
use std::io;
use std::io::prelude::*;
use std::fs::File;
#[derive(Debug)]
pub enum Errors {
DuplicateRoom(String),
UnknownRoom(String),
IoError(std::io::Error),
LineParseError { line_number: usize },
DirectionParseError(String),
}
#[derive(Clone, Copy,Hash,Eq)]
#[derive(PartialEq)]
pub enum Direction {
North,
South,
East,
West,
}
pub struct Room {
pub name: String,
pub directions: HashMap<Direction,String>
}
pub struct Dungeon {
map: HashMap<String,Room>,
}
impl Direction
{
pub fn getOppositeDirection(direction: Direction) -> Direction
{
match direction
{
Direction::North => Direction::South,
Direction::South => Direction::North,
Direction::East => Direction::West,
Direction::West => Direction::East
}
}
pub fn getDataFromString(str: &str) -> Option<Direction>
{
match str
{
"North" => Some(Direction::North),
"South" => Some(Direction::South),
"East" => Some(Direction::East),
"West" => Some(Direction::West),
_ => None
}
}
}
impl Dungeon {
pub fn new() -> Self {
Dungeon {
map: HashMap::new(),
}
}
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
if !self.map.contains_key(name){
let room: Room = Room{
name: name.to_string(),
directions: HashMap::new() ,
};
self.map.insert(name.to_string(), room);
Ok(())
}
else{
Err(Errors::DuplicateRoom(name.to_string()))
}
}
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
match self.map.contains_key(room_name){
true => return Ok(self.map.get(room_name).unwrap()),
false => return Err(Errors::UnknownRoom(room_name.to_string())),
};
}
pub fn set_link(&mut self,room_name: &str,direction: Direction, other_room_name: &str) -> Result<(), Errors> {
if self.map.contains_key(room_name){
if self.map.contains_key(other_room_name){
let opposite_direction: Direction = Direction::getOppositeDirection(direction);
self.map.get_mut(room_name).unwrap().directions.insert(direction,other_room_name.to_string());
self.map.get_mut(other_room_name).unwrap().directions.insert(opposite_direction,room_name.to_string());
Ok(())
}else{
Err(Errors::UnknownRoom(other_room_name.to_string()))
}
}
else{
Err(Errors::UnknownRoom(room_name.to_string()))
}
}
pub fn get_next_room(&self, room_name: &str, direction: Direction) -> Result<Option<&Room>, Errors> {
if self.map.contains_key(room_name){
if self.map.get(room_name).unwrap().directions.contains_key(&direction){
let room: &String = self.map.get(room_name).unwrap().directions.get(&direction).unwrap();
let next_room: &Room = self.map.get(room).unwrap();
Ok(Some(next_room))
}
else{
Ok(None)
}
}
else{
Err(Errors::UnknownRoom(room_name.to_string()))
}
}
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
//save somewhere the line numbers
let mut dungeon: Dungeon = Dungeon::new();
let mut buffer = String::new();
let mut reader = reader;
if reader.read_line(&mut buffer).unwrap() == 0{
return Err(Errors::LineParseError{ line_number: 0});
}
let mut empty_line = 0;
for (index, line) in reader.lines().enumerate(){
if !line.is_err(){
let mut line = line.unwrap();
if line.as_str().chars().next() == Some('#'){
match line.as_str(){
"## Rooms"=> continue,
"## Links" => continue,
_ => return Err(Errors::LineParseError{ line_number: index + 1 }),
}
}
else if line.is_empty(){
empty_line = empty_line + 1;
if empty_line > 1{
return Err(Errors::LineParseError{ line_number: index + 1 })
}
}
else if line.starts_with("- "){
let room = line.split_off(2);
if room.contains("->"){
let data: Vec<&str> = room.split(" -> ").collect();
let direction: Option<Direction> = Direction::getDataFromString(data[1]);
if direction.is_none(){
return Err(Errors::DirectionParseError(String::from(data[1])));
}
if let Err(error) = dungeon.set_link(data[0], direction.unwrap(), data[2]){
return Err(error);
}
}
else{
let x = dungeon.add_room(room.as_str());
if x.is_err() {
return Err(x.unwrap_err());
};
}
} else{
return Err(Errors::LineParseError{ line_number: index + 1 });
}
}
else{
return Err(Errors::IoError(line.err().unwrap()));
}
}
Ok(dungeon)
}
pub fn find_path(&self, start_room_name: &str, end_room_name: &str) -> Result<Option<Vec<&Room>>, Errors> {
let mut visited: HashMap<String, bool> = HashMap::new();
let mut queue: VecDeque<&Room> = VecDeque::new();
let mut parents: HashMap<String, String> = HashMap::new();
let mut path: Vec<&Room> = Vec::new();
if let Err(error) = self.get_room(start_room_name){
return Err(error)
};
if let Err(error) = self.get_room(end_room_name){
return Err(error)
};
//mark all unvisited
for key in self.map.iter() {
visited.insert(key.0.clone(), false);
}
queue.push_back(self.get_room(start_room_name).unwrap());
*visited.get_mut(start_room_name).unwrap() = true;
if start_room_name == end_room_name {
path.push(queue.pop_front().unwrap());
return Ok(Some(path))
}
else{
while !queue.is_empty(){
let current_room: &Room = queue.pop_back().unwrap().clone();
if current_room.name == self.get_room(end_room_name).unwrap().name{
break;
}
for next in current_room.directions.iter(){
if !next.1.is_empty(){
if visited[next.1] == false{
parents.insert(next.1.clone(), current_room.name.clone());
*visited.get_mut(next.1).unwrap() = true;
queue.push_back(self.get_room(next.1).unwrap());
}
}
}
}
if !parents.contains_key(end_room_name) { return Ok(None); }
let end = self.get_room(end_room_name);
if end.is_err() {
return Err(end.err().unwrap());
}
- path.push(end.unwrap());
+ path.push(end.unwrap());
let mut current_room = parents.get(end_room_name).unwrap();
-
+ path.push(self.get_room(current_room).unwrap());
while parents.contains_key(current_room){
let parent: &String = parents.get(current_room).unwrap();
let parent_as_room= self.get_room(parent);
if parent_as_room.is_err(){
return Err(parent_as_room.err().unwrap());
}
path.push(parent_as_room.unwrap());
current_room = parents.get(current_room).unwrap();
}
path.reverse();
Ok(Some(path))
}
}
}
/*
const TEST_INPUT: &str = "
## Rooms
- Entrance
- Hallway
## Links
- Entrance -> East -> Hallway
";
const TEST_INPUT_2: &str = "hello";
///raboti ako e mahnat purviq red
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_for_errors() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Hallway").unwrap();
dungeon.set_link("Entrance", Direction::East, "Hallway").unwrap();
assert!(dungeon.get_next_room("Club33", Direction::South).is_err());
assert!(dungeon.get_room("Club33").is_err());
}
#[test]
fn test_basic_2() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Hallway").unwrap();
dungeon.set_link("Entrance", Direction::East, "Hallway").unwrap();
assert!(dungeon.get_next_room("Entrance", Direction::South).unwrap().is_none());
assert_eq!(dungeon.get_room("Entrance").unwrap().name, "Entrance");
assert_eq!(dungeon.get_next_room("Entrance", Direction::East).unwrap().unwrap().name, "Hallway");
}
#[test]
fn test_basic_3() {
let dungeon = Dungeon::from_reader(TEST_INPUT.trim().as_bytes()).unwrap();
assert_eq!(dungeon.get_room("Entrance").unwrap().name, "Entrance");
assert_eq!(dungeon.get_room("Hallway").unwrap().name, "Hallway");
assert_eq!(dungeon.get_next_room("Entrance", Direction::East).unwrap().unwrap().name, "Hallway");
}
#[test]
fn test_basic_5() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Treasure Room").unwrap();
dungeon.add_room("Obshtaka").unwrap();
dungeon.add_room("Fitness").unwrap();
dungeon.set_link("Entrance", Direction::West, "Treasure Room").unwrap();
dungeon.set_link("Treasure Room", Direction::South, "Obshtaka").unwrap();
dungeon.set_link("Obshtaka", Direction::East, "Fitness").unwrap();
let path = dungeon.find_path("Entrance", "Fitness").unwrap().unwrap();
assert!(path.len() > 0);
}
#[test]
fn test_basic_6() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Treasure Room").unwrap();
dungeon.add_room("Obshtaka").unwrap();
dungeon.add_room("Club33").unwrap();
dungeon.add_room("Fitness").unwrap();
dungeon.set_link("Entrance", Direction::West, "Treasure Room").unwrap();
dungeon.set_link("Treasure Room", Direction::South, "Obshtaka").unwrap();
dungeon.set_link("Obshtaka", Direction::East, "Fitness").unwrap();
dungeon.set_link("Entrance", Direction::East, "Club33").unwrap();
let path = dungeon.find_path("Fitness", "Club33").unwrap().unwrap();
assert!(path.len() > 0);
}
}
*/