I just implement Dijkstra's algorithm in C99. Can you review my code please? I'm looking for any mistake, performance improvement or coding style errors.
main.c
#include "src/map.h"
#include "src/pathfinder.h"
int main() {
map *map = init(createTuple_2(11, 11));
addBegin(map, createTuple_2(1, 1));
addEnd(map, createTuple_2(10, 10));
addWall(map, createTuple_2(5, 5));
addWall(map, createTuple_2(3, 5));
addWall(map, createTuple_2(4, 5));
addWall(map, createTuple_2(2, 5));
addWall(map, createTuple_2(6, 5));
addWall(map, createTuple_2(7, 5));
addWall(map, createTuple_2(8, 5));
addWall(map, createTuple_2(9, 5));
addWall(map, createTuple_2(2, 5));
addWall(map, createTuple_2(1, 5));
addWall(map, createTuple_2(0, 5));
dijkstra(map);
print(map, 1);
}
pathfinder.h
#ifndef PATHFINDER_H
#define PATHFINDER_H
#include "map.h"
void dijkstra(map *map);
#endif // PATHFINDER_H
pathfinder.c
#include "pathfinder.h"
#include <stdio.h>
void dijkstra(map *map) {
map->coord[getIndex(map->length.x, map->begin)].distance = 0;
while(!isAllVisited(map)) {
tuple_2 u = smallestDistance(map);
if(u.x == -1 || u.y == -1) {
printf("No path found\n");
return;
}
map->coord[getIndex(map->length.x, u)].isChecked = 1;
updateNeighborhood(map, u);
}
tuple_2 path = map->end;
while(path.x != map->begin.x || path.y != map->begin.y) {
path = map->coord[getIndex(map->length.x, path)].coordinateFather;
map->coord[getIndex(map->length.x, path)].isInThePath = 1;
}
}
map.h
#ifndef MAP_H
#define MAP_H
static const char CHAR_WALL = '#';
static const char CHAR_NOTWALL = ' ';
static const char CHAR_PATH = '.';
static const char CHAR_BEGIN = '*';
static const char CHAR_END = '*';
static const char CHAR_VERTICAL_BORDER = '|';
static const char CHAR_HORIZONTAL_BORDER = '_';
typedef struct {
int x;
int y;
} tuple_2;
typedef struct {
tuple_2 coordinateFather;
int isChecked;
int distance;
int isPracticable;
int isInThePath;
} node;
typedef struct {
node *coord;
tuple_2 length;
tuple_2 begin;
tuple_2 end;
} map;
tuple_2 createTuple_2(int x, int y);
map* init(tuple_2 length);
void initNode(node *node);
void addBegin(map *map, tuple_2 begin);
void addEnd(map *map, tuple_2 end);
void addWall(map *map, tuple_2 coordinate);
int isAllVisited(map *map);
tuple_2 smallestDistance(map *map);
void print(map *map, int printPath);
int getIndex(int lengthX, tuple_2 coordinate);
int inBounds(map *map, tuple_2 coordinate);
void updateNeighborhood(map *map, tuple_2 coordinate);
#endif //MAP_H
map.c
#include "map.h"
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
tuple_2 createTuple_2(int x, int y) {
tuple_2 temp;
temp.x = x;
temp.y = y;
return temp;
}
void initNode(node *node) {
node->coordinateFather = createTuple_2(-1, -1);
node->isChecked = 0;
node->distance = INT_MAX;
node->isPracticable = 1;
node->isInThePath = 0;
}
map* init(tuple_2 length) {
if(length.x < 0 || length.y < 0) {
printf("Invalid length\n");
return NULL;
}
map *map = malloc(sizeof(map));
map->coord = malloc(length.x * length.y * sizeof(node));
map->length = length;
map->begin = createTuple_2(-1, -1);
map->end = createTuple_2(-1, -1);
for(int x = 0; x < length.x; ++x) {
for(int y = 0; y < length.y; ++y) {
initNode(&(map->coord[x + y * length.x]));
}
}
return map;
}
int getIndex(int lengthX, tuple_2 coordinate) {
return coordinate.x + coordinate.y * lengthX;
}
void addBegin(map *map, tuple_2 begin) {
if(!inBounds(map, begin))
{
printf("Begin out of bounds\n");
return;
}
map->begin = begin;
}
void addEnd(map *map, tuple_2 end) {
if(!inBounds(map, end)) {
printf("End out of bounds\n");
return;
}
map->end = end;
}
void addWall(map *map, tuple_2 coordinate) {
if(!inBounds(map, coordinate)) {
printf("Wall out of bounds");
return;
}
map->coord[getIndex(map->length.x, coordinate)].isPracticable = 0;
}
void updateNeighborhood(map *map, tuple_2 coordinate) {
for(int i = -1; i <= 1; ++i)
{
for(int j = -1; j <= 1; ++j)
{
tuple_2 neighbor = createTuple_2(coordinate.x + i, coordinate.y + j);
if(!inBounds(map, neighbor))
continue;
if(map->coord[getIndex(map->length.x, neighbor)].isChecked)
continue;
int cost = map->coord[getIndex(map->length.x, coordinate)].distance;
if(!j || !i)
cost += 10;
else
cost += 15; // diagonal
if(cost < map->coord[getIndex(map->length.x, neighbor)].distance)
{
map->coord[getIndex(map->length.x, neighbor)].distance = cost;
map->coord[getIndex(map->length.x, neighbor)].coordinateFather = coordinate;
}
}
}
}
int isAllVisited(map *map) {
for(int x = 0; x < map->length.x; ++x) {
for(int y = 0; y < map->length.y; ++y) {
if(map->coord[x + y * map->length.x].isPracticable &&
!map->coord[x + y * map->length.x].isChecked)
return 0;
}
}
return 1;
}
tuple_2 smallestDistance(map *map) {
int min = INT_MAX;
tuple_2 minCoordinate;
minCoordinate.x = -1;
minCoordinate.y = -1;
for(int x = 0; x < map->length.x; ++x) {
for(int y = 0; y < map->length.y; ++y) {
if(!map->coord[x + y * map->length.x].isChecked &&
map->coord[x + y * map->length.x].isPracticable &&
map->coord[x + y * map->length.x].distance < min) {
minCoordinate = createTuple_2(x, y);
}
}
}
return minCoordinate;
}
int inBounds(map *map, tuple_2 coordinate) {
return coordinate.x >= 0 && coordinate.x < map->length.x &&
coordinate.y >= 0 && coordinate.y < map->length.y;
}
void print(map *map, int printPath) {
putchar(' ');
for(int i = 0; i < map->length.x; ++i) {
putchar(CHAR_HORIZONTAL_BORDER);
}
for(int y = 0; y < map->length.y; ++y) {
putchar('\n');
putchar(CHAR_VERTICAL_BORDER);
for(int x = 0; x < map->length.x; ++x) {
if(x == map->begin.x && y == map->begin.y)
putchar(CHAR_BEGIN);
else if(x == map->end.x && y == map->end.y)
putchar(CHAR_END);
else {
if(printPath && map->coord[x + y * map->length.x].isInThePath) {
putchar(CHAR_PATH);
} else if (map->coord[x + y * map->length.x].isPracticable) {
putchar(CHAR_NOTWALL);
} else {
putchar(CHAR_WALL);
}
}
}
putchar(CHAR_VERTICAL_BORDER);
}
putchar('\n');
putchar(' ');
for(int i = 0; i < map->length.x; ++i) {
putchar(CHAR_HORIZONTAL_BORDER);
}
putchar('\n');
}
Output:
___________ | | | * | | . | | . | | ...... | |##########.| | .| | .| | .| | .| | *| ___________