Решение на Dungeons and Compilers от Марио Николов

Обратно към всички решения

Към профила на Марио Николов

Резултати

  • 11 точки от тестове
  • 0 бонус точки
  • 11 точки общо
  • 8 успешни тест(а)
  • 7 неуспешни тест(а)

Код

use std::collections::HashMap;
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,
}
pub fn getOppositeDirection(dir: Direction) -> Direction {
match dir {
North => return Direction::South,
South => return Direction::North,
East => return Direction::West,
West => return Direction::East
};
}
/// Една стая в подземията. Дефинира се само с име, макар че в по-интересна имплементация може да
/// държи item-и, противници...
///
pub struct Room {
pub name: String,
pub connections : HashMap<Direction, String>,
// Каквито други полета ви трябват
}
impl Room {
pub fn new(ref roomName: String ) -> Self {
Room {
name : roomName.clone(),
connections : HashMap::new(),
}
}
}
/// Контейнер за стаите и не само. Ще работим предимно със тази структура.
///
pub struct Dungeon {
pub rooms : Vec<Room>,
}
impl Dungeon {
/// Конструиране на празен Dungeon, в който няма никакви стаи.
///
pub fn new() -> Self {
Dungeon {
rooms : Vec::new(),
}
}
/// Добавяне на стая към Dungeon с име `name`. Връща `Ok(())` при успех. Ако вече има стая с
/// такова име, очакваме да върнете `Errors::DuplicateRoom` с името.
///
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
for temp in self.rooms.iter() {
if temp.name.eq(name) {
return Err(Errors::DuplicateRoom(String::from(format!("{} doesn't exist",name))));
}
}
self.rooms.push(Room::new(String::from(name)));
Ok(())
}
/// Прочитане на дадена стая -- когато извикаме `get_room`, очакваме reference към `Room`
/// структурата с това име.
///
/// Ако няма такава стая, очакваме `Errors::UnknownRoom` с подаденото име.
///
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
for temp in self.rooms.iter() {
if temp.name.eq(room_name) {
return Ok(&temp);
}
}
Err(Errors::UnknownRoom(String::from(format!("{} doesn't exist",room_name))))
}
/// Добавяне на съсед на дадена стая. След извикването на функцията, очакваме стаята с име
/// `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 mut error_name:String = {
match self.get_room(room_name){
Ok(_v) => "".to_string(),
Err(_e) => room_name.to_string()
}
};
if error_name.len() > 0 {
return Err(Errors::UnknownRoom(format!("{} does not exist.",room_name)));
}
error_name = {
match self.get_room(other_room_name){
Ok(_v) => "".to_string(),
Err(_e) => other_room_name.to_string()
}
};
if error_name.len() > 0 {
return Err(Errors::UnknownRoom(format!("{} does not exist.",other_room_name)));
}
for temp in self.rooms.iter_mut() {
if temp.name.eq(room_name) {
temp.connections.insert(direction, other_room_name.to_string());
}
}
for temp in self.rooms.iter_mut() {
if temp.name.eq(other_room_name) {
temp.connections.insert(getOppositeDirection(direction), room_name.to_string());
}
}
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 mut room = {
match self.get_room(room_name){
Ok(v) => Ok(v),
Err(e) => Err(e)
}
};
match room {
Ok(v) => {
return match v.connections.contains_key(&direction) {
true => Ok(Some(self.get_room(v.connections[&direction].as_str()).unwrap())),
false => Ok(None)
}
},
Err(e) => return Err(e)
}
}
}
impl Dungeon {
/// Прочитаме структурата на dungeon от нещо, което имплементира `BufRead`. Това може да е
/// файл, или, ако тестваме, може да е просто колекция от байтове.
///
/// Успешен резултат връща новосъздадения dungeon, пакетиран в `Ok`.
///
/// Вижте по-долу за обяснение на грешките, които очакваме.
///
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
let mut current_line:usize = 0;
let mut rooms:bool =false;
let mut directions:bool=false;
let mut check_if_links:bool=false;
let mut result = Dungeon::new();
let mut line;
for cur in reader.lines(){
line = String::new();
match cur {
Ok(v) => {line = v;}
Err(e) => return Err(Errors::IoError(e))
};
current_line+=1;
if (!line.as_str().contains("## Rooms")) {
if (current_line == 1) {
return Err(Errors::LineParseError {line_number : current_line});
}
}
else {
rooms = true;
continue;
}
if rooms {
if !(line.eq("") || line.chars().nth(0).unwrap() == '-') {
return Err(Errors::LineParseError{line_number : current_line});
}
else if line.eq("") {
check_if_links = true;
rooms = false;
continue;
}
else {
result.add_room(&line[2..]);
}
}
if (!line.contains("## Links")) && check_if_links {
return Err(Errors::LineParseError{line_number:current_line});
}
if line.contains("## Links") && check_if_links {
directions = true;
check_if_links = false;
continue;
}
if directions {
if !(line.is_empty() || line.chars().nth(0).unwrap() == '-') {
return Err(Errors::LineParseError{line_number : current_line});
}
else if line.is_empty() {
directions = false;
continue;
}
else {
let list = line[2..].split(" -> ").collect::<Vec<&str>>();
if list[1].eq("North") {
result.set_link(list[0], Direction::North , list[2])?;
}
if list[1].eq("South") {
result.set_link(list[0], Direction::South , list[2])?;
}
if list[1].eq("East") {
result.set_link(list[0], Direction::East , list[2])?;
}
if list[1].eq("West") {
result.set_link(list[0], Direction::West , list[2])?;
}
}
}
}
Ok(result)
}
/// Търси път от `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> {
todo!()
}
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20220116-3533338-eriehs/solution)
warning: unnecessary parentheses around `if` condition
   --> src/lib.rs:204:16
    |
204 |             if (!line.as_str().contains("## Rooms")) {
    |                ^                                   ^
    |
    = note: `#[warn(unused_parens)]` on by default
help: remove these parentheses
    |
204 -             if (!line.as_str().contains("## Rooms")) {
204 +             if !line.as_str().contains("## Rooms") {
    | 

warning: unnecessary parentheses around `if` condition
   --> src/lib.rs:205:20
    |
205 |                 if (current_line == 1) {
    |                    ^                 ^
    |
help: remove these parentheses
    |
205 -                 if (current_line == 1) {
205 +                 if current_line == 1 {
    | 

warning[E0170]: pattern binding `North` is named the same as one of the variants of the type `Direction`
  --> src/lib.rs:28:9
   |
28 |         North => return Direction::South,
   |         ^^^^^ help: to match on the variant, qualify the path: `Direction::North`
   |
   = note: `#[warn(bindings_with_variant_name)]` on by default

warning[E0170]: pattern binding `South` is named the same as one of the variants of the type `Direction`
  --> src/lib.rs:29:9
   |
29 |         South => return Direction::North,
   |         ^^^^^ help: to match on the variant, qualify the path: `Direction::South`

warning[E0170]: pattern binding `East` is named the same as one of the variants of the type `Direction`
  --> src/lib.rs:30:9
   |
30 |         East => return Direction::West,
   |         ^^^^ help: to match on the variant, qualify the path: `Direction::East`

warning[E0170]: pattern binding `West` is named the same as one of the variants of the type `Direction`
  --> src/lib.rs:31:9
   |
31 |         West => return Direction::East
   |         ^^^^ help: to match on the variant, qualify the path: `Direction::West`

warning: unreachable pattern
  --> src/lib.rs:29:9
   |
28 |         North => return Direction::South,
   |         ----- matches any value
29 |         South => return Direction::North,
   |         ^^^^^ unreachable pattern
   |
   = note: `#[warn(unreachable_patterns)]` on by default

warning: unreachable pattern
  --> src/lib.rs:30:9
   |
28 |         North => return Direction::South,
   |         ----- matches any value
29 |         South => return Direction::North,
30 |         East => return Direction::West,
   |         ^^^^ unreachable pattern

warning: unreachable pattern
  --> src/lib.rs:31:9
   |
28 |         North => return Direction::South,
   |         ----- matches any value
...
31 |         West => return Direction::East
   |         ^^^^ unreachable pattern

warning: unused variable: `North`
  --> src/lib.rs:28:9
   |
28 |         North => return Direction::South,
   |         ^^^^^ help: if this is intentional, prefix it with an underscore: `_North`
   |
   = note: `#[warn(unused_variables)]` on by default

warning: unused variable: `South`
  --> src/lib.rs:29:9
   |
29 |         South => return Direction::North,
   |         ^^^^^ help: if this is intentional, prefix it with an underscore: `_South`

warning: unused variable: `East`
  --> src/lib.rs:30:9
   |
30 |         East => return Direction::West,
   |         ^^^^ help: if this is intentional, prefix it with an underscore: `_East`

warning: unused variable: `West`
  --> src/lib.rs:31:9
   |
31 |         West => return Direction::East
   |         ^^^^ help: if this is intentional, prefix it with an underscore: `_West`

warning: value assigned to `line` is never read
   --> src/lib.rs:198:13
    |
198 |             line = String::new();
    |             ^^^^
    |
    = note: `#[warn(unused_assignments)]` on by default
    = help: maybe it is overwritten before being read?

warning: unused variable: `start_room_name`
   --> src/lib.rs:283:9
    |
283 |         start_room_name: &str,
    |         ^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_start_room_name`

warning: unused variable: `end_room_name`
   --> src/lib.rs:284:9
    |
284 |         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:162:13
    |
162 |         let mut room = {
    |             ----^^^^
    |             |
    |             help: remove this `mut`
    |
    = note: `#[warn(unused_mut)]` on by default

warning: function `getOppositeDirection` should have a snake case name
  --> src/lib.rs:26:8
   |
26 | pub fn getOppositeDirection(dir: Direction) -> Direction {
   |        ^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `get_opposite_direction`
   |
   = note: `#[warn(non_snake_case)]` on by default

warning: variable `North` should have a snake case name
  --> src/lib.rs:28:9
   |
28 |         North => return Direction::South,
   |         ^^^^^ help: convert the identifier to snake case: `north`

warning: variable `South` should have a snake case name
  --> src/lib.rs:29:9
   |
29 |         South => return Direction::North,
   |         ^^^^^ help: convert the identifier to snake case (notice the capitalization): `south`

warning: variable `East` should have a snake case name
  --> src/lib.rs:30:9
   |
30 |         East => return Direction::West,
   |         ^^^^ help: convert the identifier to snake case: `east`

warning: variable `West` should have a snake case name
  --> src/lib.rs:31:9
   |
31 |         West => return Direction::East
   |         ^^^^ help: convert the identifier to snake case (notice the capitalization): `west`

warning: variable `roomName` should have a snake case name
  --> src/lib.rs:46:20
   |
46 |     pub fn new(ref roomName: String ) -> Self {
   |                    ^^^^^^^^ help: convert the identifier to snake case: `room_name`

warning: unused `Result` that must be used
   --> src/lib.rs:224:21
    |
224 |                     result.add_room(&line[2..]);
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(unused_must_use)]` on by default
    = note: this `Result` may be an `Err` variant, which should be handled

For more information about this error, try `rustc --explain E0170`.
warning: `solution` (lib) generated 24 warnings
    Finished test [unoptimized + debuginfo] target(s) in 3.57s
     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 ... FAILED
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 ... ok
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 ... 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_adding_rooms_2 stdout ----
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:97:77
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- solution_test::test_finding_a_direct_path stdout ----
thread '<unnamed>' panicked at 'not yet implemented', src/lib.rs:286:9
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:306:5

---- solution_test::test_finding_a_reflexive_path stdout ----
thread '<unnamed>' panicked at 'not yet implemented', src/lib.rs:286:9
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 '<unnamed>' panicked at 'not yet implemented', src/lib.rs:286:9
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 'not yet implemented', src/lib.rs:286: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 'assertion failed: matches!(Dungeon :: from_reader(\"\".as_bytes()),\n         Err(Errors :: LineParseError { line_number : 0 }))', tests/solution_test.rs:276:5

---- solution_test::test_parsing_cyrillic_rooms stdout ----
thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:301:71


failures:
    solution_test::test_adding_rooms_2
    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_parsing_cyrillic_rooms

test result: FAILED. 8 passed; 7 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass '--test solution_test'

История (1 версия и 0 коментара)

Марио качи първо решение на 11.01.2022 16:55 (преди над 3 години)