properties = $properties; } /** * Définit une propriété * * @param string $key La clé de la propriété * @param mixed $value La valeur de la propriété */ public function setProperty(string $key, $value): void { $this->properties[$key] = $value; } /** * Récupère une propriété * * @param string $key La clé de la propriété * @param mixed $default La valeur par défaut si la propriété n'existe pas * @return mixed La valeur de la propriété */ public function getProperty(string $key, $default = null) { return $this->properties[$key] ?? $default; } /** * Vérifie si une propriété existe * * @param string $key La clé de la propriété * @return bool True si la propriété existe */ public function hasProperty(string $key): bool { return array_key_exists($key, $this->properties); } /** * Supprime une propriété * * @param string $key La clé de la propriété */ public function removeProperty(string $key): void { unset($this->properties[$key]); } /** * Récupère toutes les propriétés * * @return array Toutes les propriétés */ public function getAllProperties(): array { return $this->properties; } /** * Définit toutes les propriétés * * @param array $properties Les nouvelles propriétés */ public function setAllProperties(array $properties): void { $this->properties = $properties; } /** * Vérifie si la tuile est vide (aucune propriété) * * @return bool True si la tuile est vide */ public function isEmpty(): bool { return empty($this->properties); } /** * Convertit la tuile en tableau pour la sérialisation * * @return array Les données de la tuile */ public function toArray(): array { return $this->properties; } /** * Crée une tuile depuis un tableau * * @param array $data Les données de la tuile * @return Tile La tuile créée */ public static function fromArray(array $data): Tile { return new self($data); } /** * Méthodes d'accès rapide pour les propriétés communes */ /** * Récupère le type de la tuile * * @return string|null Le type ou null */ public function getType(): ?string { return $this->getProperty('type'); } /** * Définit le type de la tuile * * @param string $type Le type */ public function setType(string $type): void { $this->setProperty('type', $type); } /** * Récupère les ressources de la tuile * * @return array Les ressources */ public function getResources(): array { return $this->getProperty('resources', []); } /** * Définit les ressources de la tuile * * @param array $resources Les ressources */ public function setResources(array $resources): void { $this->setProperty('resources', $resources); } /** * Récupère la température de la tuile * * @return float|null La température ou null */ public function getTemperature(): ?float { return $this->getProperty('temperature'); } /** * Définit la température de la tuile * * @param float $temperature La température */ public function setTemperature(float $temperature): void { $this->setProperty('temperature', $temperature); } /** * Récupère l'élévation de la tuile * * @return int|null L'élévation ou null */ public function getElevation(): ?int { return $this->getProperty('elevation'); } /** * Définit l'élévation de la tuile * * @param int $elevation L'élévation */ public function setElevation(int $elevation): void { $this->setProperty('elevation', $elevation); } } } /** * Classe Map * * Représente une carte composée d'hexagones (damier hexagonal). * Chaque hexagone est une parcelle pouvant contenir une tuile avec des propriétés arbitraires. */ if (!class_exists('Map')) { class Map { /** * @var array Les hexagones de la carte indexés par coordonnées [q][r] */ private array $hexagons = []; /** * @var string Le nom de la carte */ private string $name; /** * @var int La largeur de la carte (nombre d'hexagones en largeur) */ private int $width; /** * @var int La hauteur de la carte (nombre d'hexagones en hauteur) */ private int $height; /** * @var string La date de création de la carte */ private string $createdAt; /** * @var string La date de dernière modification */ private string $updatedAt; /** * Constructeur de la carte * * @param string $name Le nom de la carte * @param int $width La largeur de la carte (en nombre d'hexagones) * @param int $height La hauteur de la carte (en nombre d'hexagones) */ public function __construct(string $name, int $width = 10, int $height = 10) { $this->name = $name; $this->width = $width; $this->height = $height; $this->createdAt = date('Y-m-d H:i:s'); $this->updatedAt = date('Y-m-d H:i:s'); // Initialiser la carte avec des hexagones vides $this->initializeMap(); } /** * Initialise la carte avec des hexagones vides */ private function initializeMap(): void { for ($q = 0; $q < $this->width; $q++) { for ($r = 0; $r < $this->height; $r++) { $this->hexagons[$q][$r] = new Hexagon($q, $r, new Tile(['type' => 'empty'])); } } } /** * Définit la tuile d'un hexagone * * @param int $q Coordonnée Q de l'hexagone * @param int $r Coordonnée R de l'hexagone * @param Tile $tile La tuile à placer * @return bool True si l'hexagone a été modifié, false sinon */ public function setTile(int $q, int $r, Tile $tile): bool { if (!$this->isValidCoordinate($q, $r)) { return false; } $this->hexagons[$q][$r]->setTile($tile); $this->updatedAt = date('Y-m-d H:i:s'); return true; } /** * Récupère la tuile d'un hexagone * * @param int $q Coordonnée Q de l'hexagone * @param int $r Coordonnée R de l'hexagone * @return Tile|null La tuile ou null si les coordonnées sont invalides */ public function getTile(int $q, int $r): ?Tile { if (!$this->isValidCoordinate($q, $r)) { return null; } return $this->hexagons[$q][$r]->getTile(); } /** * Récupère un hexagone * * @param int $q Coordonnée Q de l'hexagone * @param int $r Coordonnée R de l'hexagone * @return Hexagon|null L'hexagone ou null si les coordonnées sont invalides */ public function getHexagon(int $q, int $r): ?Hexagon { if (!$this->isValidCoordinate($q, $r)) { return null; } return $this->hexagons[$q][$r]; } /** * Vérifie si les coordonnées sont valides * * @param int $q Coordonnée Q * @param int $r Coordonnée R * @return bool True si les coordonnées sont valides */ public function isValidCoordinate(int $q, int $r): bool { return isset($this->hexagons[$q][$r]); } /** * Récupère tous les hexagones de la carte * * @return array Les hexagones indexés par [q][r] */ public function getAllHexagons(): array { return $this->hexagons; } /** * Récupère les hexagones d'une ligne spécifique * * @param int $q La coordonnée Q de la ligne * @return array|null Les hexagones de la ligne ou null si la ligne n'existe pas */ public function getHexagonsRow(int $q): ?array { return $this->hexagons[$q] ?? null; } /** * Compte le nombre d'hexagones d'un certain type * * @param string $tileType Le type de tuile à compter * @return int Le nombre d'hexagones de ce type */ public function countTiles(string $tileType): int { $count = 0; foreach ($this->hexagons as $row) { foreach ($row as $hexagon) { $tile = $hexagon->getTile(); if ($tile && $tile->getType() === $tileType) { $count++; } } } return $count; } /** * Compte le nombre d'hexagones vides * * @return int Le nombre d'hexagones vides */ public function countEmptyTiles(): int { $count = 0; foreach ($this->hexagons as $row) { foreach ($row as $hexagon) { if ($hexagon->isEmpty()) { $count++; } } } return $count; } /** * Récupère les statistiques de la carte * * @return array Les statistiques (nombre total d'hexagones, répartition par type) */ public function getStatistics(): array { $totalHexagons = $this->width * $this->height; $tileTypeCounts = []; $emptyCount = $this->countEmptyTiles(); // Compter les types de tuiles présents foreach ($this->hexagons as $row) { foreach ($row as $hexagon) { $tile = $hexagon->getTile(); if ($tile && !$tile->isEmpty()) { $type = $tile->getType(); if ($type !== null) { $tileTypeCounts[$type] = ($tileTypeCounts[$type] ?? 0) + 1; } } } } return [ 'total_hexagons' => $totalHexagons, 'width' => $this->width, 'height' => $this->height, 'tile_type_counts' => $tileTypeCounts, 'empty_count' => $emptyCount, 'empty_percentage' => round(($emptyCount / $totalHexagons) * 100, 2), 'filled_count' => $totalHexagons - $emptyCount, 'filled_percentage' => round((($totalHexagons - $emptyCount) / $totalHexagons) * 100, 2) ]; } /** * Convertit la carte en tableau pour la sérialisation JSON * * @return array Les données de la carte */ public function toArray(): array { $hexagonsData = []; foreach ($this->hexagons as $q => $row) { foreach ($row as $r => $hexagon) { $hexagonsData[] = $hexagon->toArray(); } } return [ 'name' => $this->name, 'width' => $this->width, 'height' => $this->height, 'created_at' => $this->createdAt, 'updated_at' => $this->updatedAt, 'hexagons' => $hexagonsData ]; } /** * Convertit la carte en JSON * * @param bool $prettyPrint True pour un JSON formaté * @return string Le JSON de la carte */ public function toJson(bool $prettyPrint = false): string { return json_encode( $this->toArray(), $prettyPrint ? JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE : 0 ); } /** * Sauvegarde la carte dans un fichier JSON * * @param string $filePath Le chemin du fichier * @return bool True si la sauvegarde a réussi */ public function saveToFile(string $filePath): bool { try { $json = $this->toJson(true); $result = file_put_contents($filePath, $json); return $result !== false; } catch (Exception $e) { AppDebugger::log('Erreur lors de la sauvegarde de la carte: ' . $e->getMessage(), 'ERROR'); return false; } } /** * Charge une carte depuis un tableau * * @param array $data Les données de la carte * @return Map|null La carte chargée ou null en cas d'erreur */ public static function fromArray(array $data): ?Map { try { $map = new self($data['name'], $data['width'], $data['height']); $map->createdAt = $data['created_at'] ?? date('Y-m-d H:i:s'); $map->updatedAt = $data['updated_at'] ?? date('Y-m-d H:i:s'); // Charger les hexagones foreach ($data['hexagons'] as $hexagonData) { $q = $hexagonData['q']; $r = $hexagonData['r']; if ($map->isValidCoordinate($q, $r)) { $map->hexagons[$q][$r] = Hexagon::fromArray($hexagonData); } } return $map; } catch (Exception $e) { AppDebugger::log('Erreur lors du chargement de la carte depuis un tableau: ' . $e->getMessage(), 'ERROR'); return null; } } /** * Charge une carte depuis un fichier JSON * * @param string $filePath Le chemin du fichier * @return Map|null La carte chargée ou null en cas d'erreur */ public static function fromFile(string $filePath): ?Map { try { if (!file_exists($filePath)) { return null; } $json = file_get_contents($filePath); $data = json_decode($json, true); if (json_last_error() !== JSON_ERROR_NONE) { AppDebugger::log('Erreur JSON lors du chargement du fichier: ' . json_last_error_msg(), 'ERROR'); return null; } return self::fromArray($data); } catch (Exception $e) { AppDebugger::log('Erreur lors du chargement de la carte depuis un fichier: ' . $e->getMessage(), 'ERROR'); return null; } } // Getters public function getName(): string { return $this->name; } public function getWidth(): int { return $this->width; } public function getHeight(): int { return $this->height; } public function getCreatedAt(): string { return $this->createdAt; } public function getUpdatedAt(): string { return $this->updatedAt; } // Setters public function setName(string $name): void { $this->name = $name; $this->updatedAt = date('Y-m-d H:i:s'); } } } /** * Classe Hexagon * * Représente un hexagone individuel dans la carte. */ if (!class_exists('Hexagon')) { class Hexagon { /** * @var int Coordonnée Q (axe horizontal) */ private int $q; /** * @var int Coordonnée R (axe diagonal) */ private int $r; /** * @var Tile|null La tuile de l'hexagone */ private ?Tile $tile; /** * Constructeur d'un hexagone * * @param int $q Coordonnée Q * @param int $r Coordonnée R * @param Tile|null $tile La tuile initiale (null pour vide) */ public function __construct(int $q, int $r, ?Tile $tile = null) { $this->q = $q; $this->r = $r; $this->tile = $tile; } /** * Définit la tuile * * @param Tile|null $tile La nouvelle tuile (null pour vider) */ public function setTile(?Tile $tile): void { $this->tile = $tile; } /** * Récupère la tuile * * @return Tile|null La tuile ou null si vide */ public function getTile(): ?Tile { return $this->tile; } /** * Vérifie si l'hexagone est vide * * @return bool True si l'hexagone est vide */ public function isEmpty(): bool { return $this->tile === null || $this->tile->isEmpty() || $this->tile->getType() === 'empty'; } /** * Récupère le type de tuile (méthode de compatibilité) * * @return string|null Le type de tuile ou null */ public function getTileType(): ?string { return $this->tile ? $this->tile->getType() : null; } /** * Définit le type de tuile (méthode de compatibilité) * * @param string $tileType Le type de tuile */ public function setTileType(string $tileType): void { if ($this->tile === null) { $this->tile = new Tile(); } $this->tile->setType($tileType); } /** * Calcule la coordonnée S (pour les coordonnées cubiques) * * @return int La coordonnée S */ public function getS(): int { return -$this->q - $this->r; } /** * Calcule la distance à un autre hexagone * * @param Hexagon $other L'autre hexagone * @return int La distance */ public function distanceTo(Hexagon $other): int { return (abs($this->q - $other->q) + abs($this->r - $other->r) + abs($this->getS() - $other->getS())) / 2; } /** * Récupère les hexagones voisins * * @return array Les directions vers les voisins [q, r] */ public static function getNeighbors(): array { return [ [1, 0], // Est [1, -1], // Nord-Est [0, -1], // Nord-Ouest [-1, 0], // Ouest [-1, 1], // Sud-Ouest [0, 1] // Sud-Est ]; } /** * Convertit l'hexagone en tableau pour la sérialisation * * @return array Les données de l'hexagone */ public function toArray(): array { return [ 'q' => $this->q, 'r' => $this->r, 'tile' => $this->tile ? $this->tile->toArray() : null ]; } /** * Crée un hexagone depuis un tableau * * @param array $data Les données de l'hexagone * @return Hexagon L'hexagone créé */ public static function fromArray(array $data): Hexagon { $tile = null; if (isset($data['tile']) && $data['tile'] !== null) { $tile = Tile::fromArray($data['tile']); } elseif (isset($data['tile_type'])) { // Compatibilité avec l'ancien format $tile = new Tile(['type' => $data['tile_type']]); } return new self($data['q'], $data['r'], $tile); } // Getters public function getQ(): int { return $this->q; } public function getR(): int { return $this->r; } } }