Решение на Dungeons and Compilers от Ивайло Петков

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

Към профила на Ивайло Петков

Резултати

  • 19 точки от тестове
  • 0 бонус точки
  • 19 точки общо
  • 14 успешни тест(а)
  • 1 неуспешни тест(а)

Код

use std::io::BufRead;
use std::collections::{HashMap, HashSet, VecDeque};
#[derive(Debug)]
pub enum Errors {
DuplicateRoom(String),
UnknownRoom(String),
IoError(std::io::Error),
LineParseError { line_number: usize },
DirectionParseError(String),
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum Direction {
North,
South,
East,
West,
}
impl Direction {
pub fn get_opposite(self) -> Direction{
match self {
Self::North => Self::South,
Self::South => Self::North,
Self::East => Self::West,
Self::West => Self::East,
}
}
pub fn get_direction(direction_str: &str) -> Result<Direction, Errors> {
match direction_str {
"North" => Ok(Self::North),
"South" => Ok(Self::South),
"East" => Ok(Self::East),
"West" => Ok(Self::West),
_ => Err(Errors::DirectionParseError(String::from(direction_str)))
}
}
}
pub struct Room {
pub name: String,
pub neighboors: HashMap<Direction, String>,
}
pub struct Dungeon {
pub rooms: HashMap<String, Room>,
}
impl Room {
pub fn new(room_name: &str) -> Self {
let name = String::from(room_name);
let neighboors = HashMap::new();
Room{
name,
neighboors,
}
}
pub fn add_neighboor(&mut self, direction: Direction, other_room: &str) -> () {
self.neighboors.insert(direction, String::from(other_room));
}
pub fn get_neighboors(&self) -> Vec<String> {
let mut vec = Vec::new();
for (_, value) in &self.neighboors {
vec.push(String::from(value));
}
vec
}
}
impl Dungeon {
pub fn new() -> Self {
let rooms = HashMap::new();
Dungeon {
rooms,
}
}
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
if self.rooms.contains_key(name)
{
return Err(Errors::DuplicateRoom(String::from(name)))
};
self.rooms.insert(String::from(name), Room::new(name));
Ok(())
}
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
let room = self.rooms.get(room_name);
match room {
Some(x) => Ok(x),
None => Err(Errors::UnknownRoom(String::from(room_name)))
}
}
pub fn set_link(
&mut self,
room_name: &str,
direction: Direction,
other_room_name: &str,
) -> Result<(), Errors> {
if !self.rooms.contains_key(room_name)
{
return Err(Errors::UnknownRoom(String::from(room_name)))
};
if !self.rooms.contains_key(other_room_name)
{
return Err(Errors::UnknownRoom(String::from(other_room_name)))
};
let room = self.rooms.get_mut(room_name).unwrap();
room.add_neighboor(direction, other_room_name);
let other_room = self.rooms.get_mut(other_room_name).unwrap();
other_room.add_neighboor(direction.get_opposite(), room_name);
Ok(())
}
pub fn get_next_room(&self, room_name: &str, direction: Direction) -> Result<Option<&Room>, Errors> {
let room = self.get_room(room_name)?;
if room.neighboors.get(&direction).is_none() {
return Ok(None)
};
let other_room_name = room.neighboors.get(&direction).unwrap();
Ok(self.rooms.get(other_room_name))
}
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
let mut lines = reader.lines();
let mut counter: usize = 0;
let mut dungeon = Dungeon::new();
let line_temp = lines.next();
if let Some(Ok(line)) = line_temp {
counter += 1;
if !(line == "## Rooms") {
return Err(Errors::LineParseError{line_number: counter})
}
}
else {
match line_temp {
Some(Err(x)) => { return Err(Errors::IoError(x)) },
_ => { return Err(Errors::LineParseError{line_number: counter}) }
}
}
while let Some(line_temp) = lines.next() {
match line_temp {
Ok(line) => {
counter += 1;
if line == "" {
break;
}
let room_name = line.strip_prefix("- ");
match room_name {
Some(name) => { dungeon.add_room(name)?; },
None => { return Err(Errors::LineParseError{line_number: counter}) }
}
},
Err(x) => { return Err(Errors::IoError(x)) }
}
}
let line_temp = lines.next();
if let Some(Ok(line)) = line_temp {
counter += 1;
if !(line == "## Links") {
return Err(Errors::LineParseError{line_number: counter})
}
}
else {
match line_temp {
Some(Err(x)) => { return Err(Errors::IoError(x)) },
_ => { return Err(Errors::LineParseError{line_number: counter}) }
}
}
while let Some(line_temp) = lines.next() {
match line_temp {
Ok(line) => {
counter += 1;
let link = line.strip_prefix("- ");
match link {
Some(link_str) => {
let mut string = String::from(" ");
string.push_str(link_str);
string.push_str(" ");
let link_strings: Vec<&str> = string.split(" -> ").collect();
if link_strings.len() != 3 {
return Err(Errors::LineParseError{line_number: counter})
}
let direction = Direction::get_direction(link_strings[1])?;
dungeon.set_link(remove_first(link_strings[0]), direction, remove_last(link_strings[2]))?;
},
None => { return Err(Errors::LineParseError{line_number: counter}) }
}
},
Err(x) => { return Err(Errors::IoError(x)) }
}
}
Ok(dungeon)
}
pub fn find_path(
&self,
start_room_name: &str,
end_room_name: &str
) -> Result<Option<Vec<&Room>>, Errors> {
if start_room_name == end_room_name {
let room = self.get_room(start_room_name)?;
return Ok(Some(vec![&room]));
}
let mut visited: HashSet<String> = HashSet::new();
let mut queue: VecDeque<&Room> = VecDeque::new();
let mut parents: HashMap<String, String> = HashMap::new();
let start_room = self.get_room(start_room_name)?;
visited.insert(String::from(start_room_name));
queue.push_back(start_room);
while let Some(room) = queue.pop_front() {
if room.name == end_room_name {
break;
}
let neighboors = room.get_neighboors();
for neighboor in neighboors {
if visited.contains(&neighboor) {
continue;
}
let child_room = self.get_room(&neighboor)?;
parents.insert(String::from(&child_room.name), String::from(&room.name));
visited.insert(String::from(&neighboor));
queue.push_back(child_room);
}
}
let room = parents.get(end_room_name);
match room {
Some(_) => {
let mut result: Vec<&Room> = Vec::new();
let end_room = self.get_room(end_room_name)?;
result.push(end_room);
while let Some(name) = parents.get(&result[0].name) {
let room = self.get_room(name)?;
result.insert(0, room);
}
Ok(Some(result))
},
None => Ok(None)
}
}
}
fn remove_first(value: &str) -> &str {
let mut chars = value.chars();
chars.next();
chars.as_str()
}
fn remove_last(value: &str) -> &str {
let mut chars = value.chars();
chars.next_back();
chars.as_str()
}

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

Compiling solution v0.1.0 (/tmp/d20220116-3533338-fgn31s/solution)
    Finished test [unoptimized + debuginfo] target(s) in 3.86s
     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 ... ok
test solution_test::test_finding_an_indirect_path ... ok
test solution_test::test_finding_no_path ... FAILED
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_no_path stdout ----
thread '<unnamed>' panicked at 'assertion failed: path.is_err()', tests/solution_test.rs:382:9
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:372:5


failures:
    solution_test::test_finding_no_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'

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

Ивайло качи първо решение на 09.01.2022 00:31 (преди почти 4 години)

Ивайло качи решение на 09.01.2022 00:55 (преди почти 4 години)

use std::io::BufRead;
use std::collections::HashMap;
#[derive(Debug)]
pub enum Errors {
DuplicateRoom(String),
UnknownRoom(String),
IoError(std::io::Error),
LineParseError { line_number: usize },
DirectionParseError(String),
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum Direction {
North,
South,
East,
West,
}
impl Direction {
pub fn get_opposite(self) -> Direction{
match self {
Self::North => Self::South,
Self::South => Self::North,
Self::East => Self::West,
Self::West => Self::East,
}
}
pub fn get_direction(direction_str: &str) -> Result<Direction, Errors> {
match direction_str {
"North" => Ok(Self::North),
"South" => Ok(Self::South),
"East" => Ok(Self::East),
"West" => Ok(Self::West),
_ => Err(Errors::DirectionParseError(String::from(direction_str)))
}
}
}
pub struct Room {
pub name: String,
pub neighboors: HashMap<Direction, String>,
}
pub struct Dungeon {
pub rooms: HashMap<String, Room>,
}
impl Room {
pub fn new(room_name: &str) -> Self {
let name = String::from(room_name);
let neighboors = HashMap::new();
Room{
name,
neighboors,
}
}
pub fn add_neighboor(&mut self, direction: Direction, other_room: &str) -> () {
self.neighboors.insert(direction, String::from(other_room));
}
}
impl Dungeon {
pub fn new() -> Self {
let rooms = HashMap::new();
Dungeon {
rooms,
}
}
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
if self.rooms.contains_key(name)
{
return Err(Errors::DuplicateRoom(String::from(name)))
};
self.rooms.insert(String::from(name), Room::new(name));
Ok(())
}
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
let room = self.rooms.get(room_name);
match room {
Some(x) => Ok(x),
None => Err(Errors::UnknownRoom(String::from(room_name)))
}
}
pub fn set_link(
&mut self,
room_name: &str,
direction: Direction,
other_room_name: &str,
) -> Result<(), Errors> {
if !self.rooms.contains_key(room_name)
{
return Err(Errors::UnknownRoom(String::from(room_name)))
};
if !self.rooms.contains_key(other_room_name)
{
return Err(Errors::UnknownRoom(String::from(other_room_name)))
};
let room = self.rooms.get_mut(room_name).unwrap();
room.add_neighboor(direction, other_room_name);
let other_room = self.rooms.get_mut(other_room_name).unwrap();
other_room.add_neighboor(direction.get_opposite(), room_name);
Ok(())
}
pub fn get_next_room(&self, room_name: &str, direction: Direction) -> Result<Option<&Room>, Errors> {
let room = self.get_room(room_name)?;
if room.neighboors.get(&direction).is_none() {
return Ok(None)
};
let other_room_name = room.neighboors.get(&direction).unwrap();
Ok(self.rooms.get(other_room_name))
}
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
let mut lines = reader.lines();
let mut counter: usize = 0;
let mut dungeon = Dungeon::new();
- if let Some(Ok(line)) = lines.next() {
+ let line_temp = lines.next();
+ if let Some(Ok(line)) = line_temp {
counter += 1;
if !(line == "## Rooms") {
return Err(Errors::LineParseError{line_number: counter})
}
}
else {
- return Err(Errors::LineParseError{line_number: counter})
+ match line_temp {
+ Some(Err(x)) => { return Err(Errors::IoError(x)) },
+ _ => { return Err(Errors::LineParseError{line_number: counter}) }
+ }
}
- while let Some(Ok(line)) = lines.next() {
- counter += 1;
- if line == "" {
- break;
+
+ while let Some(line_temp) = lines.next() {
+ match line_temp {
+ Ok(line) => {
+ counter += 1;
+ if line == "" {
+ break;
+ }
+ let room_name = line.strip_prefix("- ");
+ match room_name {
+ Some(name) => { dungeon.add_room(name)?; },
+ None => { return Err(Errors::LineParseError{line_number: counter}) }
+ }
+ },
+ Err(x) => { return Err(Errors::IoError(x)) }
}
- let room_name = line.strip_prefix("- ");
- match room_name {
- Some(name) => { dungeon.add_room(name)?; }
- None => { return Err(Errors::LineParseError{line_number: counter}) }
- }
}
- if let Some(Ok(line)) = lines.next() {
+ let line_temp = lines.next();
+ if let Some(Ok(line)) = line_temp {
counter += 1;
if !(line == "## Links") {
return Err(Errors::LineParseError{line_number: counter})
}
}
else {
- return Err(Errors::LineParseError{line_number: counter})
- }
- while let Some(Ok(line)) = lines.next() {
- counter += 1;
- if line == "" {
- break;
+ match line_temp {
+ Some(Err(x)) => { return Err(Errors::IoError(x)) },
+ _ => { return Err(Errors::LineParseError{line_number: counter}) }
}
- let link = line.strip_prefix("- ");
- match link {
- Some(link_str) => {
- let mut string = String::from(" ");
- string.push_str(link_str);
- string.push_str(" ");
- let link_strings: Vec<&str> = string.split(" -> ").collect();
+ }
- if link_strings.len() != 3 {
- return Err(Errors::LineParseError{line_number: counter})
- }
+ while let Some(line_temp) = lines.next() {
+ match line_temp {
+ Ok(line) => {
+ counter += 1;
+ let link = line.strip_prefix("- ");
+ match link {
+ Some(link_str) => {
+ let mut string = String::from(" ");
+ string.push_str(link_str);
+ string.push_str(" ");
+ let link_strings: Vec<&str> = string.split(" -> ").collect();
- let direction = Direction::get_direction(link_strings[1])?;
- dungeon.set_link(remove_first(link_strings[0]), direction, remove_last(link_strings[2]))?;
- }
- None => { return Err(Errors::LineParseError{line_number: counter}) }
+ if link_strings.len() != 3 {
+ return Err(Errors::LineParseError{line_number: counter})
+ }
+
+ let direction = Direction::get_direction(link_strings[1])?;
+ dungeon.set_link(remove_first(link_strings[0]), direction, remove_last(link_strings[2]))?;
+ },
+ None => { return Err(Errors::LineParseError{line_number: counter}) }
+ }
+ },
+ Err(x) => { return Err(Errors::IoError(x)) }
}
}
Ok(dungeon)
}
pub fn find_path(
&self,
start_room_name: &str,
end_room_name: &str
) -> Result<Option<Vec<&Room>>, Errors> {
todo!()
}
}
fn remove_first(value: &str) -> &str {
let mut chars = value.chars();
chars.next();
chars.as_str()
}
fn remove_last(value: &str) -> &str {
let mut chars = value.chars();
chars.next_back();
chars.as_str()
}

Ивайло качи решение на 10.01.2022 00:43 (преди почти 4 години)

use std::io::BufRead;
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet, VecDeque};
#[derive(Debug)]
pub enum Errors {
DuplicateRoom(String),
UnknownRoom(String),
IoError(std::io::Error),
LineParseError { line_number: usize },
DirectionParseError(String),
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum Direction {
North,
South,
East,
West,
}
impl Direction {
pub fn get_opposite(self) -> Direction{
match self {
Self::North => Self::South,
Self::South => Self::North,
Self::East => Self::West,
Self::West => Self::East,
}
}
pub fn get_direction(direction_str: &str) -> Result<Direction, Errors> {
match direction_str {
"North" => Ok(Self::North),
"South" => Ok(Self::South),
"East" => Ok(Self::East),
"West" => Ok(Self::West),
_ => Err(Errors::DirectionParseError(String::from(direction_str)))
}
}
}
pub struct Room {
pub name: String,
pub neighboors: HashMap<Direction, String>,
}
pub struct Dungeon {
pub rooms: HashMap<String, Room>,
}
impl Room {
pub fn new(room_name: &str) -> Self {
let name = String::from(room_name);
let neighboors = HashMap::new();
Room{
name,
neighboors,
}
}
pub fn add_neighboor(&mut self, direction: Direction, other_room: &str) -> () {
self.neighboors.insert(direction, String::from(other_room));
}
+
+ pub fn get_neighboors(&self) -> Vec<String> {
+ let mut vec = Vec::new();
+
+ for (_, value) in &self.neighboors {
+ vec.push(String::from(value));
+ }
+
+ vec
+ }
}
impl Dungeon {
pub fn new() -> Self {
let rooms = HashMap::new();
Dungeon {
rooms,
}
}
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
if self.rooms.contains_key(name)
{
return Err(Errors::DuplicateRoom(String::from(name)))
};
self.rooms.insert(String::from(name), Room::new(name));
Ok(())
}
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
let room = self.rooms.get(room_name);
match room {
Some(x) => Ok(x),
None => Err(Errors::UnknownRoom(String::from(room_name)))
}
}
pub fn set_link(
&mut self,
room_name: &str,
direction: Direction,
other_room_name: &str,
) -> Result<(), Errors> {
if !self.rooms.contains_key(room_name)
{
return Err(Errors::UnknownRoom(String::from(room_name)))
};
if !self.rooms.contains_key(other_room_name)
{
return Err(Errors::UnknownRoom(String::from(other_room_name)))
};
let room = self.rooms.get_mut(room_name).unwrap();
room.add_neighboor(direction, other_room_name);
let other_room = self.rooms.get_mut(other_room_name).unwrap();
other_room.add_neighboor(direction.get_opposite(), room_name);
Ok(())
}
pub fn get_next_room(&self, room_name: &str, direction: Direction) -> Result<Option<&Room>, Errors> {
let room = self.get_room(room_name)?;
if room.neighboors.get(&direction).is_none() {
return Ok(None)
};
let other_room_name = room.neighboors.get(&direction).unwrap();
Ok(self.rooms.get(other_room_name))
}
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
let mut lines = reader.lines();
let mut counter: usize = 0;
let mut dungeon = Dungeon::new();
let line_temp = lines.next();
if let Some(Ok(line)) = line_temp {
counter += 1;
if !(line == "## Rooms") {
return Err(Errors::LineParseError{line_number: counter})
}
}
else {
match line_temp {
Some(Err(x)) => { return Err(Errors::IoError(x)) },
_ => { return Err(Errors::LineParseError{line_number: counter}) }
}
}
while let Some(line_temp) = lines.next() {
match line_temp {
Ok(line) => {
counter += 1;
if line == "" {
break;
}
let room_name = line.strip_prefix("- ");
match room_name {
Some(name) => { dungeon.add_room(name)?; },
None => { return Err(Errors::LineParseError{line_number: counter}) }
}
},
Err(x) => { return Err(Errors::IoError(x)) }
}
}
let line_temp = lines.next();
if let Some(Ok(line)) = line_temp {
counter += 1;
if !(line == "## Links") {
return Err(Errors::LineParseError{line_number: counter})
}
}
else {
match line_temp {
Some(Err(x)) => { return Err(Errors::IoError(x)) },
_ => { return Err(Errors::LineParseError{line_number: counter}) }
}
}
while let Some(line_temp) = lines.next() {
match line_temp {
Ok(line) => {
counter += 1;
let link = line.strip_prefix("- ");
match link {
Some(link_str) => {
let mut string = String::from(" ");
string.push_str(link_str);
string.push_str(" ");
let link_strings: Vec<&str> = string.split(" -> ").collect();
if link_strings.len() != 3 {
return Err(Errors::LineParseError{line_number: counter})
}
let direction = Direction::get_direction(link_strings[1])?;
dungeon.set_link(remove_first(link_strings[0]), direction, remove_last(link_strings[2]))?;
},
None => { return Err(Errors::LineParseError{line_number: counter}) }
}
},
Err(x) => { return Err(Errors::IoError(x)) }
}
}
Ok(dungeon)
}
pub fn find_path(
&self,
start_room_name: &str,
end_room_name: &str
) -> Result<Option<Vec<&Room>>, Errors> {
- todo!()
+ if start_room_name == end_room_name {
+ let room = self.get_room(start_room_name)?;
+
+ return Ok(Some(vec![&room]));
+ }
+
+ let mut visited: HashSet<String> = HashSet::new();
+ let mut queue: VecDeque<&Room> = VecDeque::new();
+ let mut parents: HashMap<String, String> = HashMap::new();
+
+ let start_room = self.get_room(start_room_name)?;
+ visited.insert(String::from(start_room_name));
+ queue.push_back(start_room);
+
+ while let Some(room) = queue.pop_front() {
+ if room.name == end_room_name {
+ break;
+ }
+ let neighboors = room.get_neighboors();
+
+ for neighboor in neighboors {
+ if visited.contains(&neighboor) {
+ continue;
+ }
+
+ let child_room = self.get_room(&neighboor)?;
+ parents.insert(String::from(&child_room.name), String::from(&room.name));
+ visited.insert(String::from(&neighboor));
+ queue.push_back(child_room);
+ }
+ }
+
+ let room = parents.get(end_room_name);
+
+ match room {
+ Some(_) => {
+ let mut result: Vec<&Room> = Vec::new();
+ let end_room = self.get_room(end_room_name)?;
+ result.push(end_room);
+
+ while let Some(name) = parents.get(&result[0].name) {
+ let room = self.get_room(name)?;
+ result.insert(0, room);
+ }
+
+ Ok(Some(result))
+ },
+ None => Ok(None)
+ }
}
}
fn remove_first(value: &str) -> &str {
let mut chars = value.chars();
chars.next();
chars.as_str()
}
fn remove_last(value: &str) -> &str {
let mut chars = value.chars();
chars.next_back();
chars.as_str()
}