diff --git a/src/llua.c b/src/llua.c index 2a0812e..441a345 100644 --- a/src/llua.c +++ b/src/llua.c @@ -7,6 +7,7 @@ #include "toolkit.h" #include "space.h" #include "land.h" +#include "map.h" #include "lluadef.h" #include "llua.h" @@ -190,7 +191,7 @@ static int space_jumpDist(lua_State* L) { else goal = cur_system->name; - s = system_getJumpPath(&jumps, start, goal); + s = map_getJumpPath(&jumps, start, goal); free(s); lua_pushnumber(L, jumps); diff --git a/src/map.c b/src/map.c index 6108d01..074b5ee 100644 --- a/src/map.c +++ b/src/map.c @@ -1,3 +1,7 @@ +#include <malloc.h> +#include <math.h> +#include <float.h> + #include "log.h" #include "lephisto.h" #include "toolkit.h" @@ -277,7 +281,7 @@ static void map_mouse(SDL_Event* event, double mx, double my) { map_selected = i; if(map_path) free(map_path); - map_path = system_getJumpPath(&map_npath, + map_path = map_getJumpPath(&map_npath, cur_system->name, sys->name); 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; +} + + diff --git a/src/map.h b/src/map.h index 8f25f10..3520f6b 100644 --- a/src/map.h +++ b/src/map.h @@ -1,4 +1,5 @@ #pragma once +#include "space.h" /* Open the map window. */ void map_open(void); @@ -7,3 +8,6 @@ void map_open(void); void map_clear(void); void map_jump(void); +/* Manipulate universe stuff. */ +StarSystem** map_getJumpPath(int* njumps, char* sysstart, char* sysend); + diff --git a/src/space.c b/src/space.c index 3cc4b0b..2db9713 100644 --- a/src/space.c +++ b/src/space.c @@ -1,6 +1,5 @@ #include <malloc.h> #include <math.h> -#include <float.h> #include "xml.h" #include "lephisto.h" @@ -70,7 +69,6 @@ static int nstars = 0; /* Total stars. */ static int mstars = 0; /* Memory stars are taking. */ /* Intern. */ -static StarSystem* system_get(const char* sysname); static Planet* planet_pull(const char* name); static void space_addFleet(Fleet* fleet); static StarSystem* system_parse(const xmlNodePtr parent); @@ -148,225 +146,7 @@ void planets_minimap(const double res, const double w, } #undef PIXEL -/* 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** 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; -} - +/* Basically return a PlanetClass integer from a char. */ static PlanetClass planetclass_get(const char a) { switch(a) { /* Planets use letters. */ @@ -504,7 +284,7 @@ int space_sysReachable(StarSystem* sys) { } /* Get the system from it's name. */ -static StarSystem* system_get(const char* sysname) { +StarSystem* system_get(const char* sysname) { int i; for(i = 0; i < systems_nstack; i++) diff --git a/src/space.h b/src/space.h index 195ad1a..08de89b 100644 --- a/src/space.h +++ b/src/space.h @@ -123,7 +123,7 @@ void planets_render(void); void space_update(const double dt); /* Misc. */ -StarSystem** system_getJumpPath(int* njumps, char* sysstart, char* sysend); +StarSystem* system_get(const char* sysname); int space_canHyperspace(Pilot* p); int space_hyperspace(Pilot* p); int space_sysReachable(StarSystem* sys);