battleship game in rust

Add core game types

Changed files
+173 -27
src
+170
src/game.rs
···
···
+
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<Vector2u16> 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<Vector2u16> 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<Item = Boat>) -> 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,
+
],
+
}
+
);
+
}
+
}
+2
src/main.rs
···
use std::process::ExitCode;
mod cli;
fn main() -> ExitCode {
let mut args = std::env::args();
···
use std::process::ExitCode;
mod cli;
+
mod game;
+
mod parser;
fn main() -> ExitCode {
let mut args = std::env::args();
+1 -27
src/parser.rs
···
use std::{fs::File, io::Read, path::Path};
#[derive(Debug)]
···
impl From<std::io::Error> for ParserError {
fn from(value: std::io::Error) -> Self {
ParserError::IO(value)
-
}
-
}
-
-
#[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,
-
}
}
}
···
+
use crate::game::{Boat, Vector2u16};
use std::{fs::File, io::Read, path::Path};
#[derive(Debug)]
···
impl From<std::io::Error> for ParserError {
fn from(value: std::io::Error) -> Self {
ParserError::IO(value)
}
}