[Add] A* algorithm to get paths between systems.
This commit is contained in:
parent
ccb954324c
commit
472579aa2a
222
src/space.c
222
src/space.c
@ -1,6 +1,9 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <float.h>
|
||||||
|
|
||||||
|
#include "xml.h"
|
||||||
|
#include "lephisto.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "physics.h"
|
#include "physics.h"
|
||||||
#include "rng.h"
|
#include "rng.h"
|
||||||
@ -47,9 +50,9 @@ static int spacename_nstack = 0;
|
|||||||
|
|
||||||
// Star system stack and co.
|
// Star system stack and co.
|
||||||
StarSystem* systems_stack = NULL; // Star system stack.
|
StarSystem* systems_stack = NULL; // Star system stack.
|
||||||
int systems_nstack = 0; // Number of star systems.
|
int systems_nstack = 0; // Number of star systems.
|
||||||
static int nplanets = 0; // Total number of loaded planets - A little silly.
|
static int nplanets = 0; // Total number of loaded planets - A little silly.
|
||||||
StarSystem* cur_system = NULL; // Current star system.
|
StarSystem* cur_system = NULL; // Current star system.
|
||||||
|
|
||||||
// Fleet spawn rate.
|
// Fleet spawn rate.
|
||||||
unsigned int spawn_timer = 0; // Controls spawn rate.
|
unsigned int spawn_timer = 0; // Controls spawn rate.
|
||||||
@ -62,10 +65,11 @@ typedef struct Star_ {
|
|||||||
} Star;
|
} Star;
|
||||||
|
|
||||||
static Star* stars = NULL; // Star array.
|
static Star* stars = NULL; // Star array.
|
||||||
static int nstars = 0; // Total stars.
|
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_get(const char* name);
|
static Planet* planet_get(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);
|
||||||
@ -139,6 +143,200 @@ void planets_minimap(const double res,
|
|||||||
}
|
}
|
||||||
#undef PIXEL
|
#undef PIXEL
|
||||||
|
|
||||||
|
// A* Algorithm fo shortest path finding.
|
||||||
|
|
||||||
|
// The node struct.
|
||||||
|
typedef struct SysNode_ {
|
||||||
|
struct SysNode_* next;
|
||||||
|
|
||||||
|
struct SysNode_* parent;
|
||||||
|
StarSystem* sys;
|
||||||
|
double r; // Ranking.
|
||||||
|
int g; // Step.
|
||||||
|
} SysNode;
|
||||||
|
|
||||||
|
static SysNode* 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 int 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.;
|
||||||
|
|
||||||
|
A_add(gc, n);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double A_h(StarSystem* n, StarSystem* g) {
|
||||||
|
// Euclidean distance.
|
||||||
|
return sqrt(pow2(n->pos.x - g->pos.x) + pow2(n->pos.y - g->pos.y))/100.;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
first->next = NULL;
|
||||||
|
n = first->next;
|
||||||
|
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 int A_in(SysNode* first, StarSystem* cur) {
|
||||||
|
SysNode* n;
|
||||||
|
|
||||||
|
if(first == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
n = first;
|
||||||
|
do {
|
||||||
|
if(n->sys == cur)
|
||||||
|
return 1;
|
||||||
|
} while((n=n->next) != NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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->next) != NULL);
|
||||||
|
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
StarSystem** system_getJumpPath(int* njumps, char* sysstart, char* sysend) {
|
||||||
|
int i, cost;
|
||||||
|
|
||||||
|
StarSystem* ssys, *esys, **res;
|
||||||
|
|
||||||
|
SysNode* cur, *neighbour;
|
||||||
|
SysNode* open, *closed;
|
||||||
|
|
||||||
|
gc = NULL;
|
||||||
|
|
||||||
|
// Initial and target systems.
|
||||||
|
ssys = system_get(sysstart); // Start.
|
||||||
|
ssys = system_get(sysend); // End.
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
for(i = 0; i < cur->sys->njumps; i++) {
|
||||||
|
neighbour = A_newNode(&systems_stack[cur->sys->jumps[i]], cur);
|
||||||
|
cost = A_g(cur) + 1;
|
||||||
|
|
||||||
|
if(A_in(open, neighbour->sys) && (cost < A_g(neighbour)))
|
||||||
|
open = A_rm(open, neighbour->sys); // New path is better.
|
||||||
|
|
||||||
|
if(A_in(closed, neighbour->sys) && (cost < A_g(neighbour)))
|
||||||
|
closed = A_rm(closed, neighbour->sys); // Shouldn't happen.
|
||||||
|
|
||||||
|
if(!A_in(open, neighbour->sys) && !A_in(closed, neighbour->sys)) {
|
||||||
|
neighbour->g = cost;
|
||||||
|
open = A_add(open, neighbour);
|
||||||
|
neighbour->r = (double)A_g(neighbour) + A_h(neighbour->sys, esys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 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(open);
|
||||||
|
//A_freeList(closed);
|
||||||
|
A_freeList(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.
|
||||||
@ -256,6 +454,18 @@ char* space_getRndPlanet(void) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the system from it's name.
|
||||||
|
static StarSystem* system_get(const char* sysname) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < systems_nstack; i++)
|
||||||
|
if(strcmp(sysname, systems_stack[i].name)==0)
|
||||||
|
return &systems_stack[i];
|
||||||
|
|
||||||
|
DEBUG("System '%s' not found in stack", sysname);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the name of a system from a planetname.
|
// Get the name of a system from a planetname.
|
||||||
char* planet_getSystem(char* planetname) {
|
char* planet_getSystem(char* planetname) {
|
||||||
int i;
|
int i;
|
||||||
|
21
src/space.h
21
src/space.h
@ -69,26 +69,26 @@ typedef struct Planet_ {
|
|||||||
|
|
||||||
// Star systems.
|
// Star systems.
|
||||||
typedef struct SystemFleet_ {
|
typedef struct SystemFleet_ {
|
||||||
Fleet* fleet; // Fleet to appear.
|
Fleet* fleet; // Fleet to appear.
|
||||||
int chance; // Chance of fleet appearing in the system.
|
int chance; // Chance of fleet appearing in the system.
|
||||||
} SystemFleet;
|
} SystemFleet;
|
||||||
|
|
||||||
typedef struct StarSystem_ {
|
typedef struct StarSystem_ {
|
||||||
char* name; // Star system identifier.
|
char* name; // Star system identifier.
|
||||||
Vec2 pos; // Position.
|
Vec2 pos; // Position.
|
||||||
int stars, asteroids; // Un numero!
|
int stars, asteroids; // Un numero!
|
||||||
double interference; // Un uh.. Percentage.
|
double interference; // Un uh.. Percentage.
|
||||||
|
|
||||||
int faction; // Overall faction.
|
int faction; // Overall faction.
|
||||||
|
|
||||||
Planet* planets; // Planets.
|
Planet* planets; // Planets.
|
||||||
int nplanets; // Total number of planets.
|
int nplanets; // Total number of planets.
|
||||||
|
|
||||||
SystemFleet* fleets; // Fleets that can appear in the current system.
|
SystemFleet* fleets; // Fleets that can appear in the current system.
|
||||||
int nfleets; // Total number of fleets.
|
int nfleets; // Total number of fleets.
|
||||||
|
|
||||||
int* jumps; // Adjacent star system index number.
|
int* jumps; // Adjacent star system index number.
|
||||||
int njumps; // Number of adjacent jumps.
|
int njumps; // Number of adjacent jumps.
|
||||||
} StarSystem;
|
} StarSystem;
|
||||||
|
|
||||||
extern StarSystem* cur_system; // Current star system.
|
extern StarSystem* cur_system; // Current star system.
|
||||||
@ -109,6 +109,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);
|
||||||
int space_canHyperspace(Pilot* p);
|
int space_canHyperspace(Pilot* p);
|
||||||
int space_hyperspace(Pilot* p);
|
int space_hyperspace(Pilot* p);
|
||||||
char** space_getFactionPlanet(int* nplanets, int* factions, int nfactions);
|
char** space_getFactionPlanet(int* nplanets, int* factions, int nfactions);
|
||||||
|
Loading…
Reference in New Issue
Block a user