Решение на Dungeons and Compilers от Цветелина Чакърова

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

Към профила на Цветелина Чакърова

Резултати

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

Код

use std::collections::HashMap;
use std::collections::HashSet;
use std::collections::VecDeque;
use std::hash::Hash;
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, PartialEq, Eq, Hash)]
pub enum Direction {
North,
South,
East,
West,
}
#[derive(PartialEq)]
pub struct Room {
pub name: String,
pub neighbours: HashMap<Direction, String>,
}
pub struct Dungeon {
pub rooms: Vec<Room>,
}
impl Dungeon {
pub fn new() -> Self {
let rooms = Vec::new();
Dungeon { rooms }
}
pub fn add_room(&mut self, name: &str) -> Result<(), Errors> {
let mut flag: bool = false;
for index in 0..self.rooms.len() {
if self.rooms[index].name == name {
flag = true;
}
}
if flag == true {
return Err(Errors::DuplicateRoom(String::from(name)));
} else {
let nb: HashMap<Direction, String> = HashMap::new();
let room = Room {
name: String::from(name),
neighbours: nb,
};
self.rooms.push(room);
Ok(())
}
}
pub fn get_room(&self, room_name: &str) -> Result<&Room, Errors> {
let mut room = &self.rooms[0];
let mut flag: bool = false;
for index in 0..self.rooms.len() {
if self.rooms[index].name == room_name {
flag = true;
room = &self.rooms[index];
}
}
if flag == false {
return Err(Errors::UnknownRoom(String::from(room_name)));
} else {
Ok(room)
}
}
pub fn set_link(
&mut self,
room_name: &str,
direction: Direction,
other_room_name: &str,
) -> Result<(), Errors> {
let mut flag_room: bool = false;
let mut flag_other_room: bool = false;
let mut index_room = 0;
let mut index_other_room = 0;
for index in 0..self.rooms.len() {
if self.rooms[index].name == room_name {
flag_room = true;
index_room = index;
}
if self.rooms[index].name == other_room_name {
flag_other_room = true;
index_other_room = index;
}
}
if flag_room == false {
return Err(Errors::UnknownRoom(String::from(room_name)));
} else if flag_other_room == false {
return Err(Errors::UnknownRoom(String::from(other_room_name)));
} else {
self.rooms[index_room]
.neighbours
.insert(direction, String::from(other_room_name));
if direction == Direction::North {
self.rooms[index_other_room]
.neighbours
.insert(Direction::South, String::from(room_name));
}
if direction == Direction::South {
self.rooms[index_other_room]
.neighbours
.insert(Direction::North, String::from(room_name));
}
if direction == Direction::West {
self.rooms[index_other_room]
.neighbours
.insert(Direction::East, String::from(room_name));
}
if direction == Direction::East {
self.rooms[index_other_room]
.neighbours
.insert(Direction::West, String::from(room_name));
}
Ok(())
}
}
pub fn get_next_room(
&self,
room_name: &str,
direction: Direction,
) -> Result<Option<&Room>, Errors> {
let mut flag: bool = false;
let mut index_room = 0;
for index in 0..self.rooms.len() {
if self.rooms[index].name == room_name {
flag = true;
index_room = index;
}
}
if flag == false {
return Err(Errors::UnknownRoom(String::from(room_name)));
} else if self.rooms[index_room].neighbours.get(&direction) == None {
Ok(None)
} else {
let other_room_name = self.rooms[index_room].neighbours.get(&direction).unwrap();
let mut room = &self.rooms[0];
for index in 0..self.rooms.len() {
if self.rooms[index].name == String::from(other_room_name) {
room = &self.rooms[index];
}
}
Ok(Some(room))
}
}
}
impl Dungeon {
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors> {
let mut dungeon = Dungeon::new();
let mut mut_reader: B = reader;
let mut file_contents = String::new();
mut_reader
.read_to_string(&mut file_contents)
.ok()
.expect("failed to read!");
let lines: Vec<String> = file_contents
.split("\n")
.map(|s: &str| s.to_string())
.collect();
if lines[0] != "## Rooms" {
return Err(Errors::LineParseError { line_number: 1 });
}
let mut current_line = 2;
let mut lines_index = 1;
let mut current_string = "".to_string();
while lines[lines_index] != "" {
let chars: Vec<char> = lines[lines_index].chars().collect();
current_string += &chars[0].to_string();
current_string += &chars[1].to_string();
if current_string != "- " {
return Err(Errors::LineParseError {
line_number: current_line,
});
} else {
let mut name = "".to_string();
let mut chars_index = 2;
while chars_index < chars.len() {
name += &chars[chars_index].to_string();
chars_index += 1;
}
if let Err(e) = dungeon.add_room(&name) {
return Err(e.into());
}
}
lines_index += 1;
current_line += 1;
current_string = "".to_string();
}
lines_index += 1;
current_line += 1;
current_string = "".to_string();
if lines[lines_index] != "## Links" {
return Err(Errors::LineParseError {
line_number: current_line,
});
}
lines_index += 1;
current_line += 1;
while lines_index < lines.len() {
let chars: Vec<char> = lines[lines_index].chars().collect();
current_string += &chars[0].to_string();
current_string += &chars[1].to_string();
if current_string != "- " {
return Err(Errors::LineParseError {
line_number: current_line,
});
} else {
let mut chars_index;
let mut first_arrow_begin = 0;
let mut second_arrow_begin = 0;
chars_index = 2;
while chars_index <= chars.len() - 4 {
let mut current_string = "".to_string();
current_string += &chars[chars_index].to_string();
if current_string == " ".to_string() {
current_string += &chars[chars_index + 1].to_string();
current_string += &chars[chars_index + 2].to_string();
current_string += &chars[chars_index + 3].to_string();
if current_string == " -> ".to_string() {
if first_arrow_begin == 0 {
first_arrow_begin = chars_index;
} else if first_arrow_begin != 0 && second_arrow_begin == 0 {
second_arrow_begin = chars_index;
}
chars_index += 4
} else {
chars_index += 1;
}
} else {
chars_index += 1;
}
}
if first_arrow_begin == 0 || second_arrow_begin == 0 {
{
return Err(Errors::LineParseError {
line_number: current_line,
});
}
} else {
let mut name = "".to_string();
let mut direction = "".to_string();
let mut other_name = "".to_string();
chars_index = 2;
while chars_index < first_arrow_begin {
name += &chars[chars_index].to_string();
chars_index += 1;
}
chars_index += 4;
while chars_index < second_arrow_begin {
direction += &chars[chars_index].to_string();
chars_index += 1;
}
chars_index += 4;
while chars_index < chars.len() {
other_name += &chars[chars_index].to_string();
chars_index += 1;
}
chars_index += 4;
if direction != "North"
&& direction != "South"
&& direction != "East"
&& direction != "West"
{
return Err(Errors::DirectionParseError(String::from(direction)));
} else {
if direction == "North" {
if let Err(e) = dungeon.set_link(&name, Direction::North, &other_name) {
return Err(e.into());
}
}
if direction == "South" {
if let Err(e) = dungeon.set_link(&name, Direction::South, &other_name) {
return Err(e.into());
}
}
if direction == "West" {
if let Err(e) = dungeon.set_link(&name, Direction::West, &other_name) {
return Err(e.into());
}
}
if direction == "East" {
if let Err(e) = dungeon.set_link(&name, Direction::East, &other_name) {
return Err(e.into());
}
}
}
}
}
lines_index += 1;
current_line += 1;
current_string = "".to_string();
}
Ok(dungeon)
}
}
impl Dungeon {
pub fn find_path(
&self,
start_room_name: &str,
end_room_name: &str,
) -> Result<Option<Vec<&Room>>, Errors> {
let mut flag_start : bool = false;
let mut flag_end : bool = false;
for index in 0..self.rooms.len() {
if self.rooms[index].name == start_room_name {
flag_start = true;
};
if self.rooms[index].name == end_room_name {
flag_end = true
};
}
if flag_start == false {
return Err(Errors::UnknownRoom(String::from(start_room_name)));
}
if flag_end == false {
return Err(Errors::UnknownRoom(String::from(end_room_name)));
}
let mut edges: Vec<Vec<usize>> = Vec::new();
for index in 0..self.rooms.len() {
edges.push(Vec::new());
for (key, value) in self.rooms[index].neighbours.iter() {
for index2 in 0..self.rooms.len() {
if self.rooms[index2].name == *value {
edges[index].push(index2);
}
}
}
}
let mut start_room_index = 0;
let mut end_room_index = 0;
for index in 0..self.rooms.len() {
if self.rooms[index].name == start_room_name {
start_room_index = index
};
if self.rooms[index].name == end_room_name {
end_room_index = index
};
}
let graph: Vec<HashSet<usize>> = {
let mut graph: Vec<HashSet<usize>> = vec![HashSet::new(); self.rooms.len()];
for index in 0..edges.len() {
for index2 in 0..edges[index].len() {
graph[index].insert(edges[index][index2]);
graph[edges[index][index2]].insert(index);
}
}
graph
};
let mut visited: HashSet<usize> = HashSet::with_capacity(self.rooms.len());
visited.insert(start_room_index);
let mut path: Vec<&Room> = Vec::new();
path.push(&self.rooms[start_room_index]);
let mut flag : bool = false;
let mut create_path: VecDeque<usize> = VecDeque::with_capacity(self.rooms.len());
create_path.push_back(start_room_index);
while create_path.is_empty() == false {
for index in 0..create_path.len() {
if let Some(current_node) = create_path.pop_front() {
if current_node == end_room_index {
flag = true;
}
for &index2 in graph[current_node].iter() {
if visited.insert(index2) == true {
path.push(&self.rooms[index2]);
create_path.push_back(index2);
}
}
}
}
}
if flag == false {
return Ok(None);
} else {
return Ok(Some(path));
}
}
}

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

Compiling solution v0.1.0 (/tmp/d20220116-3533338-1abrw1x/solution)
warning: value assigned to `chars_index` is never read
   --> src/lib.rs:286:21
    |
286 |                     chars_index += 4;
    |                     ^^^^^^^^^^^
    |
    = note: `#[warn(unused_assignments)]` on by default
    = help: maybe it is overwritten before being read?

warning: unused variable: `key`
   --> src/lib.rs:356:18
    |
356 |             for (key, value) in self.rooms[index].neighbours.iter() {
    |                  ^^^ help: if this is intentional, prefix it with an underscore: `_key`
    |
    = note: `#[warn(unused_variables)]` on by default

warning: unused variable: `index`
   --> src/lib.rs:398:17
    |
398 |             for index in 0..create_path.len() {
    |                 ^^^^^ help: if this is intentional, prefix it with an underscore: `_index`

warning: `solution` (lib) generated 3 warnings
    Finished test [unoptimized + debuginfo] target(s) in 5.49s
     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 ... ok
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_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
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- solution_test::test_io_error stdout ----
thread '<unnamed>' panicked at 'failed to read!', /tmp/d20220116-3533338-1abrw1x/solution/src/lib.rs:171:14
thread 'main' panicked at 'failed to read!', tests/solution_test.rs:194:5

---- solution_test::test_parsing_no_rooms_or_links stdout ----
thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', src/lib.rs:62:25


failures:
    solution_test::test_invalid_parsing
    solution_test::test_io_error
    solution_test::test_parsing_no_rooms_or_links

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 01:00 (преди почти 4 години)