Решение на Dungeons and Compilers от Иван Борисов

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

Към профила на Иван Борисов

Резултати

  • 16 точки от тестове
  • 0 бонус точки
  • 16 точки общо
  • 12 успешни тест(а)
  • 3 неуспешни тест(а)

Код

use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use std::fs::File;
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,
}
#[derive(Hash, PartialEq, Eq, Clone)]
pub struct Room {
pub name: String,
}
type Node = (Direction, Room);
#[allow(non_snake_case)]
pub struct Dungeon {
g: HashMap<Room, HashSet<Node>>,
addedRooms: HashSet<Room>,
}
#[allow(non_snake_case)]
fn returnDirections(dir: Direction) -> (Direction, Direction) {
match dir {
Direction::East => (Direction::East, Direction::West),
Direction::West => (Direction::West, Direction::East),
Direction::North => (Direction::North, Direction::South),
Direction::South => (Direction::South, Direction::North),
}
}
#[allow(non_snake_case)]
impl Dungeon {
pub fn new() -> Self {
Dungeon {
g: HashMap::new(),
addedRooms: HashSet::new(),
}
}
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
let room = Room {
name: name.to_string(),
};
if self.addedRooms.contains(&room) {
return Err(Errors::DuplicateRoom(String::from(room.name)));
} else {
self.g.insert(room.clone(), HashSet::new());
self.addedRooms.insert(room.clone());
Ok(())
}
}
pub fn set_link(
&mut self,
room_name: &str,
direction: Direction,
other_room_name: &str,
) -> Result<(), Errors> {
let room_name_str = Room {
name: room_name.to_string(),
};
let other_room_name_str = Room {
name: other_room_name.to_string(),
};
if !self.addedRooms.contains(&room_name_str) {
Err(Errors::UnknownRoom(String::from(room_name)))
} else if !self.addedRooms.contains(&other_room_name_str) {
Err(Errors::UnknownRoom(String::from(other_room_name)))
} else {
let dir = returnDirections(direction);
//check later if direction is wrong.
let adjNodes: Vec<Node> = self
.g
.clone()
.get_mut(&room_name_str)
.unwrap()
.clone()
.into_iter()
.collect();
for adj in adjNodes.clone() {
if adj.0 == dir.0 {
self.g.get_mut(&room_name_str).unwrap().remove(&adj);
break;
}
}
let adjNodes: Vec<Node> = self
.g
.clone()
.get_mut(&other_room_name_str)
.unwrap()
.clone()
.into_iter()
.collect();
for adj in adjNodes.clone() {
if adj.0 == dir.1 {
self.g.get_mut(&other_room_name_str).unwrap().remove(&adj);
break;
}
}
self.g
.get_mut(&room_name_str)
.unwrap()
.insert((dir.0, other_room_name_str.clone()));
self.g
.get_mut(&other_room_name_str)
.unwrap()
.insert((dir.1, room_name_str.clone()));
Ok(())
}
}
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
let room = Room {
name: room_name.to_string(),
};
if !self.addedRooms.contains(&room) {
return Err(Errors::UnknownRoom(String::from(room_name)));
}
Ok(self.addedRooms.get(&room).unwrap())
}
pub fn get_next_room(
&self,
room_name: &str,
direction: Direction,
) -> Result<Option<&Room>, Errors> {
let room = Room {
name: room_name.to_string(),
};
if !self.addedRooms.contains(&room) {
return Err(Errors::UnknownRoom(String::from(room_name)));
}
let adjNodes: Vec<Node> = self
.g
.clone()
.get_mut(&room)
.unwrap()
.clone()
.into_iter()
.collect();
for adj in adjNodes.clone() {
if adj.0 == direction {
return Ok(self.addedRooms.get(&adj.1));
}
}
Ok(None)
}
//1.empty reader 2.result from reading.
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
let mut vecLines: Vec<String> = Vec::new();
let mut dungeon = Dungeon::new();
for l in reader.lines() {
vecLines.push(l.unwrap());
}
if vecLines.len() == 0{
return Err(Errors::LineParseError {
line_number: 0,
});
}
let mut curLineNumber: usize = 1;
//getting rooms
if !vecLines[curLineNumber - 1].contains("## Rooms") {
return Err(Errors::LineParseError {
line_number: curLineNumber,
});
}
curLineNumber += 1;
while !vecLines[curLineNumber - 1].is_empty() {
let vecString: Vec<_> = vecLines[curLineNumber - 1].chars().collect();
if vecString.len() <= 2 {
return Err(Errors::LineParseError {
line_number: curLineNumber,
});
}
if vecString[0] != '-' || vecString[1] != ' ' {
return Err(Errors::LineParseError {
line_number: curLineNumber,
});
}
let mut room: String = String::new();
let mut i: usize = 2;
while i < vecString.len() {
room.push(vecString[i]);
i += 1;
}
let mut d = dungeon.add_room(room.as_str()).unwrap();
curLineNumber += 1;
}
curLineNumber += 1;
//setting links
if !vecLines[curLineNumber - 1].contains("## Links") {
return Err(Errors::LineParseError {
line_number: curLineNumber,
});
}
curLineNumber += 1;
while curLineNumber - 1 < vecLines.len() {
let vecString: Vec<_> = vecLines[curLineNumber - 1].chars().collect();
let mut firstRoomName: String = String::new();
let mut direction: String = String::new();
let mut secondRoomName: String = String::new();
if vecString[0] != '-' || vecString[1] != ' ' {
return Err(Errors::LineParseError {
line_number: curLineNumber,
});
}
let mut i: usize = 2;
//getting first room name
while vecString[i] != '-' {
firstRoomName.push(vecString[i]);
i += 1;
}
firstRoomName.pop();
if vecString[i - 1] != ' '
|| vecString[i] != '-'
|| vecString[i + 1] != '>'
|| vecString[i + 2] != ' '
{
return Err(Errors::LineParseError {
line_number: curLineNumber,
});
}
i += 3;
//getting direction
while vecString[i] != '-' {
direction.push(vecString[i]);
i += 1;
}
direction.pop();
if direction != "North"
&& direction != "South"
&& direction != "East"
&& direction != "West"
{
return Err(Errors::DirectionParseError(direction));
}
let mut north: String = String::from("North");
let mut south: String = String::from("South");
let mut west: String = String::from("West");
let mut east: String = String::from("East");
let d: Direction;
if north == direction {
d = Direction::North;
} else if south == direction {
d = Direction::South;
} else if west == direction {
d = Direction::West;
} else {
d = Direction::East;
}
if vecString[i - 1] != ' '
|| vecString[i] != '-'
|| vecString[i + 1] != '>'
|| vecString[i + 2] != ' '
{
return Err(Errors::LineParseError {
line_number: curLineNumber,
});
}
i += 3;
//getting second room name
while i < vecString.len() {
secondRoomName.push(vecString[i]);
i += 1;
}
dungeon
.set_link(firstRoomName.as_str(), d, secondRoomName.as_str())
.unwrap();
curLineNumber += 1;
}
Ok(dungeon)
}
pub fn find_path(
&self,
start_room_name: &str,
end_room_name: &str,
) -> Result<Option<Vec<&Room>>, Errors> {
let mut queue: VecDeque<Room> = VecDeque::new();
let mut path: Vec<Room> = Vec::new();
let mut visited: HashMap<Room, bool> = HashMap::new();
type Parent = Room;
type Children = Room;
let mut connections: HashMap<Children, Parent> = HashMap::new();
let start_room_name = Room {
name: start_room_name.to_string(),
};
let end_room_name = Room {
name: end_room_name.to_string(),
};
let mut actualPath: Vec<&Room> = Vec::new();
if start_room_name == end_room_name {
actualPath.push(self.addedRooms.get(&start_room_name).unwrap());
return Ok(Some(actualPath));
}
let empty = Room {
name: "".to_string(),
};
//1.Set all visited to false.
for key in self.g.keys().clone() {
visited.insert(key.clone(), false);
connections.insert(key.clone(), empty.clone());
}
queue.push_back(start_room_name.clone());
visited.insert(start_room_name.clone(), true);
while !queue.is_empty() {
let parent = queue.back().unwrap().clone();
queue.pop_front();
if parent.clone() == end_room_name {
break;
}
if self.g.get(&parent).is_none() {
continue;
}
// println!("{}" , self.g.get(&parent).unwrap().len());
let adjNodes: Vec<Node> = self
.g
.clone()
.get(&parent)
.unwrap()
.clone()
.into_iter()
.collect();
let l = adjNodes.len();
for i in 0..l {
let child = adjNodes[i].1.clone();
if visited.get(&child).unwrap().clone() == false {
visited.insert(child.clone(), true);
//connections.get_mut(&child).unwrap().push(parent.clone());
connections.insert(child.clone(), parent.clone());
queue.push_back(child.clone());
}
}
}
// if connections.get_mut(&end_room_name).unwrap()
if connections
.get(&end_room_name)
.unwrap()
.clone()
.name
.is_empty()
{
return Ok(None);
}
let mut hasParent: bool = true;
let mut par = connections.get(&end_room_name).unwrap().clone();
let mut parcp = connections.get(&par).unwrap().clone();
path.push(end_room_name.clone());
while !connections.get(&par).unwrap().clone().name.is_empty() {
path.push(par.clone());
let next = connections.get(&par).unwrap().clone();
par = next;
}
path.push(start_room_name.clone());
path.reverse();
let mut actualPath: Vec<&Room> = Vec::new();
for i in 0..path.len() {
actualPath.push(self.addedRooms.get(&path[i]).unwrap());
}
Ok(Some(actualPath))
}
}
fn main() {}

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

Compiling solution v0.1.0 (/tmp/d20220116-3533338-1v2rfns/solution)
warning: unused import: `std::fs::File`
 --> src/lib.rs:4:5
  |
4 | use std::fs::File;
  |     ^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: unused variable: `d`
   --> src/lib.rs:214:21
    |
214 |             let mut d = dungeon.add_room(room.as_str()).unwrap();
    |                     ^ help: if this is intentional, prefix it with an underscore: `_d`
    |
    = note: `#[warn(unused_variables)]` on by default

warning: unused variable: `east`
   --> src/lib.rs:273:21
    |
273 |             let mut east: String = String::from("East");
    |                     ^^^^ help: if this is intentional, prefix it with an underscore: `_east`

warning: unused variable: `hasParent`
   --> src/lib.rs:387:17
    |
387 |         let mut hasParent: bool = true;
    |                 ^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_hasParent`

warning: unused variable: `parcp`
   --> src/lib.rs:389:17
    |
389 |         let mut parcp = connections.get(&par).unwrap().clone();
    |                 ^^^^^ help: if this is intentional, prefix it with an underscore: `_parcp`

warning: variable does not need to be mutable
   --> src/lib.rs:214:17
    |
214 |             let mut d = dungeon.add_room(room.as_str()).unwrap();
    |                 ----^
    |                 |
    |                 help: remove this `mut`
    |
    = note: `#[warn(unused_mut)]` on by default

warning: variable does not need to be mutable
   --> src/lib.rs:270:17
    |
270 |             let mut north: String = String::from("North");
    |                 ----^^^^^
    |                 |
    |                 help: remove this `mut`

warning: variable does not need to be mutable
   --> src/lib.rs:271:17
    |
271 |             let mut south: String = String::from("South");
    |                 ----^^^^^
    |                 |
    |                 help: remove this `mut`

warning: variable does not need to be mutable
   --> src/lib.rs:272:17
    |
272 |             let mut west: String = String::from("West");
    |                 ----^^^^
    |                 |
    |                 help: remove this `mut`

warning: variable does not need to be mutable
   --> src/lib.rs:273:17
    |
273 |             let mut east: String = String::from("East");
    |                 ----^^^^
    |                 |
    |                 help: remove this `mut`

warning: variable does not need to be mutable
   --> src/lib.rs:387:13
    |
387 |         let mut hasParent: bool = true;
    |             ----^^^^^^^^^
    |             |
    |             help: remove this `mut`

warning: variable does not need to be mutable
   --> src/lib.rs:389:13
    |
389 |         let mut parcp = connections.get(&par).unwrap().clone();
    |             ----^^^^^
    |             |
    |             help: remove this `mut`

warning: function is never used: `main`
   --> src/lib.rs:410:4
    |
410 | fn main() {}
    |    ^^^^
    |
    = note: `#[warn(dead_code)]` on by default

warning: `solution` (lib) generated 13 warnings
    Finished test [unoptimized + debuginfo] target(s) in 4.25s
     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 ... 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_no_path stdout ----
thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/lib.rs:380:14
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

---- solution_test::test_invalid_parsing stdout ----
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: UnknownRoom("Closet")', /tmp/d20220116-3533338-1v2rfns/solution/src/lib.rs:302:18

---- 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-1v2rfns/solution/src/lib.rs:176:28
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "fill_buf error!" }', tests/solution_test.rs:194:5


failures:
    solution_test::test_finding_no_path
    solution_test::test_invalid_parsing
    solution_test::test_io_error

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

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

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

Иван качи първо решение на 10.01.2022 20:14 (преди над 3 години)