| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771 |
- <?php
- /**
- * Classe Tile
- *
- * Représente une tuile avec des propriétés arbitraires.
- */
- if (!class_exists('Tile')) {
- class Tile
- {
- /**
- * @var array Les propriétés de la tuile
- */
- private array $properties;
- /**
- * Constructeur d'une tuile
- *
- * @param array $properties Les propriétés initiales de la tuile
- */
- public function __construct(array $properties = [])
- {
- $this->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
- {
- // Calculer le nombre réel d'hexagones présents (certains emplacements peuvent être absents
- // lorsqu'on construit une carte à partir d'un rayon hexagonal)
- $totalHexagons = 0;
- foreach ($this->hexagons as $row) {
- $totalHexagons += count($row);
- }
- $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)
- ];
- }
- /**
- * Crée une carte à partir d'un rayon hexagonal (axial coordinates)
- *
- * @param string $name
- * @param int $radius
- * @return Map
- */
- public static function fromRadius(string $name, int $radius): Map
- {
- // Bounding box size
- $size = 2 * $radius + 1;
- $map = new self($name, $size, $size);
- // Remplacer l'initialisation par une grille qui contient uniquement
- // les hexagones à l'intérieur du rayon. Les hexagones sont indexés
- // dans l'array par des indices positifs (offset) mais conservent
- // leurs coordonnées axiales originales dans l'objet Hexagon.
- $map->hexagons = [];
- for ($q = -$radius; $q <= $radius; $q++) {
- $r1 = max(-$radius, -$q - $radius);
- $r2 = min($radius, -$q + $radius);
- for ($r = $r1; $r <= $r2; $r++) {
- $qi = $q + $radius; // index pour stockage
- $ri = $r + $radius;
- if (!isset($map->hexagons[$qi])) $map->hexagons[$qi] = [];
- $map->hexagons[$qi][$ri] = new Hexagon($q, $r, new Tile(['type' => 'empty']));
- }
- }
- return $map;
- }
- /**
- * 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 {
- $dir = dirname($filePath);
- if (!is_dir($dir)) {
- mkdir($dir, 0755, true);
- }
- $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; }
- }
- }
|