Lyt
Coder
Hi, I'm making a little game for a college project.
I was asked by the professor to implement a pathfinding system. He also recommended a site to get the code from https://www.redblobgames.com/pathfinding/a-star/implementation.html. So I took the code, adapted it, translated the comments into Italian (my language) and split it into two files AStar.cpp and Map.cpp. The problem is that in order for the code to work I need to create the respective .h files. I have been trying for several days but still have problems. Would anyone know how to give me a hand? it's my first time working on someone else's code.
this is the Map.cpp file
this is the AStar.cpp file
I've already made several attempts, but they don't work.
Obviously I don't expect you to make me create the .h files, but if possible would you help me understand what I'm doing wrong? My files are now:
AStar.cpp
Astar.h
Map.cpp
Map.h
Here it gives me error to "find ()". But it only started after the CLion update, I don't understand why.
Thanks in advance everyone, and sorry if I made some grammatical errors, as I mentioned this is not my mother tongue
I was asked by the professor to implement a pathfinding system. He also recommended a site to get the code from https://www.redblobgames.com/pathfinding/a-star/implementation.html. So I took the code, adapted it, translated the comments into Italian (my language) and split it into two files AStar.cpp and Map.cpp. The problem is that in order for the code to work I need to create the respective .h files. I have been trying for several days but still have problems. Would anyone know how to give me a hand? it's my first time working on someone else's code.
this is the Map.cpp file
C++:
#include "librerie.h"
//Crea un tipo di dato GridLocation, che contiene la posizione sulla scacchiera
struct GridLocation {
int x, y;
};
namespace std {
//implementare la funzione hash in modo da poter inserire GridLocation in un unordered_set
//I unordered_set sono contenitori che memorizzano elementi univoci in nessun ordine particolare
// e che consentono il recupero rapido di singoli elementi in base al loro valore.
template <> struct hash<GridLocation> {
std::size_t operator()(const GridLocation& id) const noexcept {
// NOTE: better to use something like boost hash_combine
return std::hash<int>()(id.x ^ (id.y << 16));
}
};
}
struct SquareGrid {
static std::array<GridLocation, 4> DIRS;
int width, height;
std::unordered_set<GridLocation> walls;
SquareGrid(int width_, int height_)
: width(width_), height(height_) {}
bool in_bounds(GridLocation id) const {
return 0 <= id.x && id.x < width
&& 0 <= id.y && id.y < height;
}
bool passable(GridLocation id) const {
return walls.find(id) == walls.end();
}
std::vector<GridLocation> neighbors(GridLocation id) const {
std::vector<GridLocation> results;
for (GridLocation dir : DIRS) {
GridLocation next{id.x + dir.x, id.y + dir.y};
if (in_bounds(next) && passable(next)) {
results.push_back(next);
}
}
if ((id.x + id.y) % 2 == 0) {
// see "Ugly paths" section for an explanation:
std::reverse(results.begin(), results.end());
}
return results;
}
};
std::array<GridLocation, 4> SquareGrid::DIRS = {
//imposta le direzioni
GridLocation{1, 0}, //East
GridLocation{-1, 0}, //West
GridLocation{0, -1}, //North
GridLocation{0, 1} //South
};
// Funzioni che possono tornare utili a GridLocation
//Uguale
bool operator == (GridLocation a, GridLocation b) {
return a.x == b.x && a.y == b.y;
}
//Diverso
bool operator != (GridLocation a, GridLocation b) {
return !(a == b);
}
//Percorso
bool operator < (GridLocation a, GridLocation b) {
return std::tie(a.x, a.y) < std::tie(b.x, b.y);
}
std::basic_iostream<char>::basic_ostream& operator<<(std::basic_iostream<char>::basic_ostream& out, const GridLocation& loc) {
out << '(' << loc.x << ',' << loc.y << ')';
return out;
}
//Aggiunge i muri, può essere modificata per generare gli spazzi occupati dai pezzi
void add_rect(SquareGrid& grid, int x1, int y1, int x2, int y2) {
for (int x = x1; x < x2; ++x) {
for (int y = y1; y < y2; ++y) {
grid.walls.insert(GridLocation{x, y}); //genera effettivamente il "muro"
}
}
}
//crea la scacchiera e le mura al suo interno
//nel mio caso la scacchiera è 7x6, e non ha muri e aree difficili
//va modificato affinche aggiunga un muro per ogni pezzo che non sia quello mosso
SquareGrid MakeDiagram() {
SquareGrid grid(7, 6);
//add_rect(grid, 1, 1, 2, 2);
typedef GridLocation L;
return grid;
}
// Crea una classe generica, che viene usata per stampare il grafico della scacchiera
//non è necessaria al gioco, ma può essere utile durante lo sviluppo
template<class Graph>
void draw_grid(const Graph& graph,
std::unordered_map<GridLocation, double>* distances=nullptr,
std::unordered_map<GridLocation, GridLocation>* point_to=nullptr,
std::vector<GridLocation>* path=nullptr,
GridLocation* start=nullptr,
GridLocation* goal=nullptr) {
const int field_width = 3; //crea una costante per la quale alcuni simboli vengono stampati 3 volte
std::cout << std::string(field_width * graph.width, '_') << '\n'; //stampa la parte alta del grafico ___
for (int y = 0; y != graph.height; ++y) {
for (int x = 0; x != graph.width; ++x) {
GridLocation id {x, y};
if (graph.walls.find(id) != graph.walls.end()) {
std::cout << std::string(field_width, '#'); //stampa i muri nel grafico
} else if (start && id == *start) {
std::cout << " A "; //stampa start nel grafico
} else if (goal && id == *goal) {
std::cout << " Z "; //stampa l'obbiettivo nel grafico
} else if (path != nullptr && find(path->begin(), path->end(), id) != path->end()) {
std::cout << " @ "; //stampa il percorso nel grafico
} else if (point_to != nullptr && point_to->count(id)) {
GridLocation next = (*point_to)[id];
if (next.x == x + 1) { std::cout << " > "; } //stampano i "flussi"
else if (next.x == x - 1) { std::cout << " < "; } //che partono da start
else if (next.y == y + 1) { std::cout << " v "; } //e usati, per trovare
else if (next.y == y - 1) { std::cout << " ^ "; } //il percorso migliore
else { std::cout << " * "; }
} else if (distances != nullptr && distances->count(id)) {
std::cout << ' ' << std::left << std::setw(field_width - 1) << (*distances)[id];
} else {
std::cout << " . ";
}
}
std::cout << '\n';
}
std::cout << std::string(field_width * graph.width, '~') << '\n'; //stampa la parte bassa del grafico ~~~
}
// Funzione per calcolare la distanza da un punto A ad un punto B
template<class Graph>
int DistanceCalculation(const Graph& graph,
std::vector<GridLocation>* path=nullptr,
GridLocation* start=nullptr,
GridLocation* goal=nullptr) {
int distance=0;
for (int y = 0; y != graph.height; ++y) {
for (int x = 0; x != graph.width; ++x) {
GridLocation id{x, y};
if (find(path->begin(), path->end(), id) != path->end()) {
if(find(path->begin(), path->end(), id) == path->begin()){
}
else{
distance++;
}
//std::cout<<"passa da "<< id.x << "-" << id.y <<"\n";
}
}
}
return distance;
}
this is the AStar.cpp file
C++:
#include "Map.cpp"
template<typename T, typename priority_t>
struct PriorityQueue {
typedef std::pair<priority_t, T> PQElement;
std::priority_queue<PQElement, std::vector<PQElement>,
std::greater<PQElement>> elements;
inline bool empty() const {
return elements.empty();
}
inline void put(T item, priority_t priority) {
elements.emplace(priority, item);
}
T get() {
T best_item = elements.top().second;
elements.pop();
return best_item;
}
};
template<typename Location>
std::vector<Location> reconstruct_path(
Location start, Location goal,
std::unordered_map<Location, Location> came_from) {
std::vector<Location> path;
int control=0;
Location current = goal;
while (current != start) { // fallisce se non trova un percorso
//std::cout<< "cos'e' current " << current <<"\n";//percorso al contrario
path.push_back(current);
current = came_from[current];
control++;
if(control==10){ //se non trova il percorso
path[0].x=-1; //allora esce forzatamente
path[0].y=-1; //e ritorna un path simbolico che
return path; //viene letto dal programma per capire cosa è successo
}
}
//std::cout<< "cos'e' current " << current <<"\n";//percorso al contrario
path.push_back(start); // opzionale
std::reverse(path.begin(), path.end());
return path;
}
inline double heuristic(GridLocation a, GridLocation b) {
return std::abs(a.x - b.x) + std::abs(a.y - b.y);
}
template<typename Location, typename Graph>
void a_star_search
(Graph graph,
Location start,
Location goal,
std::unordered_map<Location, Location>& came_from,
std::unordered_map<Location, double>& cost_so_far)
{
PriorityQueue<Location, double> frontier;
frontier.put(start, 0);
came_from[start] = start;
cost_so_far[start] = 0;
while (!frontier.empty()) {
Location current = frontier.get();
if (current == goal) {
break;
}
for (Location next : graph.neighbors(current)) {
double new_cost = cost_so_far[current] + 1;
if (cost_so_far.find(next) == cost_so_far.end()
|| new_cost < cost_so_far[next]) {
cost_so_far[next] = new_cost;
double priority = new_cost + heuristic(next, goal);
frontier.put(next, priority);
came_from[next] = current;
}
}
}
}
I've already made several attempts, but they don't work.
Obviously I don't expect you to make me create the .h files, but if possible would you help me understand what I'm doing wrong? My files are now:
AStar.cpp
C++:
#include "AStar.h"
template<typename Location>
std::vector<Location> reconstruct_path(
Location start, Location goal,
std::unordered_map<Location, Location> came_from) {
std::vector<Location> path;
int control=0;
Location current = goal;
while (current != start) { // fallisce se non trova un percorso
//std::cout<< "cos'e' current " << current <<"\n";//percorso al contrario
path.push_back(current);
current = came_from[current];
control++;
if(control==10){ //se non trova il percorso
path[0].x=-1; //allora esce forzatamente
path[0].y=-1; //e ritorna un path simbolico che
return path; //viene letto dal programma per capire cosa è successo
}
}
//std::cout<< "cos'e' current " << current <<"\n";//percorso al contrario
path.push_back(start); // opzionale
std::reverse(path.begin(), path.end());
return path;
}
inline double heuristic(GridLocation a, GridLocation b) {
return std::abs(a.x - b.x) + std::abs(a.y - b.y);
}
template<typename Location, typename Graph>
void a_star_search
(Graph graph,
Location start,
Location goal,
std::unordered_map<Location, Location>& came_from,
std::unordered_map<Location, double>& cost_so_far)
{
PriorityQueue<Location, double> frontier;
frontier.put(start, 0);
came_from[start] = start;
cost_so_far[start] = 0;
while (!frontier.empty()) {
Location current = frontier.get();
if (current == goal) {
break;
}
for (Location next : graph.neighbors(current)) {
double new_cost = cost_so_far[current] + 1;
if (cost_so_far.find(next) == cost_so_far.end()
|| new_cost < cost_so_far[next]) {
cost_so_far[next] = new_cost;
double priority = new_cost + heuristic(next, goal);
frontier.put(next, priority);
came_from[next] = current;
}
}
}
}
Astar.h
C++:
#ifndef TURNSYSTEM_CPP_ASTAR_H
#define TURNSYSTEM_CPP_ASTAR_H
#include "Map.h"
template<typename T, typename priority_t>
struct PriorityQueue {
typedef std::pair<priority_t, T> PQElement;
std::priority_queue<PQElement, std::vector<PQElement>,
std::greater<PQElement>> elements;
inline bool empty() const {
return elements.empty();
}
inline void put(T item, priority_t priority) {
elements.emplace(priority, item);
}
T get() {
T best_item = elements.top().second;
elements.pop();
return best_item;
}
};
template<typename Location>
std::vector<Location> reconstruct_path(Location start, Location goal,std::unordered_map<Location, Location> came_from);
inline double heuristic(GridLocation a, GridLocation b);
template<typename Location, typename Graph>
void a_star_search(Graph graph, Location start, Location goal, std::unordered_map<Location, Location>& came_from, std::unordered_map<Location, double>& cost_so_far);
#endif //TURNSYSTEM_CPP_ASTAR_H
Map.cpp
C++:
#include "Map.h"
std::array<GridLocation, 4> SquareGrid::DIRS = {
//imposta le direzioni
GridLocation{1, 0}, //East
GridLocation{-1, 0}, //West
GridLocation{0, -1}, //North
GridLocation{0, 1} //South
};
// Funzioni che possono tornare utili a GridLocation
//Uguale
bool operator == (GridLocation a, GridLocation b) {
return a.x == b.x && a.y == b.y;
}
//Diverso
bool operator != (GridLocation a, GridLocation b) {
return !(a == b);
}
//Percorso
bool operator < (GridLocation a, GridLocation b) {
return std::tie(a.x, a.y) < std::tie(b.x, b.y);
}
std::basic_iostream<char>::basic_ostream& operator<<(std::basic_iostream<char>::basic_ostream& out, const GridLocation& loc) {
out << '(' << loc.x << ',' << loc.y << ')';
return out;
}
//Aggiunge i muri, può essere modificata per generare gli spazzi occupati dai pezzi
void add_rect(SquareGrid& grid, int x1, int y1, int x2, int y2) {
for (int x = x1; x < x2; ++x) {
for (int y = y1; y < y2; ++y) {
grid.walls.insert(GridLocation{x, y}); //genera effettivamente il "muro"
}
}
}
//crea la scacchiera e le mura al suo interno
//nel mio caso la scacchiera è 7x6, e non ha muri e aree difficili
//va modificato affinche aggiunga un muro per ogni pezzo che non sia quello mosso
SquareGrid MakeDiagram() {
SquareGrid grid(7, 6);
//add_rect(grid, 1, 1, 2, 2);
typedef GridLocation L;
return grid;
}
// Crea una classe generica, che viene usata per stampare il grafico della scacchiera
//non è necessaria al gioco, ma può essere utile durante lo sviluppo
template<class Graph>
void draw_grid(const Graph& graph,
std::unordered_map<GridLocation, double>* distances,
std::unordered_map<GridLocation, GridLocation>* point_to,
std::vector<GridLocation>* path,
GridLocation* start,
GridLocation* goal) {
const int field_width = 3; //crea una costante per la quale alcuni simboli vengono stampati 3 volte
std::cout << std::string(field_width * graph.width, '_') << '\n'; //stampa la parte alta del grafico ___
for (int y = 0; y != graph.height; ++y) {
for (int x = 0; x != graph.width; ++x) {
GridLocation id {x, y};
if (graph.walls.find(id) != graph.walls.end()) {
std::cout << std::string(field_width, '#'); //stampa i muri nel grafico
} else if (start && id == *start) {
std::cout << " A "; //stampa start nel grafico
} else if (goal && id == *goal) {
std::cout << " Z "; //stampa l'obbiettivo nel grafico
} else if (path != nullptr && find(path->begin(), path->end(), id) != path->end()) {
std::cout << " @ "; //stampa il percorso nel grafico
} else if (point_to != nullptr && point_to->count(id)) {
GridLocation next = (*point_to)[id];
if (next.x == x + 1) { std::cout << " > "; } //stampano i "flussi"
else if (next.x == x - 1) { std::cout << " < "; } //che partono da start
else if (next.y == y + 1) { std::cout << " v "; } //e usati, per trovare
else if (next.y == y - 1) { std::cout << " ^ "; } //il percorso migliore
else { std::cout << " * "; }
} else if (distances != nullptr && distances->count(id)) {
std::cout << ' ' << std::left << std::setw(field_width - 1) << (*distances)[id];
} else {
std::cout << " . ";
}
}
std::cout << '\n';
}
std::cout << std::string(field_width * graph.width, '~') << '\n'; //stampa la parte bassa del grafico ~~~
}
// Funzione per calcolare la distanza da un punto A ad un punto B
template<class Graph>
int DistanceCalculation(const Graph& graph,
std::vector<GridLocation>* path,
GridLocation* start,
GridLocation* goal) {
int distance=0;
for (int y = 0; y != graph.height; ++y) {
for (int x = 0; x != graph.width; ++x) {
GridLocation id{x, y};
if (find(path->begin(), path->end(), id) != path->end()) {
if(find(path->begin(), path->end(), id) == path->begin()){
}
else{
distance++;
}
//std::cout<<"passa da "<< id.x << "-" << id.y <<"\n";
}
}
}
return distance;
}
Map.h
C++:
struct GridLocation {
int x, y;
};
namespace std {
//implementare la funzione hash in modo da poter inserire GridLocation in un unordered_set
//I unordered_set sono contenitori che memorizzano elementi univoci in nessun ordine particolare
// e che consentono il recupero rapido di singoli elementi in base al loro valore.
template <> struct hash<GridLocation> {
std::size_t operator()(const GridLocation& id) const noexcept {
// NOTE: better to use something like boost hash_combine
return std::hash<int>()(id.x ^ (id.y << 16));
}
};
}
struct SquareGrid {
static std::array<GridLocation, 4> DIRS;
int width, height;
std::unordered_set<GridLocation> walls;
SquareGrid(int width_, int height_)
: width(width_), height(height_) {}
bool in_bounds(GridLocation id) const {
return 0 <= id.x && id.x < width
&& 0 <= id.y && id.y < height;
}
bool passable(GridLocation id) const {
return walls.find(id) == walls.end(); //Here it gives me error to "find ()"
}
std::vector<GridLocation> neighbors(GridLocation id) const {
std::vector<GridLocation> results;
for (GridLocation dir : DIRS) {
GridLocation next{id.x + dir.x, id.y + dir.y};
if (in_bounds(next) && passable(next)) {
results.push_back(next);
}
}
if ((id.x + id.y) % 2 == 0) {
// see "Ugly paths" section for an explanation:
std::reverse(results.begin(), results.end());
}
return results;
}
};
void add_rect(SquareGrid& grid, int x1, int y1, int x2, int y2);
SquareGrid MakeDiagram();
template<class Graph>
void draw_grid(const Graph& graph,std::unordered_map<GridLocation, double>* distances=nullptr,std::unordered_map<GridLocation, GridLocation>* point_to=nullptr,std::vector<GridLocation>* path=nullptr,GridLocation* start=nullptr,GridLocation* goal=nullptr);
template<class Graph>
int DistanceCalculation(const Graph& graph,
std::vector<GridLocation>* path=nullptr,
GridLocation* start=nullptr,
GridLocation* goal=nullptr);
#endif //TURNSYSTEM_CPP_MAP_H
Thanks in advance everyone, and sorry if I made some grammatical errors, as I mentioned this is not my mother tongue