nBiker77

Laberinto con A Star y Raylib

Apr 14th, 2024
1,084
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.87 KB | Gaming | 0 0
  1. //
  2. // ██╗      █████╗ ██████╗ ███████╗██████╗ ██╗███╗   ██╗████████╗ ██████╗
  3. // ██║     ██╔══██╗██╔══██╗██╔════╝██╔══██╗██║████╗  ██║╚══██╔══╝██╔═══██╗
  4. // ██║     ███████║██████╔╝█████╗  ██████╔╝██║██╔██╗ ██║   ██║   ██║   ██║
  5. // ██║     ██╔══██║██╔══██╗██╔══╝  ██╔══██╗██║██║╚██╗██║   ██║   ██║   ██║
  6. // ███████╗██║  ██║██████╔╝███████╗██║  ██║██║██║ ╚████║   ██║   ╚██████╔╝
  7. // ╚══════╝╚═╝  ╚═╝╚═════╝ ╚══════╝╚═╝  ╚═╝╚═╝╚═╝  ╚═══╝   ╚═╝    ╚═════╝
  8.  
  9. /*
  10. Nombre del archivo: laberinto.cpp
  11. Nombre del programa: Laberinto solucion por algoitmos de busqueda
  12.  
  13. Autor(es): Natxo Varona, IA's
  14. Fecha de creación: 2024-04-12
  15. Versión: 1.5
  16. Licencia: GPLv3
  17. Descripción breve: Este programa calcula la forma optima de salir de un laberinto.
  18. Palabras clave: laberinto, aritmético, busqueda, cálculo, .
  19. Dependencias: libreiria raylib
  20.  
  21. Descripcion: Resolucion de un supuesto laberinto utilizando el Algoritmo (A-star).*
  22.  
  23. Este código implementa el algoritmo A* para encontrar la ruta más corta en un laberinto representado
  24. por una matriz de caracteres. Se utiliza una cola de prioridad para explorar los nodos de acuerdo con
  25. su valor de f, que es la suma de los valores g y h. La función de evaluación h es la distancia
  26. euclidiana desde un nodo hasta el nodo objetivo. La función de evaluación g es la distancia
  27. recorrida desde el nodo inicial hasta el nodo actual.
  28.  
  29. Instrucciones de uso:
  30. 1. Compilar el programa: g++ laberinto.cpp -o laberinto -lraylib -std=c++11
  31. 2. Ejecutar el programa: ./laberinto
  32. 3. Ingresar los números separados por espacios: 1 2 3 4 5
  33. 4. El programa mostrará en una ventana grafica un laberinto y su solucion.
  34.  
  35. Historial de cambios:
  36. - Versión 1.0 (2024-04-12): Implementación inicial del programa.
  37. - Versión 1.5 (2024-04-14): Implementacion de impresion de inicio, final y ruta.
  38. */
  39.  
  40. #include <iostream>
  41. #include <ctime>
  42. #include <vector>
  43. #include <queue>
  44. #include <utility>
  45. #include <cmath>
  46. #include <climits>
  47. #include <raylib.h>
  48.  
  49. using namespace std;
  50.  
  51. // Definicion de variables y constantes para el programa -----------------
  52. Color Green = Color{38, 185, 154, 255};
  53. Color Dark_Green = Color{20, 160, 133, 255};
  54. Color Light_Green = Color{129, 204, 184, 255};
  55. Color Yellow = Color{243, 213, 91, 255};
  56. Color Grey = Color{29, 29, 29, 255};
  57. Color lightGreen = {173, 204, 96, 255};
  58. Color darkGreen = {43, 51, 24, 255};
  59.  
  60. const int START = 2;     // Carácter que representa el inicio
  61. const int GOAL = 3;      // Carácter que representa la meta
  62. const int mazeWidth = 10;
  63. const int mazeHeight = 10;
  64.  
  65. // Definición del laberinto como una matriz de caracteres ---------------
  66. int maze[mazeWidth][mazeHeight] = {
  67.     {1, 2, 1, 1, 1, 1, 1, 1, 1, 1},
  68.     {1, 0, 0, 0, 1, 0, 0, 0, 0, 1},
  69.     {1, 0, 1, 0, 1, 0, 1, 1, 0, 1},
  70.     {1, 0, 1, 0, 1, 0, 1, 0, 0, 1},
  71.     {1, 0, 1, 0, 1, 0, 1, 0, 1, 1},
  72.     {1, 0, 1, 0, 0, 0, 1, 0, 0, 1},
  73.     {1, 0, 1, 1, 1, 0, 1, 1, 0, 1},
  74.     {1, 0, 0, 0, 1, 0, 0, 0, 0, 1},
  75.     {1, 1, 1, 0, 1, 1, 1, 1, 0, 1},
  76.     {1, 1, 1, 1, 1, 1, 1, 1, 3, 1}
  77. };
  78.  
  79. // Direcciones posibles para explorar (arriba, abajo, izquierda, derecha)
  80. int dx[] = {-1, 1, 0, 0};
  81. int dy[] = {0, 0, -1, 1};
  82.  
  83. // Función para calcular la distancia euclidiana entre dos puntos en el laberinto
  84. double heuristic(int x, int y, int goal_x, int goal_y) {
  85.     return sqrt((x - goal_x) * (x - goal_x) + (y - goal_y) * (y - goal_y));
  86. }
  87.  
  88. // Estructura para representar un nodo en el laberinto
  89. struct Node {
  90.     int x, y;       // Posición del nodo
  91.     double f, g, h; // Valores de la función de evaluación
  92. };
  93.  
  94. // Sobrecarga del operador < para ordenar los nodos en función del valor f
  95. bool operator<(const Node& a, const Node& b) {
  96.     return a.f > b.f; // Orden inverso para que la cola de prioridad tenga el menor f en el frente
  97. }
  98.  
  99. // Función para verificar si una posición está dentro del laberinto y es transitable
  100. bool isValid(int x, int y, int mazeWidth, int mazeHeight) {
  101.     return (x >= 0 && x < mazeWidth && y >= 0 && y < mazeHeight && maze[x][y] != '1');
  102. }
  103.  
  104. // Función para encontrar la ruta más corta utilizando el algoritmo A*
  105. vector<pair<int, int>> AStar(int start_x, int start_y, int goal_x, int goal_y, int mazeWidth, int mazeHeight) {
  106.     // Crear una cola de prioridad para almacenar los nodos a explorar
  107.     priority_queue<Node> pq;
  108.  
  109.     // Crear un arreglo para almacenar los valores de g y h de cada nodo
  110.     vector<vector<pair<double, double>>> values(mazeWidth, vector<pair<double, double>>(mazeHeight, {INFINITY, INFINITY}));
  111.  
  112.     // Crear un arreglo para almacenar el camino encontrado
  113.     vector<pair<int, int>> path;
  114.  
  115.     // Insertar el nodo inicial en la cola de prioridad
  116.     pq.push({start_x, start_y, 0.0, 0.0, heuristic(start_x, start_y, goal_x, goal_y)});
  117.     values[start_x][start_y] = {0.0, heuristic(start_x, start_y, goal_x, goal_y)};
  118.  
  119.     while (!pq.empty()) {
  120.         // Obtener el nodo con el menor valor f de la cola de prioridad
  121.         Node current = pq.top();
  122.         pq.pop();
  123.  
  124.         int x = current.x;
  125.         int y = current.y;
  126.  
  127.         // Verificar si se alcanzó el nodo objetivo
  128.         if (x == goal_x && y == goal_y) {
  129.             // Rastrear el camino desde el nodo objetivo hasta el nodo inicial
  130.             int cx = goal_x, cy = goal_y;
  131.             while (cx != start_x || cy != start_y) {
  132.                 path.push_back({cx, cy});
  133.                 double min_f = INFINITY;
  134.                 int nx, ny;
  135.                 for (int i = 0; i < 4; ++i) {
  136.                     int nx = cx + dx[i];
  137.                     int ny = cy + dy[i];
  138.                     if (isValid(nx, ny, mazeWidth, mazeHeight) && values[nx][ny].first + values[nx][ny].second < min_f) {
  139.                         min_f = values[nx][ny].first + values[nx][ny].second;
  140.                         cx = nx;
  141.                         cy = ny;
  142.                     }
  143.                 }
  144.             }
  145.             path.push_back({start_x, start_y});
  146.             reverse(path.begin(), path.end());  // Invertir el camino para que esté en el orden correcto
  147.             return path;
  148.         }
  149.  
  150.         // Explorar los nodos vecinos
  151.         for (int i = 0; i < 4; ++i) {
  152.             int nx = x + dx[i];
  153.             int ny = y + dy[i];
  154.  
  155.             // Verificar si la posición vecina es válida
  156.             if (isValid(nx, ny, mazeWidth, mazeHeight)) {
  157.                 double new_g = current.g + 1.0; // Distancia hasta el vecino (asumiendo un costo de movimiento de 1)
  158.  
  159.                 // Verificar si se encontró una mejor ruta hacia el vecino
  160.                 if (new_g < values[nx][ny].first) {
  161.                     values[nx][ny].first = new_g; // Actualizar el valor de g
  162.                     values[nx][ny].second = heuristic(nx, ny, goal_x, goal_y); // Calcular el valor de h
  163.                     pq.push({nx, ny, new_g + values[nx][ny].second, new_g, values[nx][ny].second}); // Insertar el nodo en la cola de prioridad
  164.                 }
  165.             }
  166.         }
  167.     }
  168.     // Si no se encontró ningún camino, devolver un vector vacío
  169.     return {};
  170. }
  171.  
  172. int main() {
  173.     // Comenzamos el programa ------------------------------------------
  174.     std::cout << std::endl;
  175.     std::cout << "Starting the program ..." << std::endl;
  176.     std::cout << std::endl;
  177.  
  178.     const int screen_Width = 800;       // Sin interface entero seria 300
  179.     const int screen_Height = 800;      // Sin interface entero seria 600
  180.     int FPS = 60;
  181.     bool lab = false;                   // Estado de la busqueda en el laberinto
  182.     bool gameOver = false;              // Saber si ya hemos acabado, para no volver a imprimir
  183.     const int cellSize = 50;
  184.  
  185.     // Posicion de el comienzo del laberinto y la salida del laberinto
  186.     int start_x, start_y, goal_x, goal_y;
  187.  
  188.     // Crear un arreglo para almacenar el camino encontrado
  189.     vector<pair<int, int>> path;
  190.    
  191.     InitWindow(screen_Width, screen_Height, "Resolucion de Laberintos con RayLib");
  192.     SetTargetFPS(FPS);
  193.     SetConfigFlags(FLAG_VSYNC_HINT);
  194.  
  195.     // 1. Event Handing ---------------------------------------------
  196.     BeginDrawing();
  197.     ClearBackground(WHITE);
  198.  
  199.     // Encontrar las coordenadas de inicio del laberitno '2' y objetivo de salida '3'
  200.     for (int y1 = 0; y1 < mazeHeight; ++y1) {
  201.         for (int x1 = 0; x1 < mazeWidth; ++x1) {
  202.             if (maze[y1][x1] == START) {
  203.                 start_x = x1;
  204.                 start_y = y1;
  205.             } else if (maze[y1][x1] == GOAL) {
  206.                 goal_x = x1;
  207.                 goal_y = y1;
  208.             }
  209.         }
  210.     }
  211.     //cout << endl;
  212.     //cout << "Comienzo X: " << start_x << endl;
  213.     //cout << "Comienzo Y: " << start_y << endl;
  214.     //cout << "Salida X: " << goal_x << endl;
  215.     //cout << "Salida Y: " << goal_y << endl;
  216.  
  217.     // Punto de inicio del tiempo
  218.     clock_t start = clock();
  219.  
  220.     // Llamar al algoritmo A* para encontrar la ruta más corta
  221.     path = AStar(start_x, start_y, goal_x, goal_y, mazeWidth, mazeHeight);
  222.    
  223.     // Punto de finalización del tiempo
  224.     clock_t end = clock();
  225.    
  226.     // Calcula la duración de la ejecución en milisegundos
  227.     double duration = static_cast<double>(end - start) / CLOCKS_PER_SEC * 1000;
  228.  
  229.     // Imprime el tiempo transcurrido
  230.     char durationText[30];
  231.     snprintf(durationText, sizeof(durationText), "La busqueda tardó: %.2f ms", duration);
  232.     DrawText(durationText, 400, 710, 20, RED);
  233.     //cout << endl;
  234.     //cout << "La busqueda tardó: " << duration << " ms en ejecutarse." << endl;
  235.  
  236.     // 2. Updating State --------------------------------------------
  237.  
  238.     // 3. Drawing Objects -------------------------------------------
  239.  
  240.     // Dibujar el laberinto
  241.     for (int y1 = 0; y1 < mazeHeight; y1++) {
  242.         for (int x1 = 0; x1 < mazeWidth; x1++) {
  243.             if (maze[y1][x1] == 1) {
  244.                 DrawRectangle(x1 * cellSize, y1 * cellSize, cellSize, cellSize, darkGreen);
  245.             }
  246.         }
  247.     }
  248.     DrawRectangle(start_x * cellSize, start_y * cellSize, cellSize, cellSize, Yellow);
  249.     DrawRectangle(goal_x * cellSize, goal_y * cellSize, cellSize, cellSize, Grey);
  250.     if (!path.empty()) {
  251.         //cout << endl;
  252.         //cout << "Se encontró una ruta hasta el objetivo !!" << endl;
  253.         //cout << endl;
  254.         // Imprimir el camino encontrado
  255.         //cout << "Camino encontrado:" << endl;
  256.         for (int i = path.size() - 1; i >= 0; --i) {
  257.             DrawRectangle(path[i].first * cellSize, path[i].second * cellSize, cellSize, cellSize, lightGreen); // Dibujar la solucion al laberinto
  258.             // Impresion por consola del resultado del camino optimo
  259.             //cout << "(" << path[i].first << ", " << path[i].second << ")";
  260.             //if (i > 0) cout << " -> ";
  261.         }
  262.         //cout << endl;
  263.     }
  264.    
  265.     // Mostrar mensaje de salida o repeticion.
  266.     DrawText("Pulsa una tecla para salir", 400, 750, 20, RED);
  267.     EndDrawing();
  268.     bool keyPressed = false; // Variable para almacenar si se ha presionado una tecla
  269.     while (!WindowShouldClose() && !keyPressed) {
  270.         // Esperar a que el usuario pulse la tecla SPACE para continuar
  271.         if (IsKeyPressed(KEY_SPACE)) {
  272.             keyPressed = true; // Marcar que se ha presionado una tecla
  273.         }
  274.     }
  275.  
  276.     CloseWindow();
  277.     return 0;
  278. }
  279.  
Tags: Raylib
Advertisement
Add Comment
Please, Sign In to add comment