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

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

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

Резултати

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

Код

use std::{io::BufRead, collections::{HashMap, VecDeque}};
#[derive(Debug)]
pub enum Errors
{
DuplicateRoom(String),
UnknownRoom(String),
IoError(std::io::Error),
LineParseError { line_number: usize },
DirectionParseError(String),
}
#[derive(Clone, Copy)]
pub enum Direction
{
North = 0,
South = 1,
East = 2,
West = 3,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum ParsingStage
{
None = 0, Rooms = 1, Links = 2, Transition = 3
}
impl Direction
{
pub fn GetOppositeDirection(direction: Direction) -> Direction
{
match direction
{
Direction::North => return Direction::South,
Direction::South => return Direction::North,
Direction::East => return Direction::West,
Direction::West => return Direction::East
}
}
pub fn FromString(str: &str) -> Option<Direction>
{
match str
{
"North" => return Some(Direction::North),
"South" => return Some(Direction::South),
"East" => return Some(Direction::East),
"West" => return Some(Direction::West),
_ => return None
}
}
}
pub struct Room
{
pub name: String,
pub Neighbours: [Option<String>; 4]
}
pub struct Dungeon
{
m_Rooms: HashMap<String, Room>
}
impl Dungeon
{
pub fn new() -> Self
{
return Self {
m_Rooms: HashMap::new()
};
}
pub fn add_room(&mut self, name: &str) -> Result<(), Errors>
{
if !self.m_Rooms.contains_key(name)
{
let name: String = String::from(name);
let room: Room = Room
{
name: name.clone(),
Neighbours: [None, None, None, None]
};
self.m_Rooms.insert(name, room);
return Ok(());
}
else
{
return Err(Errors::DuplicateRoom(String::from(name)));
}
}
pub fn get_room(&self, name: &str) -> Result<&Room, Errors>
{
if self.m_Rooms.contains_key(name)
{
return Ok(self.m_Rooms.get(name).unwrap());
}
else
{
return Err(Errors::UnknownRoom(String::from(name)));
}
}
pub fn set_link(&mut self, name: &str, direction: Direction, neighbourName: &str) -> Result<(), Errors>
{
if self.m_Rooms.contains_key(name)
{
if self.m_Rooms.contains_key(neighbourName)
{
let oppositeDirection: Direction = Direction::GetOppositeDirection(direction);
self.m_Rooms.get_mut(name).unwrap().Neighbours[direction as usize] = Some(String::from(neighbourName));
self.m_Rooms.get_mut(neighbourName).unwrap().Neighbours[oppositeDirection as usize] = Some(String::from(name));
return Ok(());
}
else
{
return Err(Errors::UnknownRoom(String::from(neighbourName)));
}
}
else
{
return Err(Errors::UnknownRoom(String::from(name)));
}
}
pub fn get_next_room(&self, name: &str, direction: Direction) -> Result<Option<&Room>, Errors>
{
if self.m_Rooms.contains_key(name)
{
let room: &Room = self.m_Rooms.get(name).unwrap();
if room.Neighbours[direction as usize].is_some()
{
let neighbourName: &String = room.Neighbours[direction as usize].as_ref().unwrap();
let room: &Room = self.m_Rooms.get(neighbourName).unwrap();
return Ok(Some(room));
}
else
{
return Ok(None);
}
}
else
{
return Err(Errors::UnknownRoom(String::from(name)));
}
}
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors>
{
let mut parsingStage: ParsingStage = ParsingStage::None;
let mut lineIndex: usize = 1;
let mut dungeon: Dungeon = Dungeon::new();
for line in reader.lines()
{
if line.is_ok()
{
let mut line: String = line.unwrap();
if line == "## Rooms"
{
if parsingStage != ParsingStage::None
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
parsingStage = ParsingStage::Rooms;
}
else if line == "## Links"
{
if parsingStage != ParsingStage::Transition
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
parsingStage = ParsingStage::Links;
}
else if line.is_empty()
{
if parsingStage != ParsingStage::Rooms
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
parsingStage = ParsingStage::Transition;
}
else if &line[0..2] == "- "
{
line.replace_range(0..2, "");
let tokens: Vec<&str> = line.split(" -> ").collect();
match parsingStage
{
ParsingStage::Rooms =>
{
if tokens.len() != 1
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
let roomName: &str = tokens[0].trim();
if let Err(error) = dungeon.add_room(roomName)
{
return Err(error);
}
},
ParsingStage::Links =>
{
if tokens.len() != 3
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
let roomName: &str = tokens[0].trim();
let direction: Option<Direction> = Direction::FromString(tokens[1].trim());
let neighbourName: &str = tokens[2].trim();
if direction.is_none()
{
return Err(Errors::DirectionParseError(String::from(tokens[1])));
}
if let Err(error) = dungeon.set_link(roomName, direction.unwrap(), neighbourName)
{
return Err(error);
}
}
_ =>
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
}
}
else
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
lineIndex += 1;
}
else
{
return Err(Errors::IoError(line.err().unwrap()));
}
}
return Ok(dungeon);
}
pub fn find_path(&self, startRoomName: &str, endRoomName: &str) -> Result<Option<Vec<&Room>>, Errors>
{
if let Err(error) = self.get_room(startRoomName)
{
return Err(error);
}
if let Err(error) = self.get_room(endRoomName)
{
return Err(error);
}
if startRoomName == endRoomName
{
return Ok(Some(vec![self.get_room(startRoomName).unwrap()]));
}
let mut parents: HashMap<String, Option<String>> = HashMap::new();
for entry in self.m_Rooms.iter()
{
parents.insert(entry.0.clone(), None);
}
let mut visited: HashMap<String, bool> = HashMap::new();
for entry in self.m_Rooms.iter()
{
visited.insert(entry.0.clone(), false);
}
let mut queue: VecDeque<&Room> = VecDeque::new();
let startRoom: &Room = self.get_room(startRoomName).unwrap();
queue.push_back(startRoom);
*visited.get_mut(&startRoom.name).unwrap() = true;
while !queue.is_empty()
{
let currentRoom: &Room = queue.remove(0).unwrap();
if currentRoom.name == endRoomName
{
break;
}
for neighbour in currentRoom.Neighbours.iter()
{
if neighbour.is_some()
{
let neighbour: &String = neighbour.as_ref().unwrap();
if visited[neighbour] == false
{
*parents.get_mut(neighbour).unwrap() = Some(currentRoom.name.clone());
*visited.get_mut(neighbour).unwrap() = true;
let neighbourRoom = self.get_room(neighbour);
if neighbourRoom.is_err()
{
return Err(neighbourRoom.err().unwrap());
}
queue.push_back(neighbourRoom.unwrap());
}
}
}
}
if parents[endRoomName] == None
{
return Ok(None);
}
let mut path: Vec<&Room> = Vec::new();
path.push(self.get_room(endRoomName).unwrap());
let mut currentRoomName = parents.get(endRoomName).unwrap();
while currentRoomName.is_some()
{
let currentRoomNameStr = currentRoomName.as_ref().unwrap();
let currentRoom = self.get_room(currentRoomNameStr.as_str());
if currentRoom.is_err()
{
return Err(currentRoom.err().unwrap());
}
path.push(currentRoom.unwrap());
currentRoomName = parents.get(currentRoomNameStr).unwrap();
}
path.reverse();
return Ok(Some(path));
}
}

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

Compiling solution v0.1.0 (/tmp/d20220116-3533338-1m2k5sk/solution)
warning: method `GetOppositeDirection` should have a snake case name
  --> src/lib.rs:30:12
   |
30 |     pub fn GetOppositeDirection(direction: Direction) -> Direction
   |            ^^^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `get_opposite_direction`
   |
   = note: `#[warn(non_snake_case)]` on by default

warning: method `FromString` should have a snake case name
  --> src/lib.rs:41:12
   |
41 |     pub fn FromString(str: &str) -> Option<Direction>
   |            ^^^^^^^^^^ help: convert the identifier to snake case: `from_string`

warning: structure field `Neighbours` should have a snake case name
  --> src/lib.rs:57:9
   |
57 |     pub Neighbours: [Option<String>; 4]
   |         ^^^^^^^^^^ help: convert the identifier to snake case: `neighbours`

warning: structure field `m_Rooms` should have a snake case name
  --> src/lib.rs:62:5
   |
62 |     m_Rooms: HashMap<String, Room>
   |     ^^^^^^^ help: convert the identifier to snake case: `m_rooms`

warning: variable `neighbourName` should have a snake case name
   --> src/lib.rs:108:66
    |
108 |     pub fn set_link(&mut self, name: &str, direction: Direction, neighbourName: &str) -> Result<(), Errors> 
    |                                                                  ^^^^^^^^^^^^^ help: convert the identifier to snake case: `neighbour_name`

warning: variable `oppositeDirection` should have a snake case name
   --> src/lib.rs:114:21
    |
114 |                 let oppositeDirection: Direction = Direction::GetOppositeDirection(direction);
    |                     ^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `opposite_direction`

warning: variable `neighbourName` should have a snake case name
   --> src/lib.rs:140:21
    |
140 |                 let neighbourName: &String = room.Neighbours[direction as usize].as_ref().unwrap();
    |                     ^^^^^^^^^^^^^ help: convert the identifier to snake case: `neighbour_name`

warning: variable `parsingStage` should have a snake case name
   --> src/lib.rs:158:17
    |
158 |         let mut parsingStage: ParsingStage = ParsingStage::None;
    |                 ^^^^^^^^^^^^ help: convert the identifier to snake case: `parsing_stage`

warning: variable `lineIndex` should have a snake case name
   --> src/lib.rs:159:17
    |
159 |         let mut lineIndex: usize = 1;
    |                 ^^^^^^^^^ help: convert the identifier to snake case: `line_index`

warning: variable `roomName` should have a snake case name
   --> src/lib.rs:210:33
    |
210 | ...                   let roomName: &str = tokens[0].trim();
    |                           ^^^^^^^^ help: convert the identifier to snake case: `room_name`

warning: variable `roomName` should have a snake case name
   --> src/lib.rs:225:33
    |
225 | ...                   let roomName: &str = tokens[0].trim();
    |                           ^^^^^^^^ help: convert the identifier to snake case: `room_name`

warning: variable `neighbourName` should have a snake case name
   --> src/lib.rs:227:33
    |
227 | ...                   let neighbourName: &str = tokens[2].trim();
    |                           ^^^^^^^^^^^^^ help: convert the identifier to snake case: `neighbour_name`

warning: variable `startRoomName` should have a snake case name
   --> src/lib.rs:262:29
    |
262 |     pub fn find_path(&self, startRoomName: &str, endRoomName: &str) -> Result<Option<Vec<&Room>>, Errors> 
    |                             ^^^^^^^^^^^^^ help: convert the identifier to snake case: `start_room_name`

warning: variable `endRoomName` should have a snake case name
   --> src/lib.rs:262:50
    |
262 |     pub fn find_path(&self, startRoomName: &str, endRoomName: &str) -> Result<Option<Vec<&Room>>, Errors> 
    |                                                  ^^^^^^^^^^^ help: convert the identifier to snake case: `end_room_name`

warning: variable `startRoom` should have a snake case name
   --> src/lib.rs:291:13
    |
291 |         let startRoom: &Room = self.get_room(startRoomName).unwrap();
    |             ^^^^^^^^^ help: convert the identifier to snake case: `start_room`

warning: variable `currentRoom` should have a snake case name
   --> src/lib.rs:297:17
    |
297 |             let currentRoom: &Room = queue.remove(0).unwrap();
    |                 ^^^^^^^^^^^ help: convert the identifier to snake case: `current_room`

warning: variable `neighbourRoom` should have a snake case name
   --> src/lib.rs:315:29
    |
315 |                         let neighbourRoom = self.get_room(neighbour);
    |                             ^^^^^^^^^^^^^ help: convert the identifier to snake case: `neighbour_room`

warning: variable `currentRoomName` should have a snake case name
   --> src/lib.rs:336:17
    |
336 |         let mut currentRoomName = parents.get(endRoomName).unwrap();
    |                 ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `current_room_name`

warning: variable `currentRoomNameStr` should have a snake case name
   --> src/lib.rs:339:17
    |
339 |             let currentRoomNameStr = currentRoomName.as_ref().unwrap();
    |                 ^^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `current_room_name_str`

warning: variable `currentRoom` should have a snake case name
   --> src/lib.rs:340:17
    |
340 |             let currentRoom = self.get_room(currentRoomNameStr.as_str());
    |                 ^^^^^^^^^^^ help: convert the identifier to snake case: `current_room`

warning: `solution` (lib) generated 20 warnings
    Finished test [unoptimized + debuginfo] target(s) in 4.34s
     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 ... 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_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


failures:
    solution_test::test_invalid_parsing

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'

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

Николай качи първо решение на 03.01.2022 20:51 (преди почти 4 години)

Николай качи решение на 03.01.2022 20:57 (преди почти 4 години)

use std::{io::BufRead, collections::{HashMap, VecDeque}};
#[derive(Debug)]
pub enum Errors
{
DuplicateRoom(String),
UnknownRoom(String),
IoError(std::io::Error),
LineParseError { line_number: usize },
DirectionParseError(String),
}
#[derive(Clone, Copy)]
pub enum Direction
{
North = 0,
South = 1,
East = 2,
West = 3,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum ParsingStage
{
None = 0, Rooms = 1, Links = 2, Transition = 3
}
impl Direction
{
pub fn GetOppositeDirection(direction: Direction) -> Direction
{
match direction
{
Direction::North => return Direction::South,
Direction::South => return Direction::North,
Direction::East => return Direction::West,
Direction::West => return Direction::East
}
}
pub fn FromString(str: &str) -> Option<Direction>
{
match str
{
"North" => return Some(Direction::North),
"South" => return Some(Direction::South),
"East" => return Some(Direction::East),
"West" => return Some(Direction::West),
_ => return None
}
}
}
pub struct Room
{
- pub Name: String,
+ pub name: String,
pub Neighbours: [Option<String>; 4]
}
pub struct Dungeon
{
m_Rooms: HashMap<String, Room>
}
impl Dungeon
{
pub fn new() -> Self
{
return Self {
m_Rooms: HashMap::new()
};
}
pub fn add_room(&mut self, name: &str) -> Result<(), Errors>
{
if !self.m_Rooms.contains_key(name)
{
let name: String = String::from(name);
let room: Room = Room
{
- Name: name.clone(),
+ name: name.clone(),
Neighbours: [None, None, None, None]
};
self.m_Rooms.insert(name, room);
return Ok(());
}
else
{
return Err(Errors::DuplicateRoom(String::from(name)));
}
}
pub fn get_room(&self, name: &str) -> Result<&Room, Errors>
{
if self.m_Rooms.contains_key(name)
{
return Ok(self.m_Rooms.get(name).unwrap());
}
else
{
return Err(Errors::UnknownRoom(String::from(name)));
}
}
pub fn set_link(&mut self, name: &str, direction: Direction, neighbourName: &str) -> Result<(), Errors>
{
if self.m_Rooms.contains_key(name)
{
if self.m_Rooms.contains_key(neighbourName)
{
let oppositeDirection: Direction = Direction::GetOppositeDirection(direction);
self.m_Rooms.get_mut(name).unwrap().Neighbours[direction as usize] = Some(String::from(neighbourName));
self.m_Rooms.get_mut(neighbourName).unwrap().Neighbours[oppositeDirection as usize] = Some(String::from(name));
return Ok(());
}
else
{
return Err(Errors::UnknownRoom(String::from(neighbourName)));
}
}
else
{
return Err(Errors::UnknownRoom(String::from(name)));
}
}
pub fn get_next_room(&self, name: &str, direction: Direction) -> Result<Option<&Room>, Errors>
{
if self.m_Rooms.contains_key(name)
{
let room: &Room = self.m_Rooms.get(name).unwrap();
if room.Neighbours[direction as usize].is_some()
{
let neighbourName: &String = room.Neighbours[direction as usize].as_ref().unwrap();
let room: &Room = self.m_Rooms.get(neighbourName).unwrap();
return Ok(Some(room));
}
else
{
return Ok(None);
}
}
else
{
return Err(Errors::UnknownRoom(String::from(name)));
}
}
pub fn from_reader<B: BufRead>(reader: B) -> Result<Self, Errors>
{
let mut parsingStage: ParsingStage = ParsingStage::None;
let mut lineIndex: usize = 1;
let mut dungeon: Dungeon = Dungeon::new();
for line in reader.lines()
{
if line.is_ok()
{
let mut line: String = line.unwrap();
if line == "## Rooms"
{
if parsingStage != ParsingStage::None
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
parsingStage = ParsingStage::Rooms;
}
else if line == "## Links"
{
if parsingStage != ParsingStage::Transition
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
parsingStage = ParsingStage::Links;
}
else if line.is_empty()
{
if parsingStage != ParsingStage::Rooms
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
parsingStage = ParsingStage::Transition;
}
else if &line[0..2] == "- "
{
line.replace_range(0..2, "");
let tokens: Vec<&str> = line.split(" -> ").collect();
match parsingStage
{
ParsingStage::Rooms =>
{
if tokens.len() != 1
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
let roomName: &str = tokens[0].trim();
if let Err(error) = dungeon.add_room(roomName)
{
return Err(error);
}
},
ParsingStage::Links =>
{
if tokens.len() != 3
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
let roomName: &str = tokens[0].trim();
let direction: Option<Direction> = Direction::FromString(tokens[1].trim());
let neighbourName: &str = tokens[2].trim();
if direction.is_none()
{
return Err(Errors::DirectionParseError(String::from(tokens[1])));
}
if let Err(error) = dungeon.set_link(roomName, direction.unwrap(), neighbourName)
{
return Err(error);
}
}
_ =>
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
}
}
else
{
return Err(Errors::LineParseError{ line_number: lineIndex });
}
lineIndex += 1;
}
else
{
return Err(Errors::IoError(line.err().unwrap()));
}
}
return Ok(dungeon);
}
pub fn find_path(&self, startRoomName: &str, endRoomName: &str) -> Result<Option<Vec<&Room>>, Errors>
{
if let Err(error) = self.get_room(startRoomName)
{
return Err(error);
}
if let Err(error) = self.get_room(endRoomName)
{
return Err(error);
}
if startRoomName == endRoomName
{
return Ok(Some(vec![self.get_room(startRoomName).unwrap()]));
}
let mut parents: HashMap<String, Option<String>> = HashMap::new();
for entry in self.m_Rooms.iter()
{
parents.insert(entry.0.clone(), None);
}
let mut visited: HashMap<String, bool> = HashMap::new();
for entry in self.m_Rooms.iter()
{
visited.insert(entry.0.clone(), false);
}
let mut queue: VecDeque<&Room> = VecDeque::new();
let startRoom: &Room = self.get_room(startRoomName).unwrap();
queue.push_back(startRoom);
- *visited.get_mut(&startRoom.Name).unwrap() = true;
+ *visited.get_mut(&startRoom.name).unwrap() = true;
while !queue.is_empty()
{
let currentRoom: &Room = queue.remove(0).unwrap();
- if currentRoom.Name == endRoomName
+ if currentRoom.name == endRoomName
{
break;
}
for neighbour in currentRoom.Neighbours.iter()
{
if neighbour.is_some()
{
let neighbour: &String = neighbour.as_ref().unwrap();
if visited[neighbour] == false
{
- *parents.get_mut(neighbour).unwrap() = Some(currentRoom.Name.clone());
+ *parents.get_mut(neighbour).unwrap() = Some(currentRoom.name.clone());
*visited.get_mut(neighbour).unwrap() = true;
let neighbourRoom = self.get_room(neighbour);
if neighbourRoom.is_err()
{
return Err(neighbourRoom.err().unwrap());
}
queue.push_back(neighbourRoom.unwrap());
}
}
}
}
if parents[endRoomName] == None
{
return Ok(None);
}
let mut path: Vec<&Room> = Vec::new();
path.push(self.get_room(endRoomName).unwrap());
let mut currentRoomName = parents.get(endRoomName).unwrap();
while currentRoomName.is_some()
{
let currentRoomNameStr = currentRoomName.as_ref().unwrap();
let currentRoom = self.get_room(currentRoomNameStr.as_str());
if currentRoom.is_err()
{
return Err(currentRoom.err().unwrap());
}
path.push(currentRoom.unwrap());
currentRoomName = parents.get(currentRoomNameStr).unwrap();
}
path.reverse();
return Ok(Some(path));
}
}