This commit is contained in:
2026-06-18 16:27:16 +02:00
parent a4da80cb6d
commit 5f98023fd8
+111 -44
View File
@@ -13,14 +13,72 @@ private:
int real_rows, real_cols;
std::vector<std::vector<int>> data;
public:
const int EMPTY = 0;
const int WALL = 1;
struct Cell {
int r, c;
bool operator==(const Cell& other) const { return r == other.r && c == other.c; }
};
bool isValid(int r, int c, const std::vector<std::vector<bool>>& visited) {
Maze(int r, int c) : n_rows(r), n_cols(c) {
real_rows = 2 * n_rows + 1;
real_cols = 2 * n_cols + 1;
data.assign(real_rows, std::vector<int>(real_cols, WALL));
generateMaze();
}
int getRealRows() const { return real_rows; }
int getRealCols() const { return real_cols; }
int getValue(int r, int c) const { return data[r][c]; }
bool isValid(int r, int c) const {
return (r >= 0 && r < real_rows && c >= 0 && c < real_cols);
}
// Algoritmo de resolución: Busca recursivamente el camino guardando el historial (visited)
bool findShortestPath(Cell current, Cell target, std::vector<std::vector<bool>>& visited, std::vector<Cell>& path) {
// Casos base: fuera de límites, obstáculo o ya visitado
if (!isValid(current.r, current.c) || data[current.r][current.c] == WALL || visited[current.r][current.c]) {
return false;
}
// Añadir la celda actual al camino provisional
path.push_back(current);
visited[current.r][current.c] = true;
// Si hemos llegado al destino, el camino es válido
if (current == target) {
return true;
}
// Movimientos ortogonales en la matriz real (de 1 en 1)
int dr[] = {-1, 1, 0, 0};
int dc[] = {0, 0, -1, 1};
for (int i = 0; i < 4; ++i) {
Cell next = {current.r + dr[i], current.c + dc[i]};
if (findShortestPath(next, target, visited, path)) {
return true;
}
}
// Backtracking: si ninguna dirección funcionó, quitamos la celda del camino
path.pop_back();
return false;
}
// Método auxiliar para lanzar la búsqueda del camino
std::vector<Cell> getPath(Cell start, Cell end) {
std::vector<std::vector<bool>> visited(real_rows, std::vector<bool>(real_cols, false));
std::vector<Cell> path;
findShortestPath(start, end, visited, path);
return path;
}
private:
bool isLogicalValid(int r, int c, const std::vector<std::vector<bool>>& visited) {
return (r >= 0 && r < n_rows && c >= 0 && c < n_cols && !visited[r][c]);
}
@@ -37,7 +95,6 @@ private:
Cell current = {0, 0};
visited[current.r][current.c] = true;
data[1][1] = EMPTY;
cellStack.push(current);
while (!cellStack.empty()) {
@@ -45,7 +102,7 @@ private:
std::vector<int> neighbors;
for (int i = 0; i < 4; ++i) {
if (isValid(current.r + dr[i], current.c + dc[i], visited)) {
if (isLogicalValid(current.r + dr[i], current.c + dc[i], visited)) {
neighbors.push_back(i);
}
}
@@ -75,22 +132,10 @@ private:
}
}
// Perforar entrada y salida
// Perforamos de forma segura la entrada y salida iniciales en la matriz
data[1][0] = EMPTY;
data[real_rows - 2][real_cols - 1] = EMPTY;
}
public:
Maze(int r, int c) : n_rows(r), n_cols(c) {
real_rows = 2 * n_rows + 1;
real_cols = 2 * n_cols + 1;
data.assign(real_rows, std::vector<int>(real_cols, WALL));
generateMaze();
}
int getRealRows() const { return real_rows; }
int getRealCols() const { return real_cols; }
int getValue(int r, int c) const { return data[r][c]; }
};
int main(int argc, char* argv[]) {
@@ -107,76 +152,98 @@ int main(int argc, char* argv[]) {
return 1;
}
// Generar el laberinto
Maze maze(filas, columnas);
// Configuración de píxeles por celda
const float CELL_SIZE = 16.0f;
int window_width = maze.getRealCols() * CELL_SIZE;
int window_height = maze.getRealRows() * CELL_SIZE;
// Inicializar SDL3
if (!SDL_Init(SDL_INIT_VIDEO)) {
std::cerr << "Error al inicializar SDL3: " << SDL_GetError() << "\n";
return 1;
}
// Crear ventana y renderer con la API moderna de SDL3
SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
if (!SDL_CreateWindowAndRenderer("Generador de Laberintos (SDL3)", window_width, window_height, 0, &window, &renderer)) {
if (!SDL_CreateWindowAndRenderer("Laberinto Interactivo (SDL3)", window_width, window_height, 0, &window, &renderer)) {
std::cerr << "Error al crear la ventana/renderer: " << SDL_GetError() << "\n";
SDL_Quit();
return 1;
}
// Puntos de inicio y fin iniciales (coordenadas reales de la matriz)
Maze::Cell startPoint = {1, 0};
Maze::Cell endPoint = {maze.getRealRows() - 2, maze.getRealCols() - 1};
// Calcular la ruta inicial
std::vector<Maze::Cell> currentPath = maze.getPath(startPoint, endPoint);
bool running = true;
SDL_Event event;
// Bucle principal de renderizado
while (running) {
// Manejo de eventos (cerrar ventana o pulsar ESC)
while (SDL_PollEvent(&event)) {
if (event.type == SDL_EVENT_QUIT) {
running = false;
} else if (event.type == SDL_EVENT_KEY_DOWN) {
if (event.key.key == SDLK_ESCAPE) {
running = false;
}
else if (event.type == SDL_EVENT_KEY_DOWN) {
if (event.key.key == SDLK_ESCAPE) running = false;
}
// Manejo de clicks de ratón
else if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
// Calcular qué celda de la matriz real se ha pulsado
int clicked_c = event.button.x / CELL_SIZE;
int clicked_r = event.button.y / CELL_SIZE;
if (maze.isValid(clicked_r, clicked_c) && maze.getValue(clicked_r, clicked_c) == maze.EMPTY) {
if (event.button.button == SDL_BUTTON_LEFT) {
startPoint = {clicked_r, clicked_c};
} else if (event.button.button == SDL_BUTTON_RIGHT) {
endPoint = {clicked_r, clicked_c};
}
// Recalcular la ruta más corta tras cambiar un punto
currentPath = maze.getPath(startPoint, endPoint);
}
}
}
// Limpiar pantalla en negro (los pasillos y fondo)
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
// Fondo de la ventana (Pasillos)
SDL_SetRenderDrawColor(renderer, 15, 15, 20, 255);
SDL_RenderClear(renderer);
// Dibujar los muros
// El color gris oscuro/azul destaca muy bien para los muros
SDL_SetRenderDrawColor(renderer, 40, 50, 70, 255);
// 1. Dibujar Muros
SDL_SetRenderDrawColor(renderer, 45, 50, 65, 255); // Gris azulado para muros
for (int i = 0; i < maze.getRealRows(); ++i) {
for (int j = 0; j < maze.getRealCols(); ++j) {
if (maze.getValue(i, j) == 1) { // Si es un muro (WALL)
SDL_FRect rect;
rect.x = j * CELL_SIZE;
rect.y = i * CELL_SIZE;
rect.w = CELL_SIZE;
rect.h = CELL_SIZE;
if (maze.getValue(i, j) == maze.WALL) {
SDL_FRect rect = { j * CELL_SIZE, i * CELL_SIZE, CELL_SIZE, CELL_SIZE };
SDL_RenderFillRect(renderer, &rect);
}
}
}
// Presentar el frame en pantalla
// 2. Dibujar el camino óptimo calculado (Azul celeste)
SDL_SetRenderDrawColor(renderer, 0, 180, 255, 255);
for (const auto& cell : currentPath) {
SDL_FRect rect = { cell.c * CELL_SIZE, cell.r * CELL_SIZE, CELL_SIZE, CELL_SIZE };
SDL_RenderFillRect(renderer, &rect);
}
// 3. Dibujar Punto de Inicio (Verde)
SDL_SetRenderDrawColor(renderer, 50, 220, 100, 255);
SDL_FRect startRect = { startPoint.c * CELL_SIZE, startPoint.r * CELL_SIZE, CELL_SIZE, CELL_SIZE };
SDL_RenderFillRect(renderer, &startRect);
// 4. Dibujar Punto de Fin (Rojo)
SDL_SetRenderDrawColor(renderer, 255, 60, 60, 255);
SDL_FRect endRect = { endPoint.c * CELL_SIZE, endPoint.r * CELL_SIZE, CELL_SIZE, CELL_SIZE };
SDL_RenderFillRect(renderer, &endRect);
SDL_RenderPresent(renderer);
// Pequeño delay para no saturar la CPU a miles de FPS innecesariamente
SDL_Delay(16);
SDL_Delay(16);
}
// Limpieza final de recursos
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();