Решение на Dungeons and Compilers от Пламен Берберов
Към профила на Пламен Берберов
Резултати
- 8 точки от тестове
- 0 бонус точки
- 8 точки общо
- 6 успешни тест(а)
- 9 неуспешни тест(а)
Код
use std::collections::{HashMap, VecDeque};
use std::hash::{Hash};
use Errors::UnknownRoom;
use std::io::BufRead;
/// Различните грешки, които ще очакваме да върнете като резултат от някои невалидни операции.
/// Повече детайли по-долу.
///
#[derive(Debug)]
pub enum Errors {
DuplicateRoom(String),
UnknownRoom(String),
IoError(std::io::Error),
LineParseError { line_number: usize },
DirectionParseError(String),
}
/// Четирите посоки, в които може една стая да има съседи. Може да добавите още trait
/// имплементации, за да си улесните живота.
///
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
pub enum Direction {
North,
South,
East,
West,
}
//
// impl Hash for Direction {
// fn hash<H: Hasher>(&self, state: &mut H) {
// match self {
// Direction::North => String::from("North").hash(state),
// Direction::South => String::from("South").hash(state),
// Direction::East => String::from("East").hash(state),
// Direction::West => String::from("West").hash(state),
// }
// }
//
// }
/// Една стая в подземията. Дефинира се само с име, макар че в по-интересна имплементация може да
/// държи item-и, противници...
///
pub struct Room {
pub name: String,
// Каквито други полета ви трябват
}
/// Контейнер за стаите и не само. Ще работим предимно със тази структура.
///
pub struct Dungeon {
// Каквито полета ви трябват
rooms: HashMap<String, Room>,
links: HashMap<String, HashMap<Direction, String>>
}
impl Dungeon {
/// Конструиране на празен Dungeon, в който няма никакви стаи.
///
pub fn new() -> Self {
return Dungeon {rooms: HashMap::new(), links: HashMap::new() };
}
fn get_opposite_direction(&self, direction: Direction) -> Direction {
match direction {
Direction::East => Direction::West,
Direction::West => Direction::East,
Direction::North => Direction::South,
Direction::South => Direction::North
}
}
/// Добавяне на стая към Dungeon с име `name`. Връща `Ok(())` при успех. Ако вече има стая с
/// такова име, очакваме да върнете `Errors::DuplicateRoom` с името.
///
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
let result = match self.get_room(name) {
Err(_) => {
self.rooms.insert(String::from(name), Room{name: String::from(name)});
Ok(())
},
Ok(_) => Err(Errors::DuplicateRoom(String::from(name)))
};
result
}
/// Прочитане на дадена стая -- когато извикаме `get_room`, очакваме reference към `Room`
/// структурата с това име.
///
/// Ако няма такава стая, очакваме `Errors::UnknownRoom` с подаденото име.
///
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
match self.rooms.get(room_name) {
None => Err(UnknownRoom(String::from(room_name))),
Some(room) => Ok(room)
}
}
/// Добавяне на съсед на дадена стая. След извикването на функцията, очакваме стаята с име
/// `room_name` да има връзка в посока `direction` със стаята с име `other_room_name`.
///
/// Също така очакваме `other_room_name` да има връзка с `room_name` в *обратната* посока.
///
/// Успешен резултат е `Ok(())`. В случай, че която от двете стаи не същестува, очакваме грешка
/// `Errors::UnknownRoom` със съответното име на липсваща стая. Ако и двете липсват, спокойно
/// върнете тази, която проверявате първо.
///
pub fn set_link(
&mut self,
room_name: &str,
direction: Direction,
other_room_name: &str,
) -> Result<(), Errors> {
let _first = match self.get_room(room_name) {
Ok(room) => room,
Err(e) => return Err(e)
};
let _second = match self.get_room(other_room_name) {
Ok(room) => room,
Err(e) => return Err(e)
};
let one_way = self.links.entry(String::from(room_name))
.or_insert(HashMap::new());
one_way.insert(direction, String::from(other_room_name));
let opposite = self.get_opposite_direction(direction);
let second_way = self.links.entry(String::from(other_room_name))
.or_insert(HashMap::new());
second_way.insert(opposite, String::from(room_name));
Ok(())
}
/// Четене на съседа на стаята с име `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 _source = match self.get_room(room_name) {
Ok(room) => room,
Err(e) => return Err(e)
};
let result = match self.links.get(room_name){
None => Ok(None),
Some(entry) =>
match entry.get(&direction) {
None => Ok(None),
Some(name) => Ok(Some(self.get_room(name).unwrap()))
}
};
result
}
/// Прочитаме структурата на dungeon от нещо, което имплементира `BufRead`. Това може да е
/// файл, или, ако тестваме, може да е просто колекция от байтове.
///
/// Успешен резултат връща новосъздадения dungeon, пакетиран в `Ok`.
///
/// Вижте по-долу за обяснение на грешките, които очакваме.
///
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
todo!()
}
/// Търси път от `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 mut path: Vec<&Room> = Vec::new();
let mut next: VecDeque<&Room> = VecDeque::new();
let mut map: HashMap<&Room, &Room> = HashMap::new();
next.push_back(match self.get_room(start_room_name) {
Err(e) => return Err(e),
Ok(room) => room
});
while !next.is_empty() {
let curr = next.pop_front();
let links = self.links.get(&*curr.unwrap().name);
for item in links {
}
}
Ok(Some(path))
}
}
Лог от изпълнението
Compiling solution v0.1.0 (/tmp/d20220116-3533338-zzweei/solution) warning: unused variable: `reader` --> src/lib.rs:166:36 | 166 | pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> { | ^^^^^^ help: if this is intentional, prefix it with an underscore: `_reader` | = note: `#[warn(unused_variables)]` on by default warning: unused variable: `map` --> src/lib.rs:184:17 | 184 | let mut map: HashMap<&Room, &Room> = HashMap::new(); | ^^^ help: if this is intentional, prefix it with an underscore: `_map` warning: unused variable: `item` --> src/lib.rs:195:17 | 195 | for item in links { | ^^^^ help: if this is intentional, prefix it with an underscore: `_item` warning: unused variable: `end_room_name` --> src/lib.rs:180:9 | 180 | end_room_name: &str | ^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_end_room_name` warning: variable does not need to be mutable --> src/lib.rs:182:13 | 182 | let mut path: Vec<&Room> = Vec::new(); | ----^^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` on by default warning: variable does not need to be mutable --> src/lib.rs:184:13 | 184 | let mut map: HashMap<&Room, &Room> = HashMap::new(); | ----^^^ | | | help: remove this `mut` warning: `solution` (lib) generated 6 warnings Finished test [unoptimized + debuginfo] target(s) in 3.50s 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 ... FAILED 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 ... FAILED 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 ... FAILED test solution_test::test_parsing_no_rooms_or_links ... FAILED test solution_test::test_parsing_rooms ... FAILED test solution_test::test_room_errors ... ok test solution_test::test_room_links ... ok failures: ---- solution_test::test_finding_a_direct_path stdout ---- thread '<unnamed>' panicked at 'assertion failed: `(left == right)` left: `[]`, right: `["Entrance", "Treasure Room"]`', tests/solution_test.rs:314:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at 'assertion failed: `(left == right)` left: `[]`, right: `["Entrance", "Treasure Room"]`', tests/solution_test.rs:306:5 ---- solution_test::test_finding_a_reflexive_path stdout ---- thread '<unnamed>' panicked at 'index out of bounds: the len is 0 but the index is 0', tests/solution_test.rs:361:20 thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', tests/solution_test.rs:354:5 ---- solution_test::test_finding_an_indirect_path stdout ---- thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:339:42 thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:320:5 ---- solution_test::test_finding_no_path stdout ---- thread '<unnamed>' panicked at 'assertion failed: path.unwrap().is_none()', tests/solution_test.rs:379:9 thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:372:5 ---- solution_test::test_invalid_parsing stdout ---- thread 'main' panicked at 'not yet implemented', /tmp/d20220116-3533338-zzweei/solution/src/lib.rs:167:9 ---- solution_test::test_io_error stdout ---- thread '<unnamed>' panicked at 'not yet implemented', /tmp/d20220116-3533338-zzweei/solution/src/lib.rs:167:9 thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:194:5 ---- solution_test::test_parsing_cyrillic_rooms stdout ---- thread 'main' panicked at 'not yet implemented', /tmp/d20220116-3533338-zzweei/solution/src/lib.rs:167:9 ---- solution_test::test_parsing_no_rooms_or_links stdout ---- thread 'main' panicked at 'not yet implemented', /tmp/d20220116-3533338-zzweei/solution/src/lib.rs:167:9 ---- solution_test::test_parsing_rooms stdout ---- thread 'main' panicked at 'not yet implemented', /tmp/d20220116-3533338-zzweei/solution/src/lib.rs:167:9 failures: solution_test::test_finding_a_direct_path solution_test::test_finding_a_reflexive_path solution_test::test_finding_an_indirect_path solution_test::test_finding_no_path solution_test::test_invalid_parsing solution_test::test_io_error solution_test::test_parsing_cyrillic_rooms solution_test::test_parsing_no_rooms_or_links solution_test::test_parsing_rooms test result: FAILED. 6 passed; 9 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s error: test failed, to rerun pass '--test solution_test'