Add module that parse ships files
+185
src/parser.rs
+185
src/parser.rs
···
1
+
use std::{fs::File, io::Read, path::Path};
2
+
3
+
#[derive(Debug)]
4
+
pub enum ParserError {
5
+
InvalidShipCount,
6
+
InvalidCoordCount,
7
+
InvalidCoord,
8
+
IO(std::io::Error),
9
+
}
10
+
11
+
impl From<std::io::Error> for ParserError {
12
+
fn from(value: std::io::Error) -> Self {
13
+
ParserError::IO(value)
14
+
}
15
+
}
16
+
17
+
#[derive(Debug, PartialEq, Eq)]
18
+
pub struct Vector2u16 {
19
+
x: u16,
20
+
y: u16,
21
+
}
22
+
23
+
impl Vector2u16 {
24
+
pub fn new(x: u16, y: u16) -> Self {
25
+
Vector2u16 { x: x, y: y }
26
+
}
27
+
}
28
+
29
+
#[derive(Debug, PartialEq, Eq)]
30
+
pub struct Boat {
31
+
first_pos: Vector2u16,
32
+
last_pos: Vector2u16,
33
+
}
34
+
35
+
impl Boat {
36
+
pub fn new(first_pos: Vector2u16, last_pos: Vector2u16) -> Self {
37
+
Boat {
38
+
first_pos: first_pos,
39
+
last_pos: last_pos,
40
+
}
41
+
}
42
+
}
43
+
44
+
pub fn parse_file(file_path: &Path) -> Result<[Boat; 4], ParserError> {
45
+
let mut file = File::open(file_path)?;
46
+
Ok(parse_ships(&mut file)?)
47
+
}
48
+
49
+
pub fn parse_ships<T: Read>(file: &mut T) -> Result<[Boat; 4], ParserError> {
50
+
let mut content = String::new();
51
+
52
+
file.read_to_string(&mut content)?;
53
+
let lines: Vec<&str> = content.lines().collect();
54
+
55
+
if lines.len() != 4 {
56
+
return Err(ParserError::InvalidShipCount);
57
+
}
58
+
59
+
let boats = [
60
+
create_ship(lines[0])?,
61
+
create_ship(lines[1])?,
62
+
create_ship(lines[2])?,
63
+
create_ship(lines[3])?,
64
+
];
65
+
66
+
Ok(boats)
67
+
}
68
+
69
+
fn create_ship(line: &str) -> Result<Boat, ParserError> {
70
+
let coordinates: Vec<&str> = line.split(":").collect();
71
+
72
+
if coordinates.len() != 2 {
73
+
return Err(ParserError::InvalidCoordCount);
74
+
}
75
+
76
+
Ok(Boat::new(
77
+
create_coord(coordinates[0])?,
78
+
create_coord(coordinates[1])?,
79
+
))
80
+
}
81
+
82
+
fn create_coord(coord_str: &str) -> Result<Vector2u16, ParserError> {
83
+
let mut str_iter = coord_str.chars();
84
+
85
+
let Some(col_c) = str_iter.next() else {
86
+
return Err(ParserError::InvalidCoord);
87
+
};
88
+
let col = (col_c as u16) - ('A' as u16);
89
+
90
+
let Some(row_c) = str_iter.next() else {
91
+
return Err(ParserError::InvalidCoord);
92
+
};
93
+
let row = (row_c as u16) - ('0' as u16) - 1;
94
+
95
+
if col > 7 || row > 7 {
96
+
return Err(ParserError::InvalidCoord);
97
+
}
98
+
99
+
Ok(Vector2u16::new(col, row))
100
+
}
101
+
102
+
#[cfg(test)]
103
+
mod tests {
104
+
use super::*;
105
+
106
+
#[test]
107
+
fn test_create_coord() -> Result<(), ParserError> {
108
+
let coord1 = create_coord("D5")?;
109
+
110
+
assert_eq!(coord1.x, 3);
111
+
assert_eq!(coord1.y, 4);
112
+
113
+
let coord2 = create_coord("A1")?;
114
+
115
+
assert_eq!(coord2.x, 0);
116
+
assert_eq!(coord2.y, 0);
117
+
118
+
let coord3 = create_coord("H8")?;
119
+
120
+
assert_eq!(coord3.x, 7);
121
+
assert_eq!(coord3.y, 7);
122
+
123
+
Ok(())
124
+
}
125
+
126
+
#[test]
127
+
fn test_create_install_coord() {
128
+
let coord = create_coord("G9");
129
+
130
+
assert!(coord.is_err());
131
+
}
132
+
133
+
#[test]
134
+
fn test_create_bad_coord() {
135
+
let coord = create_coord("bad");
136
+
137
+
assert!(coord.is_err());
138
+
}
139
+
140
+
#[test]
141
+
fn test_create_ship() -> Result<(), ParserError> {
142
+
let ship = create_ship("C4:B1")?;
143
+
144
+
assert_eq!(ship.first_pos.x, 2);
145
+
assert_eq!(ship.first_pos.y, 3);
146
+
assert_eq!(ship.last_pos.x, 1);
147
+
assert_eq!(ship.last_pos.y, 0);
148
+
Ok(())
149
+
}
150
+
151
+
#[test]
152
+
fn test_create_bad_ship() {
153
+
let ship = create_ship("invalid");
154
+
assert!(ship.is_err());
155
+
156
+
let ship2 = create_ship("C9:B4");
157
+
assert!(ship2.is_err());
158
+
}
159
+
160
+
#[test]
161
+
fn test_parse_ships() -> Result<(), ParserError> {
162
+
let file = b"B4:C2\nD1:F3\nF1:F5\nA1:A2";
163
+
164
+
let ships = parse_ships(&mut &file[..])?;
165
+
166
+
assert_eq!(
167
+
ships[0],
168
+
Boat::new(Vector2u16::new(1, 3), Vector2u16::new(2, 1))
169
+
);
170
+
assert_eq!(
171
+
ships[1],
172
+
Boat::new(Vector2u16::new(3, 0), Vector2u16::new(5, 2))
173
+
);
174
+
assert_eq!(
175
+
ships[2],
176
+
Boat::new(Vector2u16::new(5, 0), Vector2u16::new(5, 4))
177
+
);
178
+
assert_eq!(
179
+
ships[3],
180
+
Boat::new(Vector2u16::new(0, 0), Vector2u16::new(0, 1))
181
+
);
182
+
183
+
Ok(())
184
+
}
185
+
}
History
1 round
0 comments
pebloop.dev
submitted
#0
expand 0 comments
pull request successfully merged