Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/game/board.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#[cfg(test)]
#[path = "tests/board.rs"]
mod tests;

use crate::game::{
color::Color,
piece::{Piece},
Expand All @@ -10,6 +14,7 @@ pub struct Board {
}

impl Board {
/// Creates a new empty board with all cells set to None.
pub fn new() -> Self {
Board {
board: [[None; BOARD_SIZE]; BOARD_SIZE],
Expand Down
4 changes: 4 additions & 0 deletions src/game/coordinate.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#[cfg(test)]
#[path = "tests/coordinate.rs"]
mod tests;

use crate::game::rotation::Rotation;

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
Expand Down
121 changes: 6 additions & 115 deletions src/game/gamerulelogic.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
#[cfg(test)]
#[path = "tests/gamerulelogic.rs"]
mod tests;


use std::collections::HashSet;

use crate::{game::{ board::Board,
Expand Down Expand Up @@ -305,118 +310,4 @@ pub fn is_valid_move(gamestate: &GameState, m: &Move) -> bool {
}

true
}

#[cfg(test)]
mod tests {
use crate::game::{
board::Board,
color::Color,
gamestate::GameState,
piece::PieceType,
r#move::Move,
rotation::Rotation
};
use crate::game::coordinate::Coordinate;

use super::{get_possible_moves_for_piece, is_valid_move};

fn blue_turn_state_with_board(board: Board) -> GameState {
GameState::new(
PieceType::Mono,
true,
board,
5,
2,
Color::Blue,
vec![PieceType::Mono],
vec![],
vec![],
vec![],
)
}

#[test]
fn invalid_when_directly_adjacent_to_own_piece() {
let mut board = Board::new();
board.set_cell(5, 5, Color::Blue);

let state = blue_turn_state_with_board(board);
let m = Move {
color: Color::Blue,
piece: PieceType::Mono,
x: 6,
y: 5,
is_flipped: false,
rotation: Rotation::None,
skip: false,
};

assert!(!is_valid_move(&state, &m));
}

#[test]
fn valid_when_only_corner_contact_exists() {
let mut board = Board::new();
board.set_cell(5, 5, Color::Blue);

let state = blue_turn_state_with_board(board);
let m = Move {
color: Color::Blue,
piece: PieceType::Mono,
x: 6,
y: 6,
is_flipped: false,
rotation: Rotation::None,
skip: false,
};

assert!(is_valid_move(&state, &m));
}

#[test]
fn invalid_when_no_corner_contact_after_first_move() {
let mut board = Board::new();
board.set_cell(5, 5, Color::Blue);

let state = blue_turn_state_with_board(board);
let m = Move {
color: Color::Blue,
piece: PieceType::Mono,
x: 10,
y: 10,
is_flipped: false,
rotation: Rotation::None,
skip: false,
};

assert!(!is_valid_move(&state, &m));
}

#[test]
fn calculates_moves_where_corner_is_not_piece_origin() {
let mut board = Board::new();
board.set_cell(5, 5, Color::Blue);

let state = GameState::new(
PieceType::Mono,
true,
board,
5,
2,
Color::Blue,
vec![PieceType::PentoX],
vec![],
vec![],
vec![],
);

let valid_fields = vec![Coordinate { x: 6, y: 6 }];
let moves = get_possible_moves_for_piece(&state, &PieceType::PentoX, &valid_fields);

assert!(
moves.iter().any(|m| m.x == 6 && m.y == 5),
"expected a placement that aligns a non-origin PENTO_X tile to the corner"
);
}
}
}
4 changes: 4 additions & 0 deletions src/game/gamestate.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#[cfg(test)]
#[path = "tests/gamestate.rs"]
mod tests;

use crate::game::{
board::Board,
color::Color,
Expand Down
83 changes: 4 additions & 79 deletions src/game/piece.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
#[cfg(test)]
#[path = "tests/piece.rs"]
mod tests;

use std::{fmt, str::FromStr};

use crate::game::{
Expand Down Expand Up @@ -282,83 +286,4 @@ impl FromStr for PieceType {
_ => Err(ParsePieceTypeError),
}
}
}

#[cfg(test)]
mod tests {
use super::{Piece, PieceType};
use crate::{game::rotation::Rotation, game::coordinate::Coordinate};

fn sorted_xy(coordinates: Vec<Coordinate>) -> Vec<(isize, isize)> {
let mut xy: Vec<(isize, isize)> = coordinates
.into_iter()
.map(|coord| (coord.x, coord.y))
.collect();
xy.sort_unstable();
xy
}

#[test]
fn pento_r_get_coordinates_all_8_variants() {
let cases: Vec<(Rotation, bool, Vec<(isize, isize)>)> = vec![
(
Rotation::None,
false,
vec![(2, 0), (0, 1), (1, 1), (2, 1), (1, 2)],
),
(
Rotation::Right,
false,
vec![(2, 2), (1, 0), (1, 1), (1, 2), (0, 1)],
),
(
Rotation::Mirror,
false,
vec![(0, 2), (2, 1), (1, 1), (0, 1), (1, 0)],
),
(
Rotation::Left,
false,
vec![(0, 0), (1, 2), (1, 1), (1, 0), (2, 1)],
),
(
Rotation::None,
true,
vec![(0, 0), (2, 1), (1, 1), (0, 1), (1, 2)],
),
(
Rotation::Right,
true,
vec![(0, 2), (1, 0), (1, 1), (1, 2), (2, 1)],
),
(
Rotation::Mirror,
true,
vec![(2, 2), (0, 1), (1, 1), (2, 1), (1, 0)],
),
(
Rotation::Left,
true,
vec![(2, 0), (1, 2), (1, 1), (1, 0), (0, 1)],
),
];

for (rotation, is_flipped, expected) in cases {
let piece = Piece::new(PieceType::PentoR, rotation, is_flipped);
let actual = sorted_xy(piece.get_coordinates());

assert_eq!(
actual,
sorted_xy(
expected
.into_iter()
.map(|(x, y)| Coordinate::new(x, y))
.collect()
),
"unexpected coordinates for rotation={:?}, is_flipped={}",
rotation,
is_flipped
);
}
}
}
100 changes: 100 additions & 0 deletions src/game/tests/board.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use super::Board;
use crate::game::{color::Color, constants::BOARD_SIZE, piece::{Piece, PieceType}, rotation::Rotation};

#[test]
fn test_board_initialization() {
let board = Board::new();
for row in 0..BOARD_SIZE {
for col in 0..BOARD_SIZE {
assert_eq!(board.get_cell(col, row), None);
}
}
}

#[test]
fn test_set_and_get_cell() {
let mut board = Board::new();
assert!(board.set_cell(3, 4, Color::Red));
assert_eq!(board.get_cell(3, 4), Some(Color::Red));
assert_eq!(board.set_cell(BOARD_SIZE, BOARD_SIZE, Color::Blue), false); // Out of bounds, should return false
assert_eq!(board.get_cell(BOARD_SIZE, BOARD_SIZE), None); // Out of bounds, should return None
}

#[test]
fn test_get_colored_tiles() {
let mut board = Board::new();
assert_eq!(board.get_colored_tiles(&Color::Red), 0);
board.set_cell(0, 0, Color::Red);
board.set_cell(1, 1, Color::Red);
board.set_cell(2, 2, Color::Blue);
assert_eq!(board.get_colored_tiles(&Color::Red), 2);
assert_eq!(board.get_colored_tiles(&Color::Blue), 1);
}

#[test]
fn test_place_piece_unchecked_no_rotation_no_flipping() {
let mut board = Board::new();

let piece = Piece::new(PieceType::TetroI, Rotation::None, false);
board.place_piece_unchecked(0, 0, Color::Green, piece);
assert_eq!(board.get_cell(0, 0), Some(Color::Green));
assert_eq!(board.get_cell(0, 1), Some(Color::Green));
assert_eq!(board.get_cell(0, 2), Some(Color::Green));
assert_eq!(board.get_cell(0, 3), Some(Color::Green));
}

#[test]
fn test_place_piece_unchecked_rotation_no_flipping() {
let mut board = Board::new();

let piece = Piece::new(PieceType::TetroI, Rotation::Right, false);
board.place_piece_unchecked(0, 0, Color::Green, piece);
assert_eq!(board.get_cell(0, 0), Some(Color::Green));
assert_eq!(board.get_cell(1, 0), Some(Color::Green));
assert_eq!(board.get_cell(2, 0), Some(Color::Green));
assert_eq!(board.get_cell(3, 0), Some(Color::Green));
}

#[test]
fn test_place_piece_unchecked_no_rotation_flipping() {
let mut board = Board::new();

let piece = Piece::new(PieceType::TetroL, Rotation::None, true);
board.place_piece_unchecked(0, 0, Color::Green, piece);
assert_eq!(board.get_cell(1, 0), Some(Color::Green));
assert_eq!(board.get_cell(1, 1), Some(Color::Green));
assert_eq!(board.get_cell(1, 2), Some(Color::Green));
assert_eq!(board.get_cell(0, 2), Some(Color::Green));
}

#[test]
fn test_place_piece_unchecked_rotation_flipping() {
let mut board = Board::new();

let piece = Piece::new(PieceType::TetroL, Rotation::Left, true);
board.place_piece_unchecked(0, 0, Color::Green, piece);
assert_eq!(board.get_cell(0, 0), Some(Color::Green));
assert_eq!(board.get_cell(0, 1), Some(Color::Green));
assert_eq!(board.get_cell(1, 1), Some(Color::Green));
assert_eq!(board.get_cell(2, 1), Some(Color::Green));
}

#[test]
fn test_place_piece_success() {
let mut board = Board::new();

let piece = Piece::new(PieceType::TetroI, Rotation::None, false);
assert!(board.place_piece(0, 0, Color::Green, piece));
assert_eq!(board.get_cell(0, 0), Some(Color::Green));
assert_eq!(board.get_cell(0, 1), Some(Color::Green));
assert_eq!(board.get_cell(0, 2), Some(Color::Green));
assert_eq!(board.get_cell(0, 3), Some(Color::Green));
}

#[test]
fn test_place_piece_failure_out_of_bounds() {
let mut board = Board::new();

let piece = Piece::new(PieceType::TetroI, Rotation::None, false);
assert!(!board.place_piece(BOARD_SIZE - 1, BOARD_SIZE - 1, Color::Green, piece)); // This should fail as it goes out of bounds
}
Loading
Loading