Ya que no he visto mucha información del tema en el foro, les dejo una implementación que he hecho en C++. Mi intención es que se compartamos formas de hacerlo más eficiente, encontrar errores, publicar implementaciones en otros lenguajes...
La implementación que he hecho no tiene interfaz gráfica. La entrada consiste en 4 naturales (f, c, fi, fj) y un mapa. Donde f y c son las filas y las columnas. fi y fj son las coordenadas del final con 0 <= fi < f y 0 <= fj < c. El mapa consiste en '.' terreno libre, 'X' pared y 'I' inicio.
Ejemplo de entrada (en GNU/Linux se puede copiar a un archivo y hacer ./ejecutable <entrada.txt):
- Código: Seleccionar todo
8 16 0 15
X.X......X......
....X..X....XX..
X..X.XX.XXXX..XX
X.X...X......X.I
..X.X.X.XX.X....
....X...X....X..
.XXXXXXX...XX...
.........X.....X
La salida consiste en el mapa inicial con 'O's marcando el camino. También saca por el canal de error los nodos tratados.
Salida:
- Código: Seleccionar todo
X.XOOOOOOX.OOOOO
..OOX..XOOO.XX..
XO.X.XX.XXXX..XX
XOX...X......X.I
.OX.X.X.XX.XOOO.
O...X...X.OOOX..
OXXXXXXXOO.XX...
OOOOOOOOOX.....X
Implementación en C++:
- Código: Seleccionar todo
#include <iostream>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
struct Node {
char c;
int g, h, pi, pj;
bool usado;
};
struct NInfo {
int f, i, j;
};
typedef vector<Node> Vn;
typedef vector<Vn> Mn;
#define INF 100000;
bool operator<(const NInfo& ni1, const NInfo& ni2) {
if (ni1.f != ni2.f) return ni1.f > ni2.f;
if (ni1.i != ni2.i) return ni1.i > ni2.i;
return ni1.j > ni2.j;
}
int H(int i, int j, int fi, int fj) {
return abs(i-fi)+abs(j-fj);
}
void escriu(const Mn& m) {
for (int i = 0; i < m.size(); ++i) {
for (int j = 0; j < m[i].size(); ++j) {
cout << m[i][j].c;
}
cout << endl;
}
}
void anyade_nodo(Mn& mn, priority_queue<NInfo>& c, int i, int j, int di, int dj,int fi, int fj, bool diagonal = false) {
int m = mn.size();
int n = mn[0].size();
int incr = 10;
if (diagonal) incr = 14;
if (i+di >= 0 and j+dj >= 0 and i+di < m and j+dj < n and
not mn[i+di][j+dj].usado and mn[i+di][j+dj].g > mn[i][j].g+incr and
mn[i+di][j+dj].c != 'X') {
if (diagonal and mn[i+di][j].c == 'X' or mn[i][j+dj].c == 'X') return;
mn[i+di][j+dj].g = mn[i][j].g+incr;
mn[i+di][j+dj].h = H(i+di, j+dj, fi, fj)*10;
mn[i+di][j+dj].pi = i;
mn[i+di][j+dj].pj = j;
NInfo ni2;
ni2.i = i+di;
ni2.j = j+dj;
ni2.f = mn[i+di][j+dj].g+mn[i+di][j+dj].h;
c.push(ni2);
}
}
int main() {
int m, n;
cin >> m >> n;
int fi, fj;
cin >> fi >> fj;
Mn mn(m, Vn(n));
priority_queue<NInfo> cabierta;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
mn[i][j].g = INF;
mn[i][j].usado = false;
cin >> mn[i][j].c;
if (mn[i][j].c == 'I') {
mn[i][j].g = 0;
NInfo ni;
ni.i = i;
ni.j = j;
ni.f = H(i, j, fi, fj);
cabierta.push(ni);
}
}
}
bool final = false;
while (!final and !cabierta.empty()) {
NInfo ni = cabierta.top();
cabierta.pop();
int i = ni.i;
int j = ni.j;
if (i == fi and j == fj) final = true;
if (not mn[i][j].usado and not final) {
cerr << "i:" << i << "j:" << j << endl;
mn[i][j].usado = true;
anyade_nodo(mn, cabierta, i, j, -1, 0, fi, fj);
anyade_nodo(mn, cabierta, i, j, +1, 0, fi, fj);
anyade_nodo(mn, cabierta, i, j, 0, -1, fi, fj);
anyade_nodo(mn, cabierta, i, j, 0, +1, fi, fj);
anyade_nodo(mn, cabierta, i, j, -1, -1, fi, fj, true);
anyade_nodo(mn, cabierta, i, j, +1, +1, fi, fj, true);
anyade_nodo(mn, cabierta, i, j, -1, +1, fi, fj, true);
anyade_nodo(mn, cabierta, i, j, +1, -1, fi, fj, true);
}
}
char c = mn[fi][fj].c;
while (c != 'I') {
mn[fi][fj].c = 'O';
int iaux = mn[fi][fj].pi;
int jaux = mn[fi][fj].pj;
fi = iaux;
fj = jaux;
c = mn[fi][fj].c;
}
escriu(mn);
}
Como documentación he utilizado:
-http://en.wikipedia.org/wiki/A*
-http://www.policyalmanac.org/games/articulo1.htm (aunque no conseguí descargarme la implementación)
Saludos.