Решение на Dungeons and Compilers от Мирослав Дионисиев
Към профила на Мирослав Дионисиев
Резултати
- 19 точки от тестове
- 0 бонус точки
- 19 точки общо
- 14 успешни тест(а)
- 1 неуспешни тест(а)
Код
use std::{collections::HashMap, collections::VecDeque, fmt::Error};
use std::io::{BufRead};
use std::path::Path;
use std::fs::File;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_room_exists() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
let result = dungeon.add_room("Entrance");
let room = String::from("Entance");
assert!(matches!(result.unwrap_err(), Errors::DuplicateRoom(room)));
}
#[test]
fn test_room_not_found() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
let result = dungeon.get_room("Entranc");
let room = String::from("Entanc");
assert!(matches!(result.unwrap_err(), Errors::UnknownRoom(room)));
}
#[test]
fn test_set_link_to_room_not_found() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
let result = dungeon.set_link("Entrance", Direction::North, "Hallway");
let room = String::from("Hallway");
assert!(matches!(result.unwrap_err(), Errors::UnknownRoom(room)));
}
#[test]
fn test_from_reader() {
const INPUT_1: &str = "
# Rooms
- Entrance
- Hallway
## Links
- Entrance -> East -> Hallway
";
const INPUT_2: &str = "
## Rooms
- Entrance
- Hallway
## Links
- Entrance -> East -> Hallway
";
const INPUT_3: &str = "
## Rooms
- Entrance
- Hallway
## Links
- Entrance -> East -> Hallway
";
const INPUT_4: &str = "
## Rooms
- Entrance
- Hallway
## Links
- Entrance -< East -> Hallway
";
const INPUT_5: &str = "
## Rooms
- Entrance
- Entrance
## Links
- Entrance -> East -> Hallway
";
let dungeon = Dungeon::from_reader(INPUT_1.trim().as_bytes());
assert!(matches!(dungeon.unwrap_err(), Errors::LineParseError{line_number: 1}));
let dungeon = Dungeon::from_reader(INPUT_2.trim().as_bytes());
assert!(matches!(dungeon.unwrap_err(), Errors::LineParseError{line_number: 3}));
let dungeon = Dungeon::from_reader(INPUT_3.trim().as_bytes());
assert!(matches!(dungeon.unwrap_err(), Errors::LineParseError{line_number: 5}));
let dungeon = Dungeon::from_reader(INPUT_4.trim().as_bytes());
assert!(matches!(dungeon.unwrap_err(), Errors::LineParseError{line_number: 6}));
let dungeon = Dungeon::from_reader(INPUT_5.trim().as_bytes());
let room = String::from("Entance");
assert!(matches!(dungeon.unwrap_err(), Errors::DuplicateRoom(room)));
}
#[test]
fn test_get_path() {
const TEST_INPUT_1: &str = "
## Rooms
- R1
- R2
- R3
- R4
## Links
- R1 -> East -> R2
- R1 -> West -> R3
- R3 -> East -> R4
";
let dungeon = Dungeon::from_reader(TEST_INPUT_1.trim().as_bytes()).unwrap();
let path = dungeon.find_path("R1", "R4");
assert_eq!(path.unwrap().unwrap().len(), 3);
}
}
#[derive(Debug)]
pub enum Errors {
DuplicateRoom(String),
UnknownRoom(String),
IoError(std::io::Error),
LineParseError { line_number: usize },
DirectionParseError(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Direction {
North,
South,
East,
West,
}
#[derive(Debug)]
pub struct Room {
pub name: String,
}
#[derive(Debug)]
pub struct Dungeon {
pub rooms: HashMap<String, Room>,
pub connections: HashMap<(String, Direction), String>,
}
impl Dungeon {
pub fn new() -> Self {
Dungeon
{
rooms: HashMap::new(),
connections: HashMap::new()
}
}
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
if self.rooms.contains_key(&name.to_owned()) == false
{
self.rooms.insert(name.to_owned(), Room{name:name.to_owned()});
return Ok(());
}
Err(Errors::DuplicateRoom(name.to_owned()))
}
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
match self.rooms.get(&room_name.to_owned())
{
Some(v) => Ok(v),
None => Err(Errors::UnknownRoom(room_name.to_owned())),
}
}
pub fn set_link(
&mut self,
room_name: &str,
direction: Direction,
other_room_name: &str,
) -> Result<(), Errors> {
let oppositeDirection = get_opposite_direction(direction);
let mut roomF = self.get_room(room_name);
let mut roomS = self.get_room(other_room_name);
match roomF
{
Ok(r1) => {
match roomS
{
Ok(r2) => {
self.connections.insert((room_name.to_owned(), direction), other_room_name.to_owned());
self.connections.insert((other_room_name.to_owned(), oppositeDirection), room_name.to_owned());
Ok(())
},
Err(f2) => Err(Errors::UnknownRoom(other_room_name.to_owned())),
}
},
Err(f1) => Err(Errors::UnknownRoom(room_name.to_owned())),
}
}
pub fn get_next_room(&self, room_name: &str, direction: Direction) -> Result<Option<&Room>, Errors> {
let mut room = self.get_room(room_name);
match room
{
Ok(r) => {
match self.connections.get(&(room_name.to_owned(), direction))
{
// if there is a connection between rooms then we can safeky unwrap the Result?
Some(name) => Ok(Some(self.get_room(name).unwrap())),
None => Ok(None),
}
},
Err(f) => Err(Errors::UnknownRoom(room_name.to_owned())),
}
}
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
let mut dungeon = Dungeon::new();
let mut counter:usize = 0;
let mut isRoomsOver:bool = false;
let mut isLinks:bool = false;
for line in reader.lines()
{
counter = counter+1;
match line
{
Ok(mut l) =>
{
l = l.trim().to_string();
if counter == 1 && l.eq("## Rooms") == false
{
return Err(Errors::LineParseError{line_number:counter});
}
else if counter == 1 && l.eq("## Rooms") == true
{
continue;
}
if isRoomsOver == false && isLinks == false && l.eq("") == false
{
if l.starts_with("- ")
{
let mut newRoom = l.replace("- ", "");
newRoom = newRoom.trim().to_string();
if newRoom.eq("") == false
{
match dungeon.add_room(&newRoom)
{
Ok(()) => {continue;},
Err(f) => {return Err(f);},
}
}
else
{
return Err(Errors::LineParseError{line_number:counter});
}
}
else
{
return Err(Errors::LineParseError{line_number:counter});
}
}
if l.eq("") == true && isRoomsOver == false
{
isRoomsOver = true;
continue;
}
else if l.eq("") == true && isRoomsOver == true
{
return Err(Errors::LineParseError{line_number:counter});
}
if isLinks == false && isRoomsOver == true && counter > 1 && l.eq("## Links") == false
{
return Err(Errors::LineParseError{line_number:counter});
}
else if isLinks == false && isRoomsOver == true && counter > 1 && l.eq("## Links") == true
{
isLinks = true;
continue;
}
if isLinks == true
{
if l.starts_with("- ")
{
let mut path = l.replace("- ", "");
path = path.trim().to_string();
let directions = path.split_terminator("->").map(|s| s.trim()).collect::<Vec<&str>>();
if directions.len() == 3 && directions[0].eq("") == false && directions[1].eq("") == false && directions[2].eq("") == false
{
match get_direction(directions[1])
{
Some(val) =>
{
match dungeon.set_link(directions[0], val, directions[2])
{
Ok(()) => {continue;},
Err(f) => {return Err(f);},
}
}
None => {return Err(Errors::DirectionParseError(directions[1].to_owned()));}
}
}
else
{
return Err(Errors::LineParseError{line_number:counter});
}
}
else
{
return Err(Errors::LineParseError{line_number:counter});
}
}
},
Err(f) => {return Err(Errors::IoError(f));},
}
}
match counter
{
0 => Err(Errors::LineParseError{line_number:counter}),
_ => Ok(dungeon),
}
}
pub fn find_path(
&self,
start_room_name: &str,
end_room_name: &str
) -> Result<Option<Vec<&Room>>, Errors> {
let mut counter = 0;
match self.get_room(start_room_name)
{
Ok(v) => counter = counter + 1,
Err(f) => {return Err(f);},
}
match self.get_room(end_room_name)
{
Ok(v) => counter = counter + 1,
Err(f) => {return Err(f);},
}
let mut visited:HashMap<String, bool> = HashMap::new();
let mut parents:HashMap<String, &Room> = HashMap::new();
let mut path:Vec<&Room> = Vec::new();
let mut q:VecDeque<String> = VecDeque::new();
let mut isFound = false;
for room in &self.rooms
{
visited.insert(room.0.to_owned(), false);
}
q.push_back(start_room_name.to_owned());
while q.is_empty() == false
{
let room = q.pop_front();
visited.insert(room.to_owned().unwrap(), true);
if room.to_owned().unwrap().eq(end_room_name) == true
{
isFound = true;
break;
}
match self.get_next_room(&room.to_owned().unwrap(), Direction::North).unwrap()
{
Some(v) =>
{
if *visited.get(&v.name).unwrap() == false
{
parents.insert(v.name.to_owned(), self.get_room(&room.to_owned().unwrap()).unwrap());
q.push_back(v.name.to_owned());
}
},
None => {counter = counter + 1;},
}
match self.get_next_room(&room.to_owned().unwrap(), Direction::East).unwrap()
{
Some(v) =>
{
if *visited.get(&v.name).unwrap() == false
{
parents.insert(v.name.to_owned(), self.get_room(&room.to_owned().unwrap()).unwrap());
q.push_back(v.name.to_owned());
}
},
None => {counter = counter + 1;},
}
match self.get_next_room(&room.to_owned().unwrap(), Direction::South).unwrap()
{
Some(v) =>
{
if *visited.get(&v.name).unwrap() == false
{
parents.insert(v.name.to_owned(), self.get_room(&room.to_owned().unwrap()).unwrap());
q.push_back(v.name.to_owned());
}
},
None => {counter = counter + 1;},
}
match self.get_next_room(&room.to_owned().unwrap(), Direction::West).unwrap()
{
Some(v) =>
{
if *visited.get(&v.name).unwrap() == false
{
parents.insert(v.name.to_owned(), self.get_room(&room.to_owned().unwrap()).unwrap());
q.push_back(v.name.to_owned());
}
},
None => {counter = counter + 1;},
}
}
match isFound
{
true =>
{
let mut currentRoom = end_room_name;
path.push(self.get_room(currentRoom).unwrap());
while let room = *parents.get(¤tRoom.to_owned()).unwrap()
{
path.push(room);
currentRoom = &room.name;
if currentRoom.eq(start_room_name)
{
break;
}
}
path.reverse();
Ok(Some(path))
},
false => Ok(None),
}
}
}
pub fn get_opposite_direction(direction: Direction) -> Direction
{
match direction
{
Direction::East => Direction::West,
Direction::West => Direction::East,
Direction::North => Direction::South,
Direction::South => Direction::North,
}
}
pub fn get_direction(direction: &str) -> Option<Direction>
{
match direction.to_lowercase().as_str()
{
"north" => Some(Direction::North),
"south" => Some(Direction::South),
"west" => Some(Direction::West),
"east" => Some(Direction::East),
_ => None,
}
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20220116-3533338-fw621u/solution) warning: unused import: `fmt::Error` --> src/lib.rs:1:56 | 1 | use std::{collections::HashMap, collections::VecDeque, fmt::Error}; | ^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default warning: unused import: `std::path::Path` --> src/lib.rs:3:5 | 3 | use std::path::Path; | ^^^^^^^^^^^^^^^ warning: unused import: `std::fs::File` --> src/lib.rs:4:5 | 4 | use std::fs::File; | ^^^^^^^^^^^^^ warning: irrefutable `while let` pattern --> src/lib.rs:431:23 | 431 | while let room = *parents.get(¤tRoom.to_owned()).unwrap() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(irrefutable_let_patterns)]` on by default = note: this pattern will always match, so the loop will never exit = help: consider instead using a `loop { ... }` with a `let` inside it warning: unused variable: `r1` --> src/lib.rs:193:16 | 193 | Ok(r1) => { | ^^ help: if this is intentional, prefix it with an underscore: `_r1` | = note: `#[warn(unused_variables)]` on by default warning: unused variable: `r2` --> src/lib.rs:196:24 | 196 | Ok(r2) => { | ^^ help: if this is intentional, prefix it with an underscore: `_r2` warning: unused variable: `f2` --> src/lib.rs:201:25 | 201 | Err(f2) => Err(Errors::UnknownRoom(other_room_name.to_owned())), | ^^ help: if this is intentional, prefix it with an underscore: `_f2` warning: unused variable: `f1` --> src/lib.rs:204:17 | 204 | Err(f1) => Err(Errors::UnknownRoom(room_name.to_owned())), | ^^ help: if this is intentional, prefix it with an underscore: `_f1` warning: unused variable: `r` --> src/lib.rs:212:16 | 212 | Ok(r) => { | ^ help: if this is intentional, prefix it with an underscore: `_r` warning: unused variable: `f` --> src/lib.rs:220:17 | 220 | Err(f) => Err(Errors::UnknownRoom(room_name.to_owned())), | ^ help: if this is intentional, prefix it with an underscore: `_f` warning: unused variable: `v` --> src/lib.rs:344:16 | 344 | Ok(v) => counter = counter + 1, | ^ help: if this is intentional, prefix it with an underscore: `_v` warning: unused variable: `v` --> src/lib.rs:349:16 | 349 | Ok(v) => counter = counter + 1, | ^ help: if this is intentional, prefix it with an underscore: `_v` warning: variable does not need to be mutable --> src/lib.rs:189:13 | 189 | let mut roomF = self.get_room(room_name); | ----^^^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` on by default warning: variable does not need to be mutable --> src/lib.rs:190:13 | 190 | let mut roomS = self.get_room(other_room_name); | ----^^^^^ | | | help: remove this `mut` warning: variable does not need to be mutable --> src/lib.rs:209:13 | 209 | let mut room = self.get_room(room_name); | ----^^^^ | | | help: remove this `mut` warning: variable `oppositeDirection` should have a snake case name --> src/lib.rs:188:13 | 188 | let oppositeDirection = get_opposite_direction(direction); | ^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `opposite_direction` | = note: `#[warn(non_snake_case)]` on by default warning: variable `roomF` should have a snake case name --> src/lib.rs:189:17 | 189 | let mut roomF = self.get_room(room_name); | ^^^^^ help: convert the identifier to snake case: `room_f` warning: variable `roomS` should have a snake case name --> src/lib.rs:190:17 | 190 | let mut roomS = self.get_room(other_room_name); | ^^^^^ help: convert the identifier to snake case: `room_s` warning: variable `isRoomsOver` should have a snake case name --> src/lib.rs:227:17 | 227 | let mut isRoomsOver:bool = false; | ^^^^^^^^^^^ help: convert the identifier to snake case: `is_rooms_over` warning: variable `isLinks` should have a snake case name --> src/lib.rs:228:17 | 228 | let mut isLinks:bool = false; | ^^^^^^^ help: convert the identifier to snake case: `is_links` warning: variable `newRoom` should have a snake case name --> src/lib.rs:250:37 | 250 | ... let mut newRoom = l.replace("- ", ""); | ^^^^^^^ help: convert the identifier to snake case: `new_room` warning: variable `isFound` should have a snake case name --> src/lib.rs:357:17 | 357 | let mut isFound = false; | ^^^^^^^ help: convert the identifier to snake case: `is_found` warning: variable `currentRoom` should have a snake case name --> src/lib.rs:429:25 | 429 | let mut currentRoom = end_room_name; | ^^^^^^^^^^^ help: convert the identifier to snake case: `current_room` warning: `solution` (lib) generated 23 warnings Finished test [unoptimized + debuginfo] target(s) in 3.78s 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 ... FAILED test solution_test::test_finding_an_indirect_path ... ok test solution_test::test_finding_no_path ... ok test solution_test::test_invalid_parsing ... ok test solution_test::test_io_error ... ok 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_finding_a_reflexive_path stdout ---- thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/lib.rs:431:72 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:354:5 failures: solution_test::test_finding_a_reflexive_path test result: FAILED. 14 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s error: test failed, to rerun pass '--test solution_test'
История (2 версии и 0 коментара)
Мирослав качи решение на 09.01.2022 00:31 (преди почти 4 години)
use std::{collections::HashMap, collections::VecDeque, fmt::Error};
use std::io::{BufRead};
use std::path::Path;
use std::fs::File;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_room_exists() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
let result = dungeon.add_room("Entrance");
let room = String::from("Entance");
assert!(matches!(result.unwrap_err(), Errors::DuplicateRoom(room)));
}
#[test]
fn test_room_not_found() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
let result = dungeon.get_room("Entranc");
let room = String::from("Entanc");
assert!(matches!(result.unwrap_err(), Errors::UnknownRoom(room)));
}
#[test]
fn test_set_link_to_room_not_found() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
let result = dungeon.set_link("Entrance", Direction::North, "Hallway");
let room = String::from("Hallway");
assert!(matches!(result.unwrap_err(), Errors::UnknownRoom(room)));
}
#[test]
fn test_from_reader() {
const INPUT_1: &str = "
# Rooms
- Entrance
- Hallway
## Links
- Entrance -> East -> Hallway
";
const INPUT_2: &str = "
## Rooms
- Entrance
- Hallway
## Links
- Entrance -> East -> Hallway
";
const INPUT_3: &str = "
## Rooms
- Entrance
- Hallway
## Links
- Entrance -> East -> Hallway
";
const INPUT_4: &str = "
## Rooms
- Entrance
- Hallway
## Links
- Entrance -< East -> Hallway
";
const INPUT_5: &str = "
## Rooms
- Entrance
- Entrance
## Links
- Entrance -> East -> Hallway
";
let dungeon = Dungeon::from_reader(INPUT_1.trim().as_bytes());
assert!(matches!(dungeon.unwrap_err(), Errors::LineParseError{line_number: 1}));
let dungeon = Dungeon::from_reader(INPUT_2.trim().as_bytes());
assert!(matches!(dungeon.unwrap_err(), Errors::LineParseError{line_number: 3}));
let dungeon = Dungeon::from_reader(INPUT_3.trim().as_bytes());
assert!(matches!(dungeon.unwrap_err(), Errors::LineParseError{line_number: 5}));
let dungeon = Dungeon::from_reader(INPUT_4.trim().as_bytes());
assert!(matches!(dungeon.unwrap_err(), Errors::LineParseError{line_number: 6}));
let dungeon = Dungeon::from_reader(INPUT_5.trim().as_bytes());
let room = String::from("Entance");
assert!(matches!(dungeon.unwrap_err(), Errors::DuplicateRoom(room)));
}
#[test]
fn test_get_path() {
const TEST_INPUT_1: &str = "
## Rooms
- R1
- R2
- R3
- R4
## Links
- R1 -> East -> R2
- R1 -> West -> R3
- R3 -> East -> R4
";
let dungeon = Dungeon::from_reader(TEST_INPUT_1.trim().as_bytes()).unwrap();
let path = dungeon.find_path("R1", "R4");
assert_eq!(path.unwrap().unwrap().len(), 3);
}
}
#[derive(Debug)]
pub enum Errors {
DuplicateRoom(String),
UnknownRoom(String),
IoError(std::io::Error),
LineParseError { line_number: usize },
DirectionParseError(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Direction {
North,
South,
East,
West,
}
#[derive(Debug)]
pub struct Room {
pub name: String,
}
#[derive(Debug)]
pub struct Dungeon {
pub rooms: HashMap<String, Room>,
pub connections: HashMap<(String, Direction), String>,
}
impl Dungeon {
pub fn new() -> Self {
Dungeon
{
rooms: HashMap::new(),
connections: HashMap::new()
}
}
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
if self.rooms.contains_key(&name.to_owned()) == false
{
self.rooms.insert(name.to_owned(), Room{name:name.to_owned()});
return Ok(());
}
Err(Errors::DuplicateRoom(name.to_owned()))
}
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
match self.rooms.get(&room_name.to_owned())
{
Some(v) => Ok(v),
None => Err(Errors::UnknownRoom(room_name.to_owned())),
}
}
pub fn set_link(
&mut self,
room_name: &str,
direction: Direction,
other_room_name: &str,
) -> Result<(), Errors> {
let oppositeDirection = get_opposite_direction(direction);
let mut roomF = self.get_room(room_name);
let mut roomS = self.get_room(other_room_name);
match roomF
{
Ok(r1) => {
match roomS
{
Ok(r2) => {
self.connections.insert((room_name.to_owned(), direction), other_room_name.to_owned());
self.connections.insert((other_room_name.to_owned(), oppositeDirection), room_name.to_owned());
Ok(())
},
Err(f2) => Err(Errors::UnknownRoom(other_room_name.to_owned())),
}
},
Err(f1) => Err(Errors::UnknownRoom(room_name.to_owned())),
}
}
pub fn get_next_room(&self, room_name: &str, direction: Direction) -> Result<Option<&Room>, Errors> {
let mut room = self.get_room(room_name);
match room
{
Ok(r) => {
match self.connections.get(&(room_name.to_owned(), direction))
{
// if there is a connection between rooms then we can safeky unwrap the Result?
Some(name) => Ok(Some(self.get_room(name).unwrap())),
None => Ok(None),
}
},
Err(f) => Err(Errors::UnknownRoom(room_name.to_owned())),
}
}
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
let mut dungeon = Dungeon::new();
let mut counter:usize = 0;
let mut isRoomsOver:bool = false;
let mut isLinks:bool = false;
for line in reader.lines()
{
counter = counter+1;
match line
{
Ok(mut l) =>
{
l = l.trim().to_string();
if counter == 1 && l.eq("## Rooms") == false
{
return Err(Errors::LineParseError{line_number:counter});
}
else if counter == 1 && l.eq("## Rooms") == true
{
continue;
}
if isRoomsOver == false && isLinks == false && l.eq("") == false
{
if l.starts_with("- ")
{
let mut newRoom = l.replace("- ", "");
newRoom = newRoom.trim().to_string();
if newRoom.eq("") == false
{
match dungeon.add_room(&newRoom)
{
Ok(()) => {continue;},
Err(f) => {return Err(f);},
}
}
else
{
return Err(Errors::LineParseError{line_number:counter});
}
}
else
{
return Err(Errors::LineParseError{line_number:counter});
}
}
if l.eq("") == true && isRoomsOver == false
{
isRoomsOver = true;
continue;
}
else if l.eq("") == true && isRoomsOver == true
{
return Err(Errors::LineParseError{line_number:counter});
}
if isLinks == false && isRoomsOver == true && counter > 1 && l.eq("## Links") == false
{
return Err(Errors::LineParseError{line_number:counter});
}
else if isLinks == false && isRoomsOver == true && counter > 1 && l.eq("## Links") == true
{
isLinks = true;
continue;
}
if isLinks == true
{
if l.starts_with("- ")
{
let mut path = l.replace("- ", "");
path = path.trim().to_string();
let directions = path.split_terminator("->").map(|s| s.trim()).collect::<Vec<&str>>();
if directions.len() == 3 && directions[0].eq("") == false && directions[1].eq("") == false && directions[2].eq("") == false
{
match get_direction(directions[1])
{
Some(val) =>
{
match dungeon.set_link(directions[0], val, directions[2])
{
Ok(()) => {continue;},
Err(f) => {return Err(f);},
}
}
None => {return Err(Errors::DirectionParseError(directions[1].to_owned()));}
}
}
else
{
return Err(Errors::LineParseError{line_number:counter});
}
}
else
{
return Err(Errors::LineParseError{line_number:counter});
}
}
},
Err(f) => {return Err(Errors::IoError(f));},
}
}
match counter
{
0 => Err(Errors::LineParseError{line_number:counter}),
_ => Ok(dungeon),
}
}
pub fn find_path(
&self,
start_room_name: &str,
end_room_name: &str
) -> Result<Option<Vec<&Room>>, Errors> {
let mut counter = 0;
match self.get_room(start_room_name)
{
Ok(v) => counter = counter + 1,
Err(f) => {return Err(f);},
}
match self.get_room(end_room_name)
{
Ok(v) => counter = counter + 1,
Err(f) => {return Err(f);},
}
let mut visited:HashMap<String, bool> = HashMap::new();
let mut parents:HashMap<String, &Room> = HashMap::new();
let mut path:Vec<&Room> = Vec::new();
let mut q:VecDeque<String> = VecDeque::new();
let mut isFound = false;
for room in &self.rooms
{
visited.insert(room.0.to_owned(), false);
}
q.push_back(start_room_name.to_owned());
while q.is_empty() == false
{
let room = q.pop_front();
visited.insert(room.to_owned().unwrap(), true);
if room.to_owned().unwrap().eq(end_room_name) == true
{
isFound = true;
break;
}
match self.get_next_room(&room.to_owned().unwrap(), Direction::North).unwrap()
{
Some(v) =>
{
if *visited.get(&v.name).unwrap() == false
{
parents.insert(v.name.to_owned(), self.get_room(&room.to_owned().unwrap()).unwrap());
q.push_back(v.name.to_owned());
}
},
None => {counter = counter + 1;},
}
match self.get_next_room(&room.to_owned().unwrap(), Direction::East).unwrap()
{
Some(v) =>
{
if *visited.get(&v.name).unwrap() == false
{
parents.insert(v.name.to_owned(), self.get_room(&room.to_owned().unwrap()).unwrap());
q.push_back(v.name.to_owned());
}
},
None => {counter = counter + 1;},
}
match self.get_next_room(&room.to_owned().unwrap(), Direction::South).unwrap()
{
Some(v) =>
{
if *visited.get(&v.name).unwrap() == false
{
parents.insert(v.name.to_owned(), self.get_room(&room.to_owned().unwrap()).unwrap());
q.push_back(v.name.to_owned());
}
},
None => {counter = counter + 1;},
}
match self.get_next_room(&room.to_owned().unwrap(), Direction::West).unwrap()
{
Some(v) =>
{
if *visited.get(&v.name).unwrap() == false
{
parents.insert(v.name.to_owned(), self.get_room(&room.to_owned().unwrap()).unwrap());
q.push_back(v.name.to_owned());
}
},
None => {counter = counter + 1;},
}
}
match isFound
{
true =>
{
let mut currentRoom = end_room_name;
path.push(self.get_room(currentRoom).unwrap());
while let room = *parents.get(¤tRoom.to_owned()).unwrap()
{
path.push(room);
currentRoom = &room.name;
if currentRoom.eq(start_room_name)
{
break;
}
}
path.reverse();
Ok(Some(path))
},
false => Ok(None),
}
}
}
-fn get_opposite_direction(direction: Direction) -> Direction
+pub fn get_opposite_direction(direction: Direction) -> Direction
{
match direction
{
Direction::East => Direction::West,
Direction::West => Direction::East,
Direction::North => Direction::South,
Direction::South => Direction::North,
}
}
-fn get_direction(direction: &str) -> Option<Direction>
+pub fn get_direction(direction: &str) -> Option<Direction>
{
match direction.to_lowercase().as_str()
{
"north" => Some(Direction::North),
"south" => Some(Direction::South),
"west" => Some(Direction::West),
"east" => Some(Direction::East),
_ => None,
}
}