mirror of
https://github.com/Xevion/Pac-Man.git
synced 2025-12-06 07:15:41 -06:00
254 lines
8.0 KiB
Rust
254 lines
8.0 KiB
Rust
//! This module contains all the constants used in the game.
|
|
|
|
use std::time::Duration;
|
|
|
|
use glam::UVec2;
|
|
|
|
pub const LOOP_TIME: Duration = Duration::from_nanos((1_000_000_000.0 / 60.0) as u64);
|
|
|
|
/// The size of each cell, in pixels.
|
|
pub const CELL_SIZE: u32 = 8;
|
|
/// The size of the game board, in cells.
|
|
pub const BOARD_CELL_SIZE: UVec2 = UVec2::new(28, 31);
|
|
|
|
/// The scale factor for the window (integer zoom)
|
|
pub const SCALE: f32 = 2.6;
|
|
|
|
/// The offset of the game board from the top-left corner of the window, in cells.
|
|
pub const BOARD_CELL_OFFSET: UVec2 = UVec2::new(0, 3);
|
|
/// The offset of the game board from the top-left corner of the window, in pixels.
|
|
pub const BOARD_PIXEL_OFFSET: UVec2 = UVec2::new(BOARD_CELL_OFFSET.x * CELL_SIZE, BOARD_CELL_OFFSET.y * CELL_SIZE);
|
|
/// The size of the game board, in pixels.
|
|
pub const BOARD_PIXEL_SIZE: UVec2 = UVec2::new(BOARD_CELL_SIZE.x * CELL_SIZE, BOARD_CELL_SIZE.y * CELL_SIZE);
|
|
/// The size of the canvas, in pixels.
|
|
pub const CANVAS_SIZE: UVec2 = UVec2::new(
|
|
(BOARD_CELL_SIZE.x + BOARD_CELL_OFFSET.x) * CELL_SIZE,
|
|
(BOARD_CELL_SIZE.y + BOARD_CELL_OFFSET.y) * CELL_SIZE,
|
|
);
|
|
|
|
/// An enum representing the different types of tiles on the map.
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
pub enum MapTile {
|
|
/// An empty tile.
|
|
Empty,
|
|
/// A wall tile.
|
|
Wall,
|
|
/// A regular pellet.
|
|
Pellet,
|
|
/// A power pellet.
|
|
PowerPellet,
|
|
/// A tunnel tile.
|
|
Tunnel,
|
|
}
|
|
|
|
/// The raw layout of the game board, as a 2D array of characters.
|
|
pub const RAW_BOARD: [&str; BOARD_CELL_SIZE.y as usize] = [
|
|
"############################",
|
|
"#............##............#",
|
|
"#.####.#####.##.#####.####.#",
|
|
"#o####.#####.##.#####.####o#",
|
|
"#.####.#####.##.#####.####.#",
|
|
"#..........................#",
|
|
"#.####.##.########.##.####.#",
|
|
"#.####.##.########.##.####.#",
|
|
"#......##....##....##......#",
|
|
"######.##### ## #####.######",
|
|
" #.##### ## #####.# ",
|
|
" #.## == ##.# ",
|
|
" #.## ######## ##.# ",
|
|
"######.## ######## ##.######",
|
|
"T . ######## . T",
|
|
"######.## ######## ##.######",
|
|
" #.## ######## ##.# ",
|
|
" #.## ##.# ",
|
|
" #.## ######## ##.# ",
|
|
"######.## ######## ##.######",
|
|
"#............##............#",
|
|
"#.####.#####.##.#####.####.#",
|
|
"#.####.#####.##.#####.####.#",
|
|
"#o..##.......X .......##..o#",
|
|
"###.##.##.########.##.##.###",
|
|
"###.##.##.########.##.##.###",
|
|
"#......##....##....##......#",
|
|
"#.##########.##.##########.#",
|
|
"#.##########.##.##########.#",
|
|
"#..........................#",
|
|
"############################",
|
|
];
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_loop_time() {
|
|
// 60 FPS = 16.67ms per frame
|
|
let expected_nanos = (1_000_000_000.0 / 60.0) as u64;
|
|
assert_eq!(LOOP_TIME.as_nanos() as u64, expected_nanos);
|
|
}
|
|
|
|
#[test]
|
|
fn test_cell_size() {
|
|
assert_eq!(CELL_SIZE, 8);
|
|
}
|
|
|
|
#[test]
|
|
fn test_board_cell_size() {
|
|
assert_eq!(BOARD_CELL_SIZE.x, 28);
|
|
assert_eq!(BOARD_CELL_SIZE.y, 31);
|
|
}
|
|
|
|
#[test]
|
|
fn test_scale() {
|
|
assert_eq!(SCALE, 2.6);
|
|
}
|
|
|
|
#[test]
|
|
fn test_board_cell_offset() {
|
|
assert_eq!(BOARD_CELL_OFFSET.x, 0);
|
|
assert_eq!(BOARD_CELL_OFFSET.y, 3);
|
|
}
|
|
|
|
#[test]
|
|
fn test_board_pixel_offset() {
|
|
let expected = UVec2::new(0 * CELL_SIZE, 3 * CELL_SIZE);
|
|
assert_eq!(BOARD_PIXEL_OFFSET, expected);
|
|
assert_eq!(BOARD_PIXEL_OFFSET.x, 0);
|
|
assert_eq!(BOARD_PIXEL_OFFSET.y, 24); // 3 * 8
|
|
}
|
|
|
|
#[test]
|
|
fn test_board_pixel_size() {
|
|
let expected = UVec2::new(28 * CELL_SIZE, 31 * CELL_SIZE);
|
|
assert_eq!(BOARD_PIXEL_SIZE, expected);
|
|
assert_eq!(BOARD_PIXEL_SIZE.x, 224); // 28 * 8
|
|
assert_eq!(BOARD_PIXEL_SIZE.y, 248); // 31 * 8
|
|
}
|
|
|
|
#[test]
|
|
fn test_canvas_size() {
|
|
let expected = UVec2::new((28 + 0) * CELL_SIZE, (31 + 3) * CELL_SIZE);
|
|
assert_eq!(CANVAS_SIZE, expected);
|
|
assert_eq!(CANVAS_SIZE.x, 224); // (28 + 0) * 8
|
|
assert_eq!(CANVAS_SIZE.y, 272); // (31 + 3) * 8
|
|
}
|
|
|
|
#[test]
|
|
fn test_map_tile_variants() {
|
|
assert_ne!(MapTile::Empty, MapTile::Wall);
|
|
assert_ne!(MapTile::Pellet, MapTile::PowerPellet);
|
|
assert_ne!(MapTile::Tunnel, MapTile::Empty);
|
|
}
|
|
|
|
#[test]
|
|
fn test_map_tile_clone() {
|
|
let original = MapTile::Wall;
|
|
let cloned = original;
|
|
assert_eq!(original, cloned);
|
|
}
|
|
|
|
#[test]
|
|
fn test_raw_board_dimensions() {
|
|
assert_eq!(RAW_BOARD.len(), BOARD_CELL_SIZE.y as usize);
|
|
assert_eq!(RAW_BOARD.len(), 31);
|
|
|
|
for row in RAW_BOARD.iter() {
|
|
assert_eq!(row.len(), BOARD_CELL_SIZE.x as usize);
|
|
assert_eq!(row.len(), 28);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_raw_board_boundaries() {
|
|
// First row should be all walls
|
|
assert!(RAW_BOARD[0].chars().all(|c| c == '#'));
|
|
|
|
// Last row should be all walls
|
|
let last_row = RAW_BOARD[RAW_BOARD.len() - 1];
|
|
assert!(last_row.chars().all(|c| c == '#'));
|
|
|
|
// First and last character of each row should be walls (except tunnel rows and rows with spaces)
|
|
for (i, row) in RAW_BOARD.iter().enumerate() {
|
|
if i != 14 && !row.starts_with(' ') {
|
|
// Skip tunnel row and rows that start with spaces
|
|
assert_eq!(row.chars().next().unwrap(), '#');
|
|
assert_eq!(row.chars().last().unwrap(), '#');
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_raw_board_tunnel_row() {
|
|
// Row 14 should have tunnel characters 'T' at the edges
|
|
let tunnel_row = RAW_BOARD[14];
|
|
assert_eq!(tunnel_row.chars().next().unwrap(), 'T');
|
|
assert_eq!(tunnel_row.chars().last().unwrap(), 'T');
|
|
}
|
|
|
|
#[test]
|
|
fn test_raw_board_power_pellets() {
|
|
// Power pellets are represented by 'o'
|
|
let mut power_pellet_count = 0;
|
|
for row in RAW_BOARD.iter() {
|
|
power_pellet_count += row.chars().filter(|&c| c == 'o').count();
|
|
}
|
|
assert_eq!(power_pellet_count, 4); // Should have exactly 4 power pellets
|
|
}
|
|
|
|
#[test]
|
|
fn test_raw_board_starting_position() {
|
|
// Should have a starting position 'X' for Pac-Man
|
|
let mut found_starting_position = false;
|
|
for row in RAW_BOARD.iter() {
|
|
if row.contains('X') {
|
|
found_starting_position = true;
|
|
break;
|
|
}
|
|
}
|
|
assert!(found_starting_position);
|
|
}
|
|
|
|
#[test]
|
|
fn test_raw_board_ghost_house() {
|
|
// The ghost house area should be present (the == characters)
|
|
let mut found_ghost_house = false;
|
|
for row in RAW_BOARD.iter() {
|
|
if row.contains("==") {
|
|
found_ghost_house = true;
|
|
break;
|
|
}
|
|
}
|
|
assert!(found_ghost_house);
|
|
}
|
|
|
|
#[test]
|
|
fn test_raw_board_symmetry() {
|
|
// The board should be roughly symmetrical
|
|
let mid_point = RAW_BOARD[0].len() / 2;
|
|
|
|
for row in RAW_BOARD.iter() {
|
|
let left_half = &row[..mid_point];
|
|
let right_half = &row[mid_point..];
|
|
|
|
// Check that the halves are symmetrical (accounting for the center column)
|
|
assert_eq!(left_half.len(), right_half.len());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_constants_consistency() {
|
|
// Verify that derived constants are calculated correctly
|
|
let calculated_pixel_offset = UVec2::new(BOARD_CELL_OFFSET.x * CELL_SIZE, BOARD_CELL_OFFSET.y * CELL_SIZE);
|
|
assert_eq!(BOARD_PIXEL_OFFSET, calculated_pixel_offset);
|
|
|
|
let calculated_pixel_size = UVec2::new(BOARD_CELL_SIZE.x * CELL_SIZE, BOARD_CELL_SIZE.y * CELL_SIZE);
|
|
assert_eq!(BOARD_PIXEL_SIZE, calculated_pixel_size);
|
|
|
|
let calculated_canvas_size = UVec2::new(
|
|
(BOARD_CELL_SIZE.x + BOARD_CELL_OFFSET.x) * CELL_SIZE,
|
|
(BOARD_CELL_SIZE.y + BOARD_CELL_OFFSET.y) * CELL_SIZE,
|
|
);
|
|
assert_eq!(CANVAS_SIZE, calculated_canvas_size);
|
|
}
|
|
}
|