Решение на Dungeons and Compilers от Павел Атанасов
Резултати
- 15 точки от тестове
- 1 бонус точка
- 16 точки общо
- 11 успешни тест(а)
- 4 неуспешни тест(а)
Код
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20220116-3533338-19e8xvs/solution) Finished test [unoptimized + debuginfo] target(s) in 4.23s 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 ... FAILED 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_finding_a_reflexive_path stdout ---- thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:360:71 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 ---- solution_test::test_finding_an_indirect_path stdout ---- thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Timeout', tests/solution_test.rs:320:5 ---- solution_test::test_invalid_parsing stdout ---- thread 'main' panicked at 'assertion failed: matches!(Dungeon :: from_reader(\"\".as_bytes()),\n Err(Errors :: LineParseError { line_number : 0 }))', tests/solution_test.rs:276:5 ---- solution_test::test_io_error stdout ---- thread '<unnamed>' panicked at 'assertion failed: matches!(dungeon, Err(Errors :: IoError(_)))', tests/solution_test.rs:196:9 thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:194:5 failures: solution_test::test_finding_a_reflexive_path solution_test::test_finding_an_indirect_path solution_test::test_invalid_parsing solution_test::test_io_error test result: FAILED. 11 passed; 4 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.01s error: test failed, to rerun pass '--test solution_test'
История (3 версии и 3 коментара)
Павел качи решение на 08.01.2022 16:28 (преди почти 4 години)
use std::collections::{HashMap, HashSet, VecDeque};
use std::io::{BufRead, Error};
use std::str::FromStr;
/// Различните грешки, които ще очакваме да върнете като резултат от някои невалидни операции.
/// Повече детайли по-долу.
///
#[derive(Debug)]
pub enum Errors {
DuplicateRoom(String),
UnknownRoom(String),
IoError(std::io::Error),
LineParseError { line_number: usize },
DirectionParseError(String),
}
/// Четирите посоки, в които може една стая да има съседи. Може да добавите още trait
/// имплементации, за да си улесните живота.
///
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum Direction {
North,
South,
East,
West,
}
impl Direction {
fn rev(&self) -> Self {
match &self {
Direction::North => Direction::South,
Direction::South => Direction::North,
Direction::East => Direction::West,
Direction::West => Direction::East,
}
}
}
impl FromStr for Direction {
type Err = ();
fn from_str(input: &str) -> Result<Direction, Self::Err> {
match input {
"North" => Ok(Direction::North),
"South" => Ok(Direction::South),
"East" => Ok(Direction::East),
"West" => Ok(Direction::West),
_ => Err(()),
}
}
}
/// Една стая в подземията. Дефинира се само с име, макар че в по-интересна имплементация може да
/// държи item-и, противници...
///
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Room {
pub name: String,
}
impl Room {
fn new(name: String) -> Self {
Room {
name,
}
}
}
/// Контейнер за стаите и не само. Ще работим предимно със тази структура.
///
pub struct Dungeon {
pub rooms: HashMap<String, Room>,
pub passages: HashMap<(String, Direction), String>,
}
impl Dungeon {
/// Конструиране на празен Dungeon, в който няма никакви стаи.
///
pub fn new() -> Self {
Dungeon {
rooms: HashMap::new(),
passages: HashMap::new(),
}
}
/// Добавяне на стая към Dungeon с име `name`. Връща `Ok(())` при успех. Ако вече има стая с
/// такова име, очакваме да върнете `Errors::DuplicateRoom` с името.
///
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
let name = String::from(name);
if self.rooms.contains_key(&name) {
return Err(Errors::DuplicateRoom(name.clone()));
}
self.rooms.insert(name.clone(), Room::new(name.clone()));
Ok(())
}
/// Прочитане на дадена стая -- когато извикаме `get_room`, очакваме reference към `Room`
/// структурата с това име.
///
/// Ако няма такава стая, очакваме `Errors::UnknownRoom` с подаденото име.
///
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
let room_name = String::from(room_name);
self.rooms
.get(&room_name)
.ok_or(Errors::UnknownRoom(room_name))
}
/// Четене на съседа на стаята с име `room_name` в посока `direction`. Тук има няколко
/// варианта на изход:
///
/// - Ако подадената стая не съществува, очакваме грешка `Errors::UnknownRoom`
/// - Ако подадената стая няма съсед в тази посока, Ok(None) е смисления резултат
/// - Иначе, чакаме reference към `Room` структурата на въпросния съсед, опакована в `Ok(Some(`.
///
pub fn get_next_room(
&self,
room_name: &str,
direction: Direction,
) -> Result<Option<&Room>, Errors> {
let room_name = String::from(room_name);
let _room = self.get_room(&room_name)?;
Ok(self
.passages
.get(&(room_name, direction))
.map(|room_name| self.get_room(room_name).unwrap()))
}
/// Прочитаме структурата на dungeon от нещо, което имплементира `BufRead`. Това може да е
/// файл, или, ако тестваме, може да е просто колекция от байтове.
///
/// Успешен резултат връща новосъздадения dungeon, пакетиран в `Ok`.
///
/// Вижте по-долу за обяснение на грешките, които очакваме.
///
pub fn set_link(
&mut self,
room_name: &str,
direction: Direction,
other_room_name: &str,
) -> Result<(), Errors> {
let start_room_name = String::from(room_name);
let end_room_name = String::from(other_room_name);
let start_room = self
.rooms
.get(&start_room_name)
- // .map(Rc::as_ref)
.ok_or(Errors::UnknownRoom(start_room_name.clone()))?;
let end_room = self
.rooms
.get(&end_room_name)
- // .map(Rc::as_ref)
.ok_or(Errors::UnknownRoom(end_room_name.clone()))?;
let passages = &mut self.passages;
let direction_1 = direction;
let direction_2 = direction.rev();
let _ = passages.insert(
(start_room.name.clone(), direction_1),
end_room.name.clone(),
);
let _ = passages.insert(
(end_room.name.clone(), direction_2),
start_room.name.clone(),
);
Ok(())
}
/// Добавяне на съсед на дадена стая. След извикването на функцията, очакваме стаята с име
/// `room_name` да има връзка в посока `direction` със стаята с име `other_room_name`.
///
/// Също така очакваме `other_room_name` да има връзка с `room_name` в *обратната* посока.
///
/// Успешен резултат е `Ok(())`. В случай, че която от двете стаи не същестува, очакваме грешка
/// `Errors::UnknownRoom` със съответното име на липсваща стая. Ако и двете липсват, спокойно
/// върнете тази, която проверявате първо.
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
let line_parse_error = |line_num: usize| Errors::LineParseError {
line_number: line_num,
};
let trim_line = |line: String| String::from(line.as_str().trim());
- let map_line_err = |line: Result<String, Error>, line_num: usize| {
+ let map_line_parse_err = |line: Result<String, Error>, line_num: usize| {
line.map_err(|_| line_parse_error(line_num))
};
+ let map_io_err = |line: Result<String, Error>| {
+ line.map_err(|io_error| Errors::IoError(io_error))
+ };
+
let mut lines = reader.lines();
let mut new_dungeon = Dungeon::new();
let mut line_num = 0;
line_num += 1;
- let line = trim_line(map_line_err(
+ let line = trim_line(map_line_parse_err(
lines.next().ok_or(line_parse_error(line_num))?,
line_num,
)?);
- if line != String::from("## Rooms") {
+ if line != "## Rooms" {
return Err(line_parse_error(line_num));
}
// Rooms
while let Some(line) = lines.next() {
line_num += 1;
- let line = trim_line(map_line_err(line, line_num)?);
+ let line = trim_line(map_io_err(line)?);
if line.len() < 3 || line[..2].to_string() != "- " {
if line == "## Links" {
break;
} else {
return Err(line_parse_error(line_num));
}
}
new_dungeon.add_room(&line[2..])?;
}
// Links
while let Some(line) = lines.next() {
line_num += 1;
- let line = trim_line(map_line_err(line, line_num)?);
+ let line = trim_line(map_io_err(line)?);
if line.len() < 3 || line[..2].to_string() != "- " {
return Err(line_parse_error(line_num));
}
let components = line[2..].split(" -> ").collect::<Vec<_>>();
if components.len() != 3 {
return Err(line_parse_error(line_num));
}
if let Ok(direction) = Direction::from_str(components[1]) {
new_dungeon.set_link(components[0], direction, components[2])?;
} else {
return Err(line_parse_error(line_num));
}
}
Ok(new_dungeon)
}
/// Търси път от `start_room_name` до `end_room_name` и го връща във вектор, пакетиран във
/// `Ok(Some(` ако намери.
///
/// Ако няма път между тези две стаи, връща `Ok(None)`.
///
/// Ако четенето на стаи в един момент върне грешка, очакваме да върнете грешката нагоре.
///
pub fn find_path(
&self,
start_room_name: &str,
end_room_name: &str,
) -> Result<Option<Vec<&Room>>, Errors> {
let start_room_name = String::from(start_room_name);
let end_room_name = String::from(end_room_name);
let start_room = self.get_room(&start_room_name)?;
let end_room = self.get_room(&end_room_name)?;
let mut visited: HashSet<String> = HashSet::new();
let mut parents: HashMap<String, String> = HashMap::new();
let mut queue = VecDeque::new();
queue.push_back(start_room);
while let Some(current_room) = queue.pop_front() {
if current_room == end_room {
break;
}
self.passages
.iter()
.filter(|((start_room_name, _), _)| current_room.name == *start_room_name)
.map(|((_, _), end_room)| end_room)
.for_each(|neighbouring_room| {
if visited.insert(neighbouring_room.clone()) {
queue.push_front(self.get_room(&neighbouring_room).unwrap());
parents.insert(neighbouring_room.clone(), current_room.name.clone());
}
})
}
Ok(match parents.get(&end_room.name) {
Some(_) => {
let mut path: VecDeque<&Room> = VecDeque::new();
path.push_front(&end_room);
let mut current_room: &Room = &end_room;
while let Some(parent_room_name) = parents.get(¤t_room.name) {
let parent_room = self.get_room(&parent_room_name)?;
path.push_front(parent_room);
current_room = parent_room;
}
Some(path.into())
}
None => None,
})
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn test_basic_1_two_rooms() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Hallway").unwrap();
dungeon
.set_link("Entrance", Direction::East, "Hallway")
.unwrap();
assert_eq!(dungeon.get_room("Entrance").unwrap().name, "Entrance");
assert_eq!(
dungeon
.get_next_room("Entrance", Direction::East)
.unwrap()
.unwrap()
.name,
"Hallway"
);
}
const TEST_INPUT_1: &'static str = "
## Rooms
- Entrance
- Hallway
## Links
- Entrance -> East -> Hallway
";
Това не е базовия тест -- липсва един ред. Виж го внимателно, виж внимателно и условието.
#[test]
fn test_basic_2_from_reader() {
// .trim() за да премахнем първия и последния ред:
let dungeon = Dungeon::from_reader(TEST_INPUT_1.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_3_find_path() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Treasure Room").unwrap();
dungeon
.set_link("Entrance", Direction::West, "Treasure Room")
.unwrap();
let path = dungeon
.find_path("Entrance", "Treasure Room")
.unwrap()
.unwrap();
assert!(path.len() > 0);
}
const TEST_INPUT_2: &'static str = "
## Rooms
- Entrance
- Hallway
- Stairs
- Restrooms
- 325
- 101
## Links
- Entrance -> West -> Hallway
- Hallway -> East -> Stairs
- Stairs -> South -> 101
- Stairs -> North -> 325
- 325 -> South -> Restrooms
- Restrooms -> West -> Restrooms
";
#[test]
fn test_basic_4_find_path_fmi_success() {
let dungeon = Dungeon::from_reader(TEST_INPUT_2.trim().as_bytes()).unwrap();
let path = dungeon.find_path("Entrance", "Restrooms").unwrap().unwrap();
assert!(path.len() > 0);
}
#[test]
fn test_basic_5_find_path_fmi_failure() {
let dungeon = Dungeon::from_reader(TEST_INPUT_2.trim().as_bytes()).unwrap();
let path = dungeon.find_path("325", "Hallway").unwrap();
assert_eq!(path, None);
}
}
Павел качи решение на 09.01.2022 13:21 (преди почти 4 години)
use std::collections::{HashMap, HashSet, VecDeque};
use std::io::{BufRead, Error};
use std::str::FromStr;
/// Различните грешки, които ще очакваме да върнете като резултат от някои невалидни операции.
/// Повече детайли по-долу.
///
#[derive(Debug)]
pub enum Errors {
DuplicateRoom(String),
UnknownRoom(String),
IoError(std::io::Error),
LineParseError { line_number: usize },
DirectionParseError(String),
}
/// Четирите посоки, в които може една стая да има съседи. Може да добавите още trait
/// имплементации, за да си улесните живота.
///
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum Direction {
North,
South,
East,
West,
}
impl Direction {
fn rev(&self) -> Self {
match &self {
Direction::North => Direction::South,
Direction::South => Direction::North,
Direction::East => Direction::West,
Direction::West => Direction::East,
}
}
}
impl FromStr for Direction {
type Err = ();
fn from_str(input: &str) -> Result<Direction, Self::Err> {
match input {
"North" => Ok(Direction::North),
"South" => Ok(Direction::South),
"East" => Ok(Direction::East),
"West" => Ok(Direction::West),
_ => Err(()),
}
}
}
/// Една стая в подземията. Дефинира се само с име, макар че в по-интересна имплементация може да
/// държи item-и, противници...
///
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Room {
pub name: String,
}
impl Room {
fn new(name: String) -> Self {
Room {
name,
}
}
}
/// Контейнер за стаите и не само. Ще работим предимно със тази структура.
///
pub struct Dungeon {
pub rooms: HashMap<String, Room>,
pub passages: HashMap<(String, Direction), String>,
}
impl Dungeon {
/// Конструиране на празен Dungeon, в който няма никакви стаи.
///
pub fn new() -> Self {
Dungeon {
rooms: HashMap::new(),
passages: HashMap::new(),
}
}
/// Добавяне на стая към Dungeon с име `name`. Връща `Ok(())` при успех. Ако вече има стая с
/// такова име, очакваме да върнете `Errors::DuplicateRoom` с името.
///
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
let name = String::from(name);
if self.rooms.contains_key(&name) {
return Err(Errors::DuplicateRoom(name.clone()));
}
self.rooms.insert(name.clone(), Room::new(name.clone()));
Ok(())
}
/// Прочитане на дадена стая -- когато извикаме `get_room`, очакваме reference към `Room`
/// структурата с това име.
///
/// Ако няма такава стая, очакваме `Errors::UnknownRoom` с подаденото име.
///
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
let room_name = String::from(room_name);
self.rooms
.get(&room_name)
.ok_or(Errors::UnknownRoom(room_name))
}
/// Четене на съседа на стаята с име `room_name` в посока `direction`. Тук има няколко
/// варианта на изход:
///
/// - Ако подадената стая не съществува, очакваме грешка `Errors::UnknownRoom`
/// - Ако подадената стая няма съсед в тази посока, Ok(None) е смисления резултат
/// - Иначе, чакаме reference към `Room` структурата на въпросния съсед, опакована в `Ok(Some(`.
///
pub fn get_next_room(
&self,
room_name: &str,
direction: Direction,
) -> Result<Option<&Room>, Errors> {
let room_name = String::from(room_name);
let _room = self.get_room(&room_name)?;
Ok(self
.passages
.get(&(room_name, direction))
.map(|room_name| self.get_room(room_name).unwrap()))
}
/// Прочитаме структурата на dungeon от нещо, което имплементира `BufRead`. Това може да е
/// файл, или, ако тестваме, може да е просто колекция от байтове.
///
/// Успешен резултат връща новосъздадения dungeon, пакетиран в `Ok`.
///
/// Вижте по-долу за обяснение на грешките, които очакваме.
///
pub fn set_link(
&mut self,
room_name: &str,
direction: Direction,
other_room_name: &str,
) -> Result<(), Errors> {
let start_room_name = String::from(room_name);
let end_room_name = String::from(other_room_name);
let start_room = self
.rooms
.get(&start_room_name)
.ok_or(Errors::UnknownRoom(start_room_name.clone()))?;
let end_room = self
.rooms
.get(&end_room_name)
.ok_or(Errors::UnknownRoom(end_room_name.clone()))?;
let passages = &mut self.passages;
let direction_1 = direction;
let direction_2 = direction.rev();
let _ = passages.insert(
(start_room.name.clone(), direction_1),
end_room.name.clone(),
);
let _ = passages.insert(
(end_room.name.clone(), direction_2),
start_room.name.clone(),
);
Ok(())
}
/// Добавяне на съсед на дадена стая. След извикването на функцията, очакваме стаята с име
/// `room_name` да има връзка в посока `direction` със стаята с име `other_room_name`.
///
/// Също така очакваме `other_room_name` да има връзка с `room_name` в *обратната* посока.
///
/// Успешен резултат е `Ok(())`. В случай, че която от двете стаи не същестува, очакваме грешка
/// `Errors::UnknownRoom` със съответното име на липсваща стая. Ако и двете липсват, спокойно
/// върнете тази, която проверявате първо.
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
let line_parse_error = |line_num: usize| Errors::LineParseError {
line_number: line_num,
};
let trim_line = |line: String| String::from(line.as_str().trim());
let map_line_parse_err = |line: Result<String, Error>, line_num: usize| {
line.map_err(|_| line_parse_error(line_num))
};
let map_io_err = |line: Result<String, Error>| {
line.map_err(|io_error| Errors::IoError(io_error))
};
let mut lines = reader.lines();
let mut new_dungeon = Dungeon::new();
let mut line_num = 0;
line_num += 1;
let line = trim_line(map_line_parse_err(
lines.next().ok_or(line_parse_error(line_num))?,
line_num,
)?);
if line != "## Rooms" {
return Err(line_parse_error(line_num));
}
// Rooms
while let Some(line) = lines.next() {
line_num += 1;
let line = trim_line(map_io_err(line)?);
if line.len() < 3 || line[..2].to_string() != "- " {
- if line == "## Links" {
+ if line.is_empty() {
break;
} else {
return Err(line_parse_error(line_num));
}
}
new_dungeon.add_room(&line[2..])?;
}
+ line_num += 1;
+ let line = trim_line(map_line_parse_err(
+ lines.next().ok_or(line_parse_error(line_num))?,
+ line_num,
+ )?);
+ if line != "## Links" {
+ return Err(line_parse_error(line_num));
+ }
+
// Links
while let Some(line) = lines.next() {
line_num += 1;
let line = trim_line(map_io_err(line)?);
if line.len() < 3 || line[..2].to_string() != "- " {
return Err(line_parse_error(line_num));
}
let components = line[2..].split(" -> ").collect::<Vec<_>>();
if components.len() != 3 {
return Err(line_parse_error(line_num));
}
if let Ok(direction) = Direction::from_str(components[1]) {
new_dungeon.set_link(components[0], direction, components[2])?;
} else {
return Err(line_parse_error(line_num));
}
}
Ok(new_dungeon)
}
/// Търси път от `start_room_name` до `end_room_name` и го връща във вектор, пакетиран във
/// `Ok(Some(` ако намери.
///
/// Ако няма път между тези две стаи, връща `Ok(None)`.
///
/// Ако четенето на стаи в един момент върне грешка, очакваме да върнете грешката нагоре.
///
pub fn find_path(
&self,
start_room_name: &str,
end_room_name: &str,
) -> Result<Option<Vec<&Room>>, Errors> {
let start_room_name = String::from(start_room_name);
let end_room_name = String::from(end_room_name);
let start_room = self.get_room(&start_room_name)?;
let end_room = self.get_room(&end_room_name)?;
let mut visited: HashSet<String> = HashSet::new();
let mut parents: HashMap<String, String> = HashMap::new();
let mut queue = VecDeque::new();
queue.push_back(start_room);
while let Some(current_room) = queue.pop_front() {
if current_room == end_room {
break;
}
self.passages
.iter()
.filter(|((start_room_name, _), _)| current_room.name == *start_room_name)
.map(|((_, _), end_room)| end_room)
.for_each(|neighbouring_room| {
if visited.insert(neighbouring_room.clone()) {
queue.push_front(self.get_room(&neighbouring_room).unwrap());
parents.insert(neighbouring_room.clone(), current_room.name.clone());
}
})
}
Ok(match parents.get(&end_room.name) {
Some(_) => {
let mut path: VecDeque<&Room> = VecDeque::new();
path.push_front(&end_room);
let mut current_room: &Room = &end_room;
while let Some(parent_room_name) = parents.get(¤t_room.name) {
let parent_room = self.get_room(&parent_room_name)?;
path.push_front(parent_room);
current_room = parent_room;
}
Some(path.into())
}
None => None,
})
}
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn test_basic_1_two_rooms() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Hallway").unwrap();
dungeon
.set_link("Entrance", Direction::East, "Hallway")
.unwrap();
assert_eq!(dungeon.get_room("Entrance").unwrap().name, "Entrance");
assert_eq!(
dungeon
.get_next_room("Entrance", Direction::East)
.unwrap()
.unwrap()
.name,
"Hallway"
);
}
const TEST_INPUT_1: &'static str = "
## Rooms
- Entrance
- Hallway
+
## Links
- Entrance -> East -> Hallway
";
Благодаря ви, сигурно след 150-тното пускане на formatter-а се е загубил реда, а помня, че в началото го бях писал да чете и празен, но после забелязах, че в стригчето липсва :D
Хах, ясно :)
#[test]
fn test_basic_2_from_reader() {
// .trim() за да премахнем първия и последния ред:
let dungeon = Dungeon::from_reader(TEST_INPUT_1.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_3_find_path() {
let mut dungeon = Dungeon::new();
dungeon.add_room("Entrance").unwrap();
dungeon.add_room("Treasure Room").unwrap();
dungeon
.set_link("Entrance", Direction::West, "Treasure Room")
.unwrap();
let path = dungeon
.find_path("Entrance", "Treasure Room")
.unwrap()
.unwrap();
assert!(path.len() > 0);
}
const TEST_INPUT_2: &'static str = "
## Rooms
- Entrance
- Hallway
- Stairs
- Restrooms
- 325
- 101
+
## Links
- Entrance -> West -> Hallway
- Hallway -> East -> Stairs
- Stairs -> South -> 101
- Stairs -> North -> 325
- 325 -> South -> Restrooms
- Restrooms -> West -> Restrooms
";
#[test]
fn test_basic_4_find_path_fmi_success() {
let dungeon = Dungeon::from_reader(TEST_INPUT_2.trim().as_bytes()).unwrap();
let path = dungeon.find_path("Entrance", "Restrooms").unwrap().unwrap();
assert!(path.len() > 0);
}
#[test]
fn test_basic_5_find_path_fmi_failure() {
let dungeon = Dungeon::from_reader(TEST_INPUT_2.trim().as_bytes()).unwrap();
let path = dungeon.find_path("325", "Hallway").unwrap();
assert_eq!(path, None);
}
}
Това не е базовия тест -- липсва един ред. Виж го внимателно, виж внимателно и условието.
Благодаря ви, сигурно след 150-тното пускане на formatter-а се е загубил реда, а помня, че в началото го бях писал да чете и празен, но после забелязах, че в стригчето липсва :D
Хах, ясно :)