battleship game in rust

Parse ships files #2

merged opened by pebloop.dev targeting main from feat-parse-file

Add module that parse ships files

Labels

None yet.

Participants 1
AT URI
at://did:plc:zz6iwrmsqw6q4bsrgxicg2wu/sh.tangled.repo.pull/3lt7xdais6x22
+185
Diff #0
+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
sign up or login to add to the discussion
pebloop.dev submitted #0
2 commits
expand
Add ships parser
Format document
expand 0 comments
pull request successfully merged