···
1
+
use std::{fs::File, io::Read, path::Path};
4
+
pub enum ParserError {
11
+
impl From<std::io::Error> for ParserError {
12
+
fn from(value: std::io::Error) -> Self {
13
+
ParserError::IO(value)
17
+
#[derive(Debug, PartialEq, Eq)]
18
+
pub struct Vector2u16 {
24
+
pub fn new(x: u16, y: u16) -> Self {
25
+
Vector2u16 {x: x, y: y}
29
+
#[derive(Debug, PartialEq, Eq)]
31
+
first_pos: Vector2u16,
32
+
last_pos: Vector2u16,
36
+
pub fn new(first_pos: Vector2u16, last_pos: Vector2u16) -> Self {
37
+
Boat { first_pos: first_pos, last_pos: last_pos }
41
+
pub fn parse_file(file_path: &Path) -> Result<[Boat; 4], ParserError> {
42
+
let mut file = File::open(file_path)?;
43
+
Ok(parse_ships(&mut file)?)
46
+
pub fn parse_ships<T: Read>(file: &mut T) -> Result<[Boat; 4], ParserError> {
47
+
let mut content = String::new();
49
+
file.read_to_string(&mut content)?;
50
+
let lines: Vec<&str> = content.lines().collect();
52
+
if lines.len() != 4 {
53
+
return Err(ParserError::InvalidShipCount);
57
+
create_ship(lines[0])?,
58
+
create_ship(lines[1])?,
59
+
create_ship(lines[2])?,
60
+
create_ship(lines[3])?,
66
+
fn create_ship(line: &str) -> Result<Boat, ParserError> {
67
+
let coordinates: Vec<&str> = line.split(":").collect();
69
+
if coordinates.len() != 2 {
70
+
return Err(ParserError::InvalidCoordCount);
74
+
Ok(Boat::new(create_coord(coordinates[0])?, create_coord(coordinates[1])?))
77
+
fn create_coord(coord_str: &str) -> Result<Vector2u16, ParserError> {
78
+
let mut str_iter = coord_str.chars();
80
+
let Some(col_c) = str_iter.next() else {
81
+
return Err(ParserError::InvalidCoord);
83
+
let col = (col_c as u16) - ('A' as u16);
85
+
let Some(row_c) = str_iter.next() else {
86
+
return Err(ParserError::InvalidCoord);
88
+
let row = (row_c as u16) - ('0' as u16) - 1;
90
+
if col > 7 || row > 7 {
91
+
return Err(ParserError::InvalidCoord);
94
+
Ok(Vector2u16::new(col, row))
103
+
fn test_create_coord() -> Result<(), ParserError> {
104
+
let coord1 = create_coord("D5")?;
106
+
assert_eq!(coord1.x, 3);
107
+
assert_eq!(coord1.y, 4);
109
+
let coord2 = create_coord("A1")?;
111
+
assert_eq!(coord2.x, 0);
112
+
assert_eq!(coord2.y, 0);
114
+
let coord3 = create_coord("H8")?;
116
+
assert_eq!(coord3.x, 7);
117
+
assert_eq!(coord3.y, 7);
123
+
fn test_create_install_coord() {
124
+
let coord = create_coord("G9");
126
+
assert!(coord.is_err());
130
+
fn test_create_bad_coord() {
131
+
let coord = create_coord("bad");
133
+
assert!(coord.is_err());
137
+
fn test_create_ship() -> Result<(), ParserError> {
138
+
let ship = create_ship("C4:B1")?;
140
+
assert_eq!(ship.first_pos.x, 2);
141
+
assert_eq!(ship.first_pos.y, 3);
142
+
assert_eq!(ship.last_pos.x, 1);
143
+
assert_eq!(ship.last_pos.y, 0);
148
+
fn test_create_bad_ship() {
149
+
let ship = create_ship("invalid");
150
+
assert!(ship.is_err());
152
+
let ship2 = create_ship("C9:B4");
153
+
assert!(ship2.is_err());
157
+
fn test_parse_ships() -> Result<(), ParserError> {
158
+
let file = b"B4:C2\nD1:F3\nF1:F5\nA1:A2";
160
+
let ships = parse_ships(&mut &file[..])?;
162
+
assert_eq!(ships[0], Boat::new(Vector2u16::new(1, 3), Vector2u16::new(2, 1)));
163
+
assert_eq!(ships[1], Boat::new(Vector2u16::new(3, 0), Vector2u16::new(5, 2)));
164
+
assert_eq!(ships[2], Boat::new(Vector2u16::new(5, 0), Vector2u16::new(5, 4)));
165
+
assert_eq!(ships[3], Boat::new(Vector2u16::new(0, 0), Vector2u16::new(0, 1)));