From 5f98023fd8d998e4465fef4b03e831253886810a Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 18 Jun 2026 16:27:16 +0200 Subject: [PATCH] getPath --- main.cpp | 155 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 111 insertions(+), 44 deletions(-) diff --git a/main.cpp b/main.cpp index 6a3c866..03350fe 100644 --- a/main.cpp +++ b/main.cpp @@ -13,14 +13,72 @@ private: int real_rows, real_cols; std::vector> 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>& 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(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>& visited, std::vector& 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 getPath(Cell start, Cell end) { + std::vector> visited(real_rows, std::vector(real_cols, false)); + std::vector path; + findShortestPath(start, end, visited, path); + return path; + } + +private: + bool isLogicalValid(int r, int c, const std::vector>& 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 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(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 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();