Grid.cpp h - JulianKerignard/ProjetJeuDeLaVie_POO GitHub Wiki
#ifndef GRID_H
#define GRID_H
#include <vector>
#include "Cell.h"
// Enumération pour les différents motifs de cellules
enum class Pattern {
GLIDER, // Motif de planeur
BLINKER, // Motif de clignotant
BLOCK, // Motif de bloc
BEACON // Motif de balise
};
// Classe représentant une grille de cellules pour le Jeu de la Vie
class Grid {
private:
std::vector<std::vector<Cell>> cells; // Grille de cellules
int width; // Largeur de la grille
int height; // Hauteur de la grille
bool isToroidal; // Mode torique (bords connectés)
// Méthodes privées de gestion des indices et des voisins
int getValidIndex(int index, int max) const;
int countLiveNeighbors(int x, int y) const;
public:
// Constructeur avec dimensions de la grille
Grid(int width, int height);
// Mise à jour des cellules de la grille
void updateCells();
// Accesseur pour une cellule (modifiable)
Cell& getCellAt(int x, int y);
// Accesseur pour une cellule (non-modifiable)
const Cell& getCellAt(int x, int y) const;
// Modificateur pour l'état d'une cellule
void setCellAt(int x, int y, CellState state);
// Obtient les voisins d'une cellule
std::vector<std::pair<int, int>> getNeighbors(int x, int y) const;
// Définit le mode torique de la grille
void setToroidal(bool enabled) { isToroidal = enabled; }
// Ajoute un obstacle à la grille
void addObstacle(int x, int y);
// Ajoute un motif à la grille
void addPattern(Pattern pattern, int x, int y);
// Accesseurs pour la largeur et la hauteur de la grille
int getWidth() const { return width; }
int getHeight() const { return height; }
bool getToroidal() const { return isToroidal; }
};
#endif // GRID_H
-
Enumération
Pattern
:- Définit les différents motifs de cellules :
-
GLIDER
: Motif de planeur. -
BLINKER
: Motif de clignotant. -
BLOCK
: Motif de bloc. -
BEACON
: Motif de balise.
-
- Définit les différents motifs de cellules :
-
Classe
Grid
:-
Représente une grille de cellules pour le Jeu de la Vie.
-
Membres privés :
-
std::vector<std::vector<Cell>> cells
: Grille de cellules. -
int width
: Largeur de la grille. -
int height
: Hauteur de la grille. -
bool isToroidal
: Indique si la grille est en mode torique.
-
-
Membres publics :
-
Grid(int width, int height) :
- Constructeur qui initialise la grille avec les dimensions spécifiées.
-
void updateCells() :
- Met à jour l'état des cellules dans la grille.
-
Cell& getCellAt(int x, int y) :
- Accesseur modifiable pour une cellule aux coordonnées spécifiées.
-
const Cell& getCellAt(int x, int y) const :
- Accesseur non modifiable pour une cellule aux coordonnées spécifiées.
-
void setCellAt(int x, int y, CellState state) :
- Modifie l'état de la cellule aux coordonnées spécifiées.
-
std::vector<std::pair<int, int>> getNeighbors(int x, int y) const :
- Retourne les coordonnées des cellules voisines d'une cellule donnée.
-
void setToroidal(bool enabled) :
- Active ou désactive le mode torique de la grille.
-
void addObstacle(int x, int y) :
- Ajoute un obstacle à la grille aux coordonnées spécifiées.
-
void addPattern(Pattern pattern, int x, int y) :
- Ajoute un motif de cellules à la grille aux coordonnées spécifiées.
-
int getWidth() const :
- Retourne la largeur de la grille.
-
int getHeight() const :
- Retourne la hauteur de la grille.
-
bool getToroidal() const :
- Retourne l'état du mode torique de la grille.
-
Grid(int width, int height) :
-
-
Grid(int width, int height) :
- Initialise une grille avec les dimensions spécifiées. Lance une exception si les dimensions ne sont pas positives.
Grid::Grid(int width, int height)
: width(width), height(height), isToroidal(false) {
if (width <= 0 || height <= 0) {
throw std::invalid_argument("Grid dimensions must be positive");
}
cells.resize(height, std::vector<Cell>(width));
}
-
void setCellAt(int x, int y, CellState state) :
- Modifie l'état de la cellule aux coordonnées spécifiées. Lance une exception si les coordonnées sont hors limites et que le mode torique est désactivé.
void Grid::setCellAt(int x, int y, CellState state) {
int validX = x;
int validY = y;
if (isToroidal) {
validX = ((x % width) + width) % width;
validY = ((y % height) + height) % height;
} else if (x < 0 || x >= width || y < 0 || y >= height) {
throw std::out_of_range("Cell coordinates out of range");
}
cells[validY][validX] = Cell(state);
}
-
int getValidIndex(int index, int max) const :
- Retourne l'index valide en tenant compte du mode torique.
int Grid::getValidIndex(int index, int max) const {
if (isToroidal) {
return ((index % max) + max) % max;
}
return index;
}
-
int countLiveNeighbors(int x, int y) const :
- Compte le nombre de voisins vivants autour de la cellule aux coordonnées spécifiées.
int Grid::countLiveNeighbors(int x, int y) const {
int count = 0;
for (const auto& neighbor : getNeighbors(x, y)) {
const Cell& neighborCell = getCellAt(neighbor.first, neighbor.second);
if (!neighborCell.isObstacleCell() && neighborCell.getCurrentState() == CellState::ALIVE) {
count++;
}
}
return count;
}
-
void updateCells() :
- Met à jour l'état des cellules de la grille. Utilise plusieurs threads pour améliorer les performances.
void Grid::updateCells() {
auto start = std::chrono::high_resolution_clock::now();
// Créer une copie de la grille pour les calculs
auto newCells = cells;
// Calculer le nombre optimal de threads
int threadCount = std::min(static_cast<int>(std::thread::hardware_concurrency()), height);
std::vector<std::thread> threads;
threads.reserve(threadCount);
// S'assurer qu'il y a au moins une ligne par thread
const int rowsPerThread = std::max(1, height / threadCount);
threadCount = (height + rowsPerThread - 1) / rowsPerThread;
// Mise à jour des états
for (int i = 0; i < threadCount; ++i) {
int startRow = i * rowsPerThread;
int endRow = std::min(startRow + rowsPerThread, height);
threads.emplace_back([this, &newCells, startRow, endRow, i]() {
std::cout << "Thread " << i << " traite les lignes " << startRow << " à " << endRow - 1 << std::endl;
for (int y = startRow; y < endRow; y++) {
for (int x = 0; x < width; x++) {
if (cells[y][x].isObstacleCell()) {
continue;
}
int liveNeighbors = countLiveNeighbors(x, y);
CellState currentState = cells[y][x].getCurrentState();
if (currentState == CellState::DEAD) {
if (liveNeighbors == 3) {
newCells[y][x] = Cell(CellState::ALIVE);
}
} else { // ALIVE
if (liveNeighbors < 2 || liveNeighbors > 3) {
newCells[y][x] = Cell(CellState::DEAD);
}
}
}
}
});
}
// Attendre que tous les threads terminent
for (auto& thread : threads) {
thread.join();
}
// Mettre à jour la grille avec les nouveaux états
cells = std::move(newCells);
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "Mise à jour effectuée en " << duration.count()
<< " microsecondes avec " << threadCount << " threads" << std::endl;
}
-
Cell& getCellAt(int x, int y) :
- Retourne une référence à la cellule aux coordonnées spécifiées.
Cell& Grid::getCellAt(int x, int y) {
if (isToroidal) {
x = ((x % width) + width) % width;
y = ((y % height) + height) % height;
} else if (x < 0 || x >= width || y < 0 || y >= height) {
throw std::out_of_range("Cell coordinates out of range");
}
return cells[y][x];
}
-
const Cell& getCellAt(int x, int y) const :
- Retourne une référence constante à la cellule aux coordonnées spécifiées.
const Cell& Grid::getCellAt(int x, int y) const {
return const_cast<Grid*>(this)->getCellAt(x, y);
}
-
void addObstacle(int x, int y) :
- Ajoute un obstacle à la grille aux coordonnées spécifiées.
void Grid::addObstacle(int x, int y) {
if (isToroidal) {
x = ((x % width) + width) % width;
y = ((y % height) + height) % height;
} else if (x < 0 || x >= width || y < 0 || y >= height) {
throw std::out_of_range("Obstacle coordinates out of range");
}
cells[y][x].setObstacle(true);
}
-
std::vector<std::pair<int, int>> getNeighbors(int x, int y) const :
- Retourne les coordonnées des cellules voisines d'une cellule donnée.
std::vector<std::pair<int, int>> Grid::getNeighbors(int x, int y) const {
std::vector<std::pair<int, int>> neighbors;
neighbors.reserve(8);
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
if (dx == 0 && dy == 0) continue;
int newX = x + dx;
int newY = y + dy;
if (isToroidal) {
newX = ((newX % width) + width) % width;
newY = ((newY % height) + height) % height;
neighbors.emplace_back(newX, newY);
} else if (newX >= 0 && newX < width && newY >= 0 && newY < height) {
neighbors.emplace_back(newX, newY);
}
}
}
return neighbors;
}
-
void addPattern(Pattern pattern, int x, int y) :
- Ajoute un motif de cellules à la grille aux coordonnées spécifiées.
void Grid::addPattern(Pattern pattern, int x, int y) {
switch (pattern) {
case Pattern::GLIDER:
if (x + 2 < width && y + 2 < height) {
setCellAt(x + 1, y, CellState::ALIVE);
setCellAt(x + 2, y + 1, CellState::ALIVE);
setCellAt(x, y + 2, CellState::ALIVE);
setCellAt(x + 1, y + 2, CellState::ALIVE);
setCellAt(x + 2, y + 2, CellState::ALIVE);
}
break;
case Pattern::BLINKER:
if (x + 2 < width && y < height) {
setCellAt(x, y, CellState::ALIVE);
setCellAt(x + 1, y, CellState::ALIVE);
setCellAt(x + 2, y, CellState::ALIVE);
}
break;
case Pattern::BLOCK:
if (x + 1 < width && y + 1 < height) {
setCellAt(x, y, CellState::ALIVE);
setCellAt(x + 1, y, CellState::ALIVE);
setCellAt(x, y + 1, CellState::ALIVE);
setCellAt(x + 1, y + 1, CellState::ALIVE);
}
break;
case Pattern::BEACON:
if (x + 3 < width && y + 3 < height) {
setCellAt(x, y, CellState::ALIVE);
setCellAt(x + 1, y, CellState::ALIVE);
setCellAt(x, y + 1, CellState::ALIVE);
setCellAt(x + 3, y + 2, CellState::ALIVE);
setCellAt(x + 2, y + 3, CellState::ALIVE);
setCellAt(x + 3, y + 3, CellState::ALIVE);
}
break;
}
}