[Change] Moved A* jump pathfinding from space.c to map.c.

This commit is contained in:
Allanis 2013-06-25 21:07:54 +01:00
parent 700e47cd57
commit 5760978e56
5 changed files with 234 additions and 225 deletions

View File

@ -7,6 +7,7 @@
#include "toolkit.h" #include "toolkit.h"
#include "space.h" #include "space.h"
#include "land.h" #include "land.h"
#include "map.h"
#include "lluadef.h" #include "lluadef.h"
#include "llua.h" #include "llua.h"
@ -190,7 +191,7 @@ static int space_jumpDist(lua_State* L) {
else else
goal = cur_system->name; goal = cur_system->name;
s = system_getJumpPath(&jumps, start, goal); s = map_getJumpPath(&jumps, start, goal);
free(s); free(s);
lua_pushnumber(L, jumps); lua_pushnumber(L, jumps);

226
src/map.c
View File

@ -1,3 +1,7 @@
#include <malloc.h>
#include <math.h>
#include <float.h>
#include "log.h" #include "log.h"
#include "lephisto.h" #include "lephisto.h"
#include "toolkit.h" #include "toolkit.h"
@ -277,7 +281,7 @@ static void map_mouse(SDL_Event* event, double mx, double my) {
map_selected = i; map_selected = i;
if(map_path) if(map_path)
free(map_path); free(map_path);
map_path = system_getJumpPath(&map_npath, map_path = map_getJumpPath(&map_npath,
cur_system->name, sys->name); cur_system->name, sys->name);
if(map_npath == 0) if(map_npath == 0)
@ -394,3 +398,223 @@ void map_jump(void) {
} }
} }
/* A* Algorithm fo shortest path finding. */
/* The node struct. */
typedef struct SysNode_ {
struct SysNode_* next, *gnext;
struct SysNode_* parent;
StarSystem* sys;
double r; /* Ranking. */
int g; /* Step. */
} SysNode;
static SysNode* A_gc;
/* Prototypes. */
static SysNode* A_newNode(StarSystem* sys, SysNode* parent);
static double A_h(StarSystem* n, StarSystem* g);
static double A_g(SysNode* n);
static SysNode* A_add(SysNode* first, SysNode* cur);
static SysNode* A_rm(SysNode* first, StarSystem* cur);
static SysNode* A_in(SysNode* first, StarSystem* cur);
static SysNode* A_lowest(SysNode* first);
static void A_freeList(SysNode* first);
/* Creates a new node link to star system. */
static SysNode* A_newNode(StarSystem* sys, SysNode* parent) {
SysNode* n;
n = malloc(sizeof(SysNode));
n->next = NULL;
n->parent = parent;
n->sys = sys;
n->r = DBL_MAX;
n->g = 0.;
n->gnext = A_gc;
A_gc = n;
return n;
}
static double A_h(StarSystem* n, StarSystem* g) {
(void)n;
(void)g;
/* Euclidean distance. */
/*return sqrt(pow2(n->pos.x - g->pos.x) + pow2(n->pos.y - g->pos.y))/100.; */
return 0.;
}
/* Get the g from a node. */
static double A_g(SysNode* n) {
return n->g;
}
/* Add a node to the linkes list. */
static SysNode* A_add(SysNode* first, SysNode* cur) {
SysNode* n;
if(first == NULL)
return cur;
n = first;
while(n->next != NULL)
n = n->next;
n->next = cur;
return first;
}
/* Remove a node from a linked list. */
static SysNode* A_rm(SysNode* first, StarSystem* cur) {
SysNode* n, *p;
if(first->sys == cur) {
n = first->next;
first->next = NULL;
return n;
}
p = first;
n = p->next;
do {
if(n->sys == cur) {
n->next = NULL;
p->next = n->next;
break;
}
} while((n=n->next) != NULL);
return first;
}
/* Check if node is in linked list. */
static SysNode* A_in(SysNode* first, StarSystem* cur) {
SysNode* n;
if(first == NULL)
return NULL;
n = first;
do {
if(n->sys == cur)
return n;
} while((n=n->next) != NULL);
return NULL;
}
/* Return the lowest ranking node from a linked list of nodes. */
static SysNode* A_lowest(SysNode* first) {
SysNode* lowest, *n;
if(first == NULL)
return NULL;
n = first;
lowest = n;
do {
if(n->r < lowest->r)
lowest = n;
} while((n=n->next) != NULL);
return lowest;
}
/* Free a linked list. */
static void A_freeList(SysNode* first) {
SysNode* p, *n;
if(first == NULL)
return;
p = NULL;
n = first;
do {
if(p != NULL)
free(p);
p = n;
} while((n=n->gnext) != NULL);
free(p);
}
StarSystem** map_getJumpPath(int* njumps, char* sysstart, char* sysend) {
int i, cost;
StarSystem* sys, *ssys, *esys, **res;
SysNode* cur, *neighbour;
SysNode* open, *closed;
SysNode* ocost, *ccost;
A_gc = NULL;
/* Initial and target systems. */
ssys = system_get(sysstart); /* Start. */
esys = system_get(sysend); /* End. */
/* System target must be known. */
if(!sys_isKnown(esys)) {
if(space_sysReachable(esys)) { /* Can we still reach it? */
res = malloc(sizeof(StarSystem*));
(*njumps) = 1;
res[0] = esys;
return res;
}
/* Can't reach - Don't make path. */
(*njumps) = 0;
return NULL;
}
/* Start the linked lists. */
open = closed = NULL;
cur = A_newNode(ssys, NULL);
open = A_add(open, cur); /* Initial open node is the start system. */
while((cur = A_lowest(open))->sys != esys) {
/* Get best from open and toss to closed. */
open = A_rm(open, cur->sys);
closed = A_add(closed, cur);
cost = A_g(cur) + 1;
for(i = 0; i < cur->sys->njumps; i++) {
sys = &systems_stack[cur->sys->jumps[i]];
if(!sys_isKnown(sys)) continue;
neighbour = A_newNode(sys, NULL);
ocost = A_in(open, sys);
if((ocost != NULL) && (cost < ocost->g)) {
open = A_rm(open, sys); /* New path is better. */
}
ccost = A_in(closed, sys);
if(ccost != NULL) {
closed = A_rm(closed, sys); /* Shouldn't happen. */
}
if((ocost == NULL) && (ccost == NULL)) {
neighbour->g = cost;
neighbour->r = A_g(neighbour) + A_h(cur->sys, sys);
neighbour->parent = cur;
open = A_add(open, neighbour);
}
}
}
/* Build the path backwards. */
(*njumps) = A_g(cur);
res = malloc(sizeof(StarSystem*) * (*njumps));
for(i = 0; i < (*njumps); i++) {
res[(*njumps)-i-1] = cur->sys;
cur = cur->parent;
}
/* Free the linked list. */
A_freeList(A_gc);
return res;
}

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "space.h"
/* Open the map window. */ /* Open the map window. */
void map_open(void); void map_open(void);
@ -7,3 +8,6 @@ void map_open(void);
void map_clear(void); void map_clear(void);
void map_jump(void); void map_jump(void);
/* Manipulate universe stuff. */
StarSystem** map_getJumpPath(int* njumps, char* sysstart, char* sysend);

View File

@ -1,6 +1,5 @@
#include <malloc.h> #include <malloc.h>
#include <math.h> #include <math.h>
#include <float.h>
#include "xml.h" #include "xml.h"
#include "lephisto.h" #include "lephisto.h"
@ -70,7 +69,6 @@ static int nstars = 0; /* Total stars. */
static int mstars = 0; /* Memory stars are taking. */ static int mstars = 0; /* Memory stars are taking. */
/* Intern. */ /* Intern. */
static StarSystem* system_get(const char* sysname);
static Planet* planet_pull(const char* name); static Planet* planet_pull(const char* name);
static void space_addFleet(Fleet* fleet); static void space_addFleet(Fleet* fleet);
static StarSystem* system_parse(const xmlNodePtr parent); static StarSystem* system_parse(const xmlNodePtr parent);
@ -148,225 +146,7 @@ void planets_minimap(const double res, const double w,
} }
#undef PIXEL #undef PIXEL
/* A* Algorithm fo shortest path finding. */ /* Basically return a PlanetClass integer from a char. */
/* The node struct. */
typedef struct SysNode_ {
struct SysNode_* next, *gnext;
struct SysNode_* parent;
StarSystem* sys;
double r; /* Ranking. */
int g; /* Step. */
} SysNode;
static SysNode* A_gc;
/* Prototypes. */
static SysNode* A_newNode(StarSystem* sys, SysNode* parent);
static double A_h(StarSystem* n, StarSystem* g);
static double A_g(SysNode* n);
static SysNode* A_add(SysNode* first, SysNode* cur);
static SysNode* A_rm(SysNode* first, StarSystem* cur);
static SysNode* A_in(SysNode* first, StarSystem* cur);
static SysNode* A_lowest(SysNode* first);
static void A_freeList(SysNode* first);
/* Creates a new node link to star system. */
static SysNode* A_newNode(StarSystem* sys, SysNode* parent) {
SysNode* n;
n = malloc(sizeof(SysNode));
n->next = NULL;
n->parent = parent;
n->sys = sys;
n->r = DBL_MAX;
n->g = 0.;
n->gnext = A_gc;
A_gc = n;
return n;
}
static double A_h(StarSystem* n, StarSystem* g) {
(void)n;
(void)g;
/* Euclidean distance. */
/*return sqrt(pow2(n->pos.x - g->pos.x) + pow2(n->pos.y - g->pos.y))/100.; */
return 0.;
}
/* Get the g from a node. */
static double A_g(SysNode* n) {
return n->g;
}
/* Add a node to the linkes list. */
static SysNode* A_add(SysNode* first, SysNode* cur) {
SysNode* n;
if(first == NULL)
return cur;
n = first;
while(n->next != NULL)
n = n->next;
n->next = cur;
return first;
}
/* Remove a node from a linked list. */
static SysNode* A_rm(SysNode* first, StarSystem* cur) {
SysNode* n, *p;
if(first->sys == cur) {
n = first->next;
first->next = NULL;
return n;
}
p = first;
n = p->next;
do {
if(n->sys == cur) {
n->next = NULL;
p->next = n->next;
break;
}
} while((n=n->next) != NULL);
return first;
}
/* Check if node is in linked list. */
static SysNode* A_in(SysNode* first, StarSystem* cur) {
SysNode* n;
if(first == NULL)
return NULL;
n = first;
do {
if(n->sys == cur)
return n;
} while((n=n->next) != NULL);
return NULL;
}
/* Return the lowest ranking node from a linked list of nodes. */
static SysNode* A_lowest(SysNode* first) {
SysNode* lowest, *n;
if(first == NULL)
return NULL;
n = first;
lowest = n;
do {
if(n->r < lowest->r)
lowest = n;
} while((n=n->next) != NULL);
return lowest;
}
/* Free a linked list. */
static void A_freeList(SysNode* first) {
SysNode* p, *n;
if(first == NULL)
return;
p = NULL;
n = first;
do {
if(p != NULL)
free(p);
p = n;
} while((n=n->gnext) != NULL);
free(p);
}
StarSystem** system_getJumpPath(int* njumps, char* sysstart, char* sysend) {
int i, cost;
StarSystem* sys, *ssys, *esys, **res;
SysNode* cur, *neighbour;
SysNode* open, *closed;
SysNode* ocost, *ccost;
A_gc = NULL;
/* Initial and target systems. */
ssys = system_get(sysstart); /* Start. */
esys = system_get(sysend); /* End. */
/* System target must be known. */
if(!sys_isKnown(esys)) {
if(space_sysReachable(esys)) { /* Can we still reach it? */
res = malloc(sizeof(StarSystem*));
(*njumps) = 1;
res[0] = esys;
return res;
}
/* Can't reach - Don't make path. */
(*njumps) = 0;
return NULL;
}
/* Start the linked lists. */
open = closed = NULL;
cur = A_newNode(ssys, NULL);
open = A_add(open, cur); /* Initial open node is the start system. */
while((cur = A_lowest(open))->sys != esys) {
/* Get best from open and toss to closed. */
open = A_rm(open, cur->sys);
closed = A_add(closed, cur);
cost = A_g(cur) + 1;
for(i = 0; i < cur->sys->njumps; i++) {
sys = &systems_stack[cur->sys->jumps[i]];
if(!sys_isKnown(sys)) continue;
neighbour = A_newNode(sys, NULL);
ocost = A_in(open, sys);
if((ocost != NULL) && (cost < ocost->g)) {
open = A_rm(open, sys); /* New path is better. */
}
ccost = A_in(closed, sys);
if(ccost != NULL) {
closed = A_rm(closed, sys); /* Shouldn't happen. */
}
if((ocost == NULL) && (ccost == NULL)) {
neighbour->g = cost;
neighbour->r = A_g(neighbour) + A_h(cur->sys, sys);
neighbour->parent = cur;
open = A_add(open, neighbour);
}
}
}
/* Build the path backwards. */
(*njumps) = A_g(cur);
res = malloc(sizeof(StarSystem*) * (*njumps));
for(i = 0; i < (*njumps); i++) {
res[(*njumps)-i-1] = cur->sys;
cur = cur->parent;
}
/* Free the linked list. */
A_freeList(A_gc);
return res;
}
static PlanetClass planetclass_get(const char a) { static PlanetClass planetclass_get(const char a) {
switch(a) { switch(a) {
/* Planets use letters. */ /* Planets use letters. */
@ -504,7 +284,7 @@ int space_sysReachable(StarSystem* sys) {
} }
/* Get the system from it's name. */ /* Get the system from it's name. */
static StarSystem* system_get(const char* sysname) { StarSystem* system_get(const char* sysname) {
int i; int i;
for(i = 0; i < systems_nstack; i++) for(i = 0; i < systems_nstack; i++)

View File

@ -123,7 +123,7 @@ void planets_render(void);
void space_update(const double dt); void space_update(const double dt);
/* Misc. */ /* Misc. */
StarSystem** system_getJumpPath(int* njumps, char* sysstart, char* sysend); StarSystem* system_get(const char* sysname);
int space_canHyperspace(Pilot* p); int space_canHyperspace(Pilot* p);
int space_hyperspace(Pilot* p); int space_hyperspace(Pilot* p);
int space_sysReachable(StarSystem* sys); int space_sysReachable(StarSystem* sys);