Решение на Dungeons and Compilers от Георги Събев

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

Към профила на Георги Събев

Резултати

  • 13 точки от тестове
  • 0 бонус точки
  • 13 точки общо
  • 10 успешни тест(а)
  • 5 неуспешни тест(а)

Код

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),
}
#[derive(Clone, Copy, Hash, Eq, PartialEq)]
pub enum Direction {
North,
South,
East,
West,
}
pub struct Room {
pub name: String,
pub neighbours: HashMap<Direction, String>,
}
pub struct Dungeon {
pub rooms: HashMap<String, Room>,
}
impl Dungeon {
pub fn new() -> Self {
Dungeon {
rooms: HashMap::new(),
}
}
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
match self.rooms.contains_key(name) {
true => Err(Errors::DuplicateRoom(String::from(name))),
false => {
self.rooms.insert(
String::from(name),
Room {
name: String::from(name),
neighbours: HashMap::new(),
},
);
Ok(())
}
}
}
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
match self.rooms.contains_key(room_name) {
true => Ok(self.rooms.get(room_name).unwrap()),
false => Err(Errors::UnknownRoom(String::from(room_name))),
}
}
pub fn set_link(
&mut self,
room_name: &str,
direction: Direction,
other_room_name: &str,
) -> Result<(), Errors> {
match self.rooms.contains_key(room_name) {
true => match self.rooms.contains_key(other_room_name) {
true => {
let opposite_direction: Direction = match direction {
Direction::North => Direction::South,
Direction::South => Direction::North,
Direction::East => Direction::West,
Direction::West => Direction::East,
};
self.rooms
.get_mut(room_name)
.unwrap()
.neighbours
.insert(direction, String::from(other_room_name));
self.rooms
.get_mut(other_room_name)
.unwrap()
.neighbours
.insert(opposite_direction, String::from(room_name));
Ok(())
}
false => Err(Errors::UnknownRoom(String::from(other_room_name))),
},
false => Err(Errors::UnknownRoom(String::from(room_name))),
}
}
pub fn get_next_room(
&self,
room_name: &str,
direction: Direction,
) -> Result<Option<&Room>, Errors> {
match self.rooms.contains_key(room_name) {
true => match self
.rooms
.get(room_name)
.unwrap()
.neighbours
.contains_key(&direction)
{
true => {
let neighbour_name = self
.rooms
.get(room_name)
.unwrap()
.neighbours
.get(&direction)
.unwrap();
Ok(Some(self.rooms.get(neighbour_name).unwrap()))
}
false => Ok(None),
},
false => Err(Errors::UnknownRoom(String::from(room_name))),
}
}
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
let mut r = reader;
let mut line_str = String::new();
let mut line_idx = 0;
let mut flag_rooms: bool = false;
let mut flag_empty: bool = false;
let mut flag_links: bool = false;
let mut dungeon = Dungeon::new();
while r.read_line(&mut line_str).unwrap() > 0 {
line_idx += 1;
if line_str == "## Rooms\n" && line_idx == 1 {
flag_rooms = true;
} else if line_str.find("- ") == Some(0)
&& line_str.find(" -> ") == None
&& line_idx > 1
&& flag_rooms
&& flag_empty == false
&& flag_links == false
{
let mut room_str = line_str.split_off(2);
let last_char = room_str.pop().unwrap();
if last_char != '\n' {
room_str.push(last_char);
}
dungeon.add_room(room_str.as_str())?;
} else if line_str == "\n"
&& line_idx > 1
&& flag_rooms
&& flag_empty == false
&& flag_links == false
{
flag_empty = true;
} else if line_str == "## Links\n"
&& line_idx > 1
&& flag_rooms
&& flag_empty
&& flag_links == false
{
flag_links = true;
} else if line_str.find("- ") == Some(0)
&& line_str.find(" ->") != None
&& line_idx > 1
&& flag_rooms
&& flag_empty
&& flag_links
{
let mut link_str = line_str.split_off(2);
let last_char = link_str.pop().unwrap();
if last_char != '\n' {
link_str.push(last_char);
}
let substrings: Vec<&str> = link_str.split_terminator(" -> ").collect();
let room1: &str = substrings.get(0).unwrap();
let room2: &str = substrings.get(2).unwrap();
let direction: &str = substrings.get(1).unwrap();
let direction: Direction = match direction {
"North" => Direction::North,
"South" => Direction::South,
"East" => Direction::East,
"West" => Direction::West,
_ => {
return Err(Errors::LineParseError {
line_number: line_idx,
});
}
};
dungeon.set_link(room1, direction, room2)?;
} else {
return Err(Errors::LineParseError {
line_number: line_idx,
});
}
line_str.clear();
}
Ok(dungeon)
}
pub fn find_path(
&self,
start_room_name: &str,
end_room_name: &str,
) -> Result<Option<Vec<&Room>>, Errors> {
let mut queue: Vec<String> = Vec::new();
let mut result: Vec<&Room> = Vec::new();
let mut visited: HashMap<String, bool> = HashMap::new();
let mut parents: HashMap<String, String> = HashMap::new();
let mut current_room: String;
queue.push(String::from(start_room_name));
visited.insert(String::from(start_room_name), true);
while queue.is_empty() == false {
current_room = queue[0].clone();
queue.remove(0);
if current_room == end_room_name {
break;
}
for neigh in &self.rooms.get(&current_room).unwrap().neighbours {
if visited.contains_key(&neigh.1.clone()) == false {
parents.insert(neigh.1.clone(), current_room.clone());
visited.insert(neigh.1.clone(), true);
queue.push(String::from(neigh.1));
}
}
}
if parents.contains_key(end_room_name) {
let mut current_child = String::from(end_room_name);
let room = self.get_room(&current_child).unwrap();
result.push(room);
while parents.contains_key(&current_child.clone()) {
let parent: &Room = self.get_room(parents.get(&current_child).unwrap()).unwrap();
result.push(parent);
current_child = parents.get(&current_child).unwrap().to_string();
}
result.reverse();
Ok(Some(result))
} else {
return Ok(None);
}
}
}

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

Compiling solution v0.1.0 (/tmp/d20220116-3533338-dk4ubh/solution)
    Finished test [unoptimized + debuginfo] target(s) in 3.84s
     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 ... 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 ... ok
test solution_test::test_parsing_no_rooms_or_links ... FAILED
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_no_path stdout ----
thread '<unnamed>' panicked at 'assertion failed: path.is_err()', tests/solution_test.rs:382: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_io_error stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "fill_buf error!" }', /tmp/d20220116-3533338-dk4ubh/solution/src/lib.rs:139:42
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "fill_buf error!" }', tests/solution_test.rs:194:5

---- solution_test::test_parsing_no_rooms_or_links stdout ----
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: LineParseError { line_number: 3 }', tests/solution_test.rs:237:72


failures:
    solution_test::test_finding_a_reflexive_path
    solution_test::test_finding_no_path
    solution_test::test_invalid_parsing
    solution_test::test_io_error
    solution_test::test_parsing_no_rooms_or_links

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

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

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

Георги качи първо решение на 09.01.2022 16:04 (преди почти 4 години)