Advertisement
nBiker77

Laberinto con A Star y Raylib

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