Решение на 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(&currentRoom.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(&currentRoom.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:24 (преди почти 4 години)

Мирослав качи решение на 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(&currentRoom.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,
}
}