From b110bec2c61fd8042eeb49a9dbcad4a66ad69841 Mon Sep 17 00:00:00 2001 From: nasso Date: Fri, 4 Jul 2025 20:29:12 +0200 Subject: [PATCH] Add core game types Change-Id: syytxqpvzmuypymwtklpvyswpwpxvoqq --- src/game.rs | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 2 + src/parser.rs | 28 +-------- 3 files changed, 173 insertions(+), 27 deletions(-) create mode 100644 src/game.rs diff --git a/src/game.rs b/src/game.rs new file mode 100644 index 0000000..07848dd --- /dev/null +++ b/src/game.rs @@ -0,0 +1,170 @@ +use std::{ + fmt::{Display, Formatter}, + ops::{Index, IndexMut}, +}; + +#[derive(Debug, PartialEq, Eq)] +pub struct Vector2u16 { + pub x: u16, + pub y: u16, +} + +impl Vector2u16 { + pub fn new(x: u16, y: u16) -> Self { + Vector2u16 { x, y } + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct Boat { + pub first_pos: Vector2u16, + pub last_pos: Vector2u16, +} + +impl Boat { + pub fn new(first_pos: Vector2u16, last_pos: Vector2u16) -> Self { + Boat { + first_pos, + last_pos, + } + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct Board { + pub cells: [BoardCell; 64], +} + +impl Display for Board { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + writeln!(f, " | A B C D E F G H ")?; + writeln!(f, "---+-----------------")?; + + for row in 1..=8 { + writeln!( + f, + " {row} | {} {} {} {} {} {} {} {}", + self.cells[8 * row - 1], + self.cells[8 * row], + self.cells[8 * row + 1], + self.cells[8 * row + 2], + self.cells[8 * row + 3], + self.cells[8 * row + 4], + self.cells[8 * row + 5], + self.cells[8 * row + 6], + )?; + } + + Ok(()) + } +} + +impl Default for Board { + fn default() -> Self { + Self { + cells: [Default::default(); 64], + } + } +} + +impl Index for Board { + type Output = BoardCell; + + fn index(&self, index: Vector2u16) -> &Self::Output { + &self.cells[index.y as usize * 8 + index.x as usize] + } +} + +impl IndexMut for Board { + fn index_mut(&mut self, index: Vector2u16) -> &mut Self::Output { + &mut self.cells[index.y as usize * 8 + index.x as usize] + } +} + +impl Board { + fn new(boats: impl IntoIterator) -> Self { + let mut board = Self::default(); + + for (i, boat) in boats.into_iter().enumerate() { + let start_x = boat.first_pos.x.min(boat.last_pos.x); + let start_y = boat.first_pos.y.min(boat.last_pos.y); + let end_x = boat.first_pos.x.max(boat.last_pos.x); + let end_y = boat.first_pos.y.max(boat.last_pos.y); + + for x in start_x..=end_x { + for y in start_y..=end_y { + board[Vector2u16 { x, y }] = BoardCell::Boat(i as u8); + } + } + } + + board + } +} + +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] +pub enum BoardCell { + #[default] + Nothing, + Missed, + Hit, + Boat(u8), +} + +impl Display for BoardCell { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + BoardCell::Nothing => write!(f, "."), + BoardCell::Missed => write!(f, "o"), + BoardCell::Hit => write!(f, "x"), + BoardCell::Boat(n) => write!(f, "{n}"), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn empty_board() { + assert_eq!( + Board::default(), + Board { + cells: [Default::default(); 64], + } + ); + } + + #[test] + fn init_boards_with_boats() { + let board = Board::new([ + Boat::new(Vector2u16 { x: 2, y: 0 }, Vector2u16 { x: 2, y: 1 }), + Boat::new(Vector2u16 { x: 3, y: 3 }, Vector2u16 { x: 5, y: 3 }), + Boat::new(Vector2u16 { x: 1, y: 4 }, Vector2u16 { x: 1, y: 7 }), + Boat::new(Vector2u16 { x: 3, y: 6 }, Vector2u16 { x: 7, y: 6 }), + ]); + + let n = BoardCell::Nothing; + let a = BoardCell::Boat(0); + let b = BoardCell::Boat(1); + let c = BoardCell::Boat(2); + let d = BoardCell::Boat(3); + + assert_eq!( + board, + Board { + cells: [ + n, n, a, n, n, n, n, n, // + n, n, a, n, n, n, n, n, // + n, n, n, n, n, n, n, n, // + n, n, n, b, b, b, n, n, // + n, c, n, n, n, n, n, n, // + n, c, n, n, n, n, n, n, // + n, c, n, d, d, d, d, d, // + n, c, n, n, n, n, n, n, + ], + } + ); + } +} diff --git a/src/main.rs b/src/main.rs index ef8ff34..6550562 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ use std::process::ExitCode; mod cli; +mod game; +mod parser; fn main() -> ExitCode { let mut args = std::env::args(); diff --git a/src/parser.rs b/src/parser.rs index 589f4ef..6f0728e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,3 +1,4 @@ +use crate::game::{Boat, Vector2u16}; use std::{fs::File, io::Read, path::Path}; #[derive(Debug)] @@ -14,33 +15,6 @@ impl From for ParserError { } } -#[derive(Debug, PartialEq, Eq)] -pub struct Vector2u16 { - x: u16, - y: u16, -} - -impl Vector2u16 { - pub fn new(x: u16, y: u16) -> Self { - Vector2u16 { x: x, y: y } - } -} - -#[derive(Debug, PartialEq, Eq)] -pub struct Boat { - first_pos: Vector2u16, - last_pos: Vector2u16, -} - -impl Boat { - pub fn new(first_pos: Vector2u16, last_pos: Vector2u16) -> Self { - Boat { - first_pos: first_pos, - last_pos: last_pos, - } - } -} - pub fn parse_file(file_path: &Path) -> Result<[Boat; 4], ParserError> { let mut file = File::open(file_path)?; Ok(parse_ships(&mut file)?) -- 2.49.0