Skip to content

Instantly share code, notes, and snippets.

@mpatraw
Last active August 29, 2015 14:10
Show Gist options
  • Save mpatraw/9750b947a8e350611f7a to your computer and use it in GitHub Desktop.
Save mpatraw/9750b947a8e350611f7a to your computer and use it in GitHub Desktop.
Daily Programmer #191 Intermediate
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 10
#define GRAVITY_WELL_CHANCE 0.1
#define ASTEROID_CHANCE 0.3
#define START_X 0
#define START_Y 0
#define END_X 9
#define END_Y 9
#define IN_BOUNDS(x, y) ((x) >= 0 && (x) < N && (y) >= 0 && (y) < N)
#define SQ(x) ((x) * (x))
enum obstacle {
NO_OBSTACLE,
GRAVITY_WELL,
ASTEROID,
};
enum path {
NO_PATH,
PATH,
START,
END,
};
/* A node during path finding. */
struct node {
int x;
int y;
struct node *prev;
struct node *parent;
};
static enum obstacle obstacle_map[N * N];
static enum path path_map[N * N];
static bool visited[N * N];
/* Places an obstacle at a random free spot. */
static void place_at_random_spot(enum obstacle obst)
{
int x;
int y;
int at_start;
int at_end;
do {
x = rand() % N;
y = rand() % N;
at_start = x == START_X && y == START_Y;
at_end = y == END_X && y == END_Y;
} while (at_start || at_end || obstacle_map[y * N + x]);
obstacle_map[y * N + x] = obst;
}
/* Calculates distance. No need to sqrt. */
static int distance_to_end(int x, int y)
{
return SQ(x - END_X) + SQ(y - END_Y);
}
/* Initialized the obstacle_map with random data. */
static void initialize(void)
{
int well_count = ((int)N * N * GRAVITY_WELL_CHANCE);
int asteroid_count = ((int)N * N * ASTEROID_CHANCE);
unsigned int seed = time(NULL);
srand(seed);
while (well_count-- > 0) {
place_at_random_spot(GRAVITY_WELL);
}
while (asteroid_count-- > 0) {
place_at_random_spot(ASTEROID);
}
path_map[START_Y * N + START_X] = START;
path_map[END_Y * N + END_X] = END;
}
/* Returns true if the spot is safe. A square is safe if it is inside
* the map, isn't on an asteroid, and isn't near a gravity well.
*/
static bool is_obstructed(int x, int y)
{
int dx;
int dy;
int tx;
int ty;
bool obst;
if (!IN_BOUNDS(x, y)) {
return true;
}
if (obstacle_map[y * N + x] == ASTEROID) {
return true;
}
for (dy = -1; dy <= 1; ++dy) {
for (dx = -1; dx <= 1; ++dx) {
tx = x + dx;
ty = y + dy;
if (IN_BOUNDS(tx, ty)) {
obst = obstacle_map[ty * N + tx] ==
GRAVITY_WELL;
if (obst) {
return true;
}
}
}
}
return false;
}
/* Pushes a node onto a stack with a given parent. */
static void
push_node(struct node **top, int x, int y, struct node *parent)
{
struct node *p = malloc(sizeof(*p));
assert(p && "out of memory");
p->x = x;
p->y = y;
p->prev = *top;
p->parent = parent;
*top = p;
}
/* Pops a node from the stack. */
static struct node *pop_node(struct node **top)
{
struct node *n = *top;
if (*top) {
*top = (*top)->prev;
}
return n;
}
/* Clears the stack, freeing all the memory. */
static void clear_stack(struct node *top)
{
struct node *tmp;
while (top) {
tmp = top;
top = top->prev;
free(tmp);
}
}
/* Adds all neighbors that can be checked to the stack. */
static void enumerate_neighbors(struct node **top, struct node *n)
{
int dx;
int dy;
int tx;
int ty;
bool obst;
for (dy = -1; dy <= 1; ++dy) {
for (dx = -1; dx <= 1; ++dx) {
tx = n->x + dx;
ty = n->y + dy;
obst = is_obstructed(tx, ty);
if (!obst && !visited[ty * N + tx]) {
visited[ty * N + tx] = true;
push_node(top, tx, ty, n);
}
}
}
}
/* Attempts to find a path, returns false if not found. */
static bool find_path(void)
{
struct node *top = NULL;
struct node *tofree = NULL;
struct node *tmp;
struct node *n;
struct node *closest = NULL;
int closest_dist = INT_MAX;
int dist;
bool found = false;
push_node(&top, START_X, START_Y, NULL);
visited[START_Y * N + START_X] = true;
while ((tmp = pop_node(&top))) {
n = tmp;
/* Must save all nodes for finding our way back. We'll
* free them later by adding them to a stack.
*/
n->prev = tofree;
tofree = n;
dist = distance_to_end(n->x, n->y);
if (dist < closest_dist) {
closest = n;
closest_dist = dist;
}
if (n->x == END_X && n->y == END_Y) {
found = true;
break;
}
enumerate_neighbors(&top, n);
}
/* Fill in path. */
n = closest;
while (n) {
/* Skip start/end. */
if (!path_map[n->y * N + n->x]) {
path_map[n->y * N + n->x] = PATH;
}
n = n->parent;
}
clear_stack(top);
clear_stack(tofree);
return found;
}
/* Prints both maps, obstacle and path, to stdout. */
static void print_maps(void)
{
int x;
int y;
enum obstacle obst;
enum path path;
for (y = 0; y < N; ++y) {
for (x = 0; x < N; ++x) {
obst = obstacle_map[y * N + x];
path = path_map[y * N + x];
if (obst == GRAVITY_WELL) {
printf("G");
} else if (obst == ASTEROID) {
printf("A");
} else if (path == PATH) {
printf("O");
} else if (path == START) {
printf("S");
} else if (path == END) {
printf("E");
} else {
printf(".");
}
}
printf("\n");
}
}
int main(void)
{
initialize();
if (!find_path()) {
printf("no complete path\n");
}
print_maps();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment