Add core game types #3

merged
opened by nasso.dev targeting main from nasso/push-syytxqpvzmuy
Changed files
+173 -27
src
+170
src/game.rs
···
··· 1 + use std::{ 2 + fmt::{Display, Formatter}, 3 + ops::{Index, IndexMut}, 4 + }; 5 + 6 + #[derive(Debug, PartialEq, Eq)] 7 + pub struct Vector2u16 { 8 + pub x: u16, 9 + pub y: u16, 10 + } 11 + 12 + impl Vector2u16 { 13 + pub fn new(x: u16, y: u16) -> Self { 14 + Vector2u16 { x, y } 15 + } 16 + } 17 + 18 + #[derive(Debug, PartialEq, Eq)] 19 + pub struct Boat { 20 + pub first_pos: Vector2u16, 21 + pub last_pos: Vector2u16, 22 + } 23 + 24 + impl Boat { 25 + pub fn new(first_pos: Vector2u16, last_pos: Vector2u16) -> Self { 26 + Boat { 27 + first_pos, 28 + last_pos, 29 + } 30 + } 31 + } 32 + 33 + #[derive(Debug, PartialEq, Eq)] 34 + pub struct Board { 35 + pub cells: [BoardCell; 64], 36 + } 37 + 38 + impl Display for Board { 39 + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 40 + writeln!(f, " | A B C D E F G H ")?; 41 + writeln!(f, "---+-----------------")?; 42 + 43 + for row in 1..=8 { 44 + writeln!( 45 + f, 46 + " {row} | {} {} {} {} {} {} {} {}", 47 + self.cells[8 * row - 1], 48 + self.cells[8 * row], 49 + self.cells[8 * row + 1], 50 + self.cells[8 * row + 2], 51 + self.cells[8 * row + 3], 52 + self.cells[8 * row + 4], 53 + self.cells[8 * row + 5], 54 + self.cells[8 * row + 6], 55 + )?; 56 + } 57 + 58 + Ok(()) 59 + } 60 + } 61 + 62 + impl Default for Board { 63 + fn default() -> Self { 64 + Self { 65 + cells: [Default::default(); 64], 66 + } 67 + } 68 + } 69 + 70 + impl Index<Vector2u16> for Board { 71 + type Output = BoardCell; 72 + 73 + fn index(&self, index: Vector2u16) -> &Self::Output { 74 + &self.cells[index.y as usize * 8 + index.x as usize] 75 + } 76 + } 77 + 78 + impl IndexMut<Vector2u16> for Board { 79 + fn index_mut(&mut self, index: Vector2u16) -> &mut Self::Output { 80 + &mut self.cells[index.y as usize * 8 + index.x as usize] 81 + } 82 + } 83 + 84 + impl Board { 85 + fn new(boats: impl IntoIterator<Item = Boat>) -> Self { 86 + let mut board = Self::default(); 87 + 88 + for (i, boat) in boats.into_iter().enumerate() { 89 + let start_x = boat.first_pos.x.min(boat.last_pos.x); 90 + let start_y = boat.first_pos.y.min(boat.last_pos.y); 91 + let end_x = boat.first_pos.x.max(boat.last_pos.x); 92 + let end_y = boat.first_pos.y.max(boat.last_pos.y); 93 + 94 + for x in start_x..=end_x { 95 + for y in start_y..=end_y { 96 + board[Vector2u16 { x, y }] = BoardCell::Boat(i as u8); 97 + } 98 + } 99 + } 100 + 101 + board 102 + } 103 + } 104 + 105 + #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] 106 + pub enum BoardCell { 107 + #[default] 108 + Nothing, 109 + Missed, 110 + Hit, 111 + Boat(u8), 112 + } 113 + 114 + impl Display for BoardCell { 115 + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 116 + match self { 117 + BoardCell::Nothing => write!(f, "."), 118 + BoardCell::Missed => write!(f, "o"), 119 + BoardCell::Hit => write!(f, "x"), 120 + BoardCell::Boat(n) => write!(f, "{n}"), 121 + } 122 + } 123 + } 124 + 125 + #[cfg(test)] 126 + mod tests { 127 + use super::*; 128 + 129 + #[test] 130 + fn empty_board() { 131 + assert_eq!( 132 + Board::default(), 133 + Board { 134 + cells: [Default::default(); 64], 135 + } 136 + ); 137 + } 138 + 139 + #[test] 140 + fn init_boards_with_boats() { 141 + let board = Board::new([ 142 + Boat::new(Vector2u16 { x: 2, y: 0 }, Vector2u16 { x: 2, y: 1 }), 143 + Boat::new(Vector2u16 { x: 3, y: 3 }, Vector2u16 { x: 5, y: 3 }), 144 + Boat::new(Vector2u16 { x: 1, y: 4 }, Vector2u16 { x: 1, y: 7 }), 145 + Boat::new(Vector2u16 { x: 3, y: 6 }, Vector2u16 { x: 7, y: 6 }), 146 + ]); 147 + 148 + let n = BoardCell::Nothing; 149 + let a = BoardCell::Boat(0); 150 + let b = BoardCell::Boat(1); 151 + let c = BoardCell::Boat(2); 152 + let d = BoardCell::Boat(3); 153 + 154 + assert_eq!( 155 + board, 156 + Board { 157 + cells: [ 158 + n, n, a, n, n, n, n, n, // 159 + n, n, a, n, n, n, n, n, // 160 + n, n, n, n, n, n, n, n, // 161 + n, n, n, b, b, b, n, n, // 162 + n, c, n, n, n, n, n, n, // 163 + n, c, n, n, n, n, n, n, // 164 + n, c, n, d, d, d, d, d, // 165 + n, c, n, n, n, n, n, n, 166 + ], 167 + } 168 + ); 169 + } 170 + }
+2
src/main.rs
··· 1 use std::process::ExitCode; 2 3 mod cli; 4 5 fn main() -> ExitCode { 6 let mut args = std::env::args();
··· 1 use std::process::ExitCode; 2 3 mod cli; 4 + mod game; 5 + mod parser; 6 7 fn main() -> ExitCode { 8 let mut args = std::env::args();
+1 -27
src/parser.rs
··· 1 use std::{fs::File, io::Read, path::Path}; 2 3 #[derive(Debug)] ··· 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)?)
··· 1 + use crate::game::{Boat, Vector2u16}; 2 use std::{fs::File, io::Read, path::Path}; 3 4 #[derive(Debug)] ··· 15 } 16 } 17 18 pub fn parse_file(file_path: &Path) -> Result<[Boat; 4], ParserError> { 19 let mut file = File::open(file_path)?; 20 Ok(parse_ships(&mut file)?)