You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.8 KiB
124 lines
3.8 KiB
import json |
|
from pathlib import Path |
|
|
|
|
|
LEVELS_PER_DAT_FILE = 32 |
|
LEVEL_WIDTH = 32 |
|
LEVEL_HEIGHT = 32 |
|
LEVEL_SIZE = LEVEL_WIDTH * LEVEL_HEIGHT |
|
EXPECTED_DAT_SIZE = LEVELS_PER_DAT_FILE * LEVEL_SIZE |
|
PROJECT_ROOT = Path(__file__).resolve().parent.parent |
|
DEFAULT_DAT_PATH = PROJECT_ROOT / "assets" / "Rat" / "level.dat" |
|
DEFAULT_JSON_PATH = PROJECT_ROOT / "maze.json" |
|
MAP_EMPTY = 0 |
|
MAP_WALL = 1 |
|
MAP_TUNNEL = 2 |
|
|
|
|
|
def get_default_map_source(): |
|
if DEFAULT_DAT_PATH.exists(): |
|
return DEFAULT_DAT_PATH |
|
return DEFAULT_JSON_PATH |
|
|
|
|
|
class Map: |
|
"""Classe che rappresenta la mappa del labirinto.""" |
|
|
|
def __init__(self, maze_file=None, level_index=0): |
|
self.source_path = self._resolve_source_path(maze_file) |
|
self.level_index = level_index |
|
self.tiles = self._load_tiles(self.source_path, level_index) |
|
self.matrix = [ |
|
[cell == MAP_WALL for cell in row] |
|
for row in self.tiles |
|
] |
|
self.height = len(self.tiles) |
|
self.width = len(self.tiles[0]) |
|
|
|
def _resolve_source_path(self, maze_file): |
|
if maze_file is None: |
|
return get_default_map_source() |
|
|
|
candidate = Path(maze_file) |
|
if candidate.is_absolute(): |
|
return candidate |
|
|
|
if candidate.exists(): |
|
return candidate.resolve() |
|
|
|
project_candidate = PROJECT_ROOT / candidate |
|
if project_candidate.exists(): |
|
return project_candidate |
|
|
|
return project_candidate |
|
|
|
def _load_tiles(self, source_path, level_index): |
|
suffix = source_path.suffix.lower() |
|
if suffix == ".dat": |
|
return self._load_dat_level(source_path, level_index) |
|
return self._load_json_level(source_path) |
|
|
|
def _load_json_level(self, source_path): |
|
with source_path.open("r", encoding="utf-8") as file: |
|
matrix = json.load(file) |
|
return [ |
|
[MAP_WALL if cell else MAP_TUNNEL for cell in row] |
|
for row in matrix |
|
] |
|
|
|
def _load_dat_level(self, source_path, level_index): |
|
raw_data = source_path.read_bytes() |
|
if len(raw_data) != EXPECTED_DAT_SIZE: |
|
raise ValueError( |
|
f"Invalid DAT size for {source_path}: expected {EXPECTED_DAT_SIZE} bytes, got {len(raw_data)}" |
|
) |
|
|
|
normalized_level = level_index % LEVELS_PER_DAT_FILE |
|
level_offset = normalized_level * LEVEL_SIZE |
|
level_data = raw_data[level_offset:level_offset + LEVEL_SIZE] |
|
|
|
matrix = [] |
|
for row in range(LEVEL_HEIGHT): |
|
row_start = row * LEVEL_WIDTH |
|
raw_row = level_data[row_start:row_start + LEVEL_WIDTH] |
|
matrix.append(list(raw_row)) |
|
return matrix |
|
|
|
def in_bounds(self, x, y): |
|
return 0 <= x < self.width and 0 <= y < self.height |
|
|
|
def get_cell(self, x, y): |
|
return self.tiles[y][x] |
|
|
|
def is_wall(self, x, y): |
|
"""Restituisce True se la cella è un muro, False altrimenti.""" |
|
return self.matrix[y][x] |
|
|
|
def is_traversable(self, x, y): |
|
return self.get_cell(x, y) != MAP_WALL |
|
|
|
def is_empty(self, x, y): |
|
return self.get_cell(x, y) == MAP_EMPTY |
|
|
|
def is_tunnel(self, x, y): |
|
return self.get_cell(x, y) == MAP_TUNNEL |
|
|
|
def get_tunnel_direction(self, x, y): |
|
directions = [ |
|
("UP", 0, -1), |
|
("DOWN", 0, 1), |
|
("LEFT", -1, 0), |
|
("RIGHT", 1, 0), |
|
] |
|
traversable_neighbors = [] |
|
for direction, dx, dy in directions: |
|
nx = x + dx |
|
ny = y + dy |
|
if self.in_bounds(nx, ny) and self.is_traversable(nx, ny): |
|
traversable_neighbors.append(direction) |
|
|
|
if len(traversable_neighbors) == 1: |
|
return traversable_neighbors[0] |
|
if traversable_neighbors: |
|
return traversable_neighbors[0] |
|
return "UP" |