/* path.c - functions related to finding path between points * on board * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. */ #include #include #include /* returns x coordinate of the node number_of_cells: number of cells in the row */ int __find_x_of_the_node(int node, int number_of_x_cells, int number_of_y_cells) { assert(number_of_x_cells > 0); return node % number_of_x_cells; } /* returns y coordinate of the node number_of_cells: number of cells in the row */ int __find_y_of_the_node(int node, int number_of_x_cells, int number_of_y_cells) { assert(number_of_x_cells > 0); return node / number_of_x_cells; } /* returns x and y coordinates of the node */ void find_x_y_of_the_node(int *x, int *y, int node, int number_of_x_cells, int number_of_y_cells) { *x = __find_x_of_the_node(node, number_of_x_cells, number_of_y_cells); *y = __find_y_of_the_node(node, number_of_x_cells, number_of_y_cells); } /* returns node at x and y coordinates */ int find_node_of_x_y(int x, int y, int number_of_x_cells) { return y * number_of_x_cells + x; } /* find number of the node by its coordinates number_of_cells: number of cells in the row */ int find_node_by_coords(int x, int y, int number_of_x_cells, int number_of_y_cells) { return y * number_of_x_cells + x; } /* mark all neighbouring nodes of the nodes source_nodes: source nodes neighbours: neighbouring nodes mark: number to mark neighbours number_of_cells: number of cells in the row returns number of marked nodes */ int mark_neighbours_of_the_nodes(int *nodes, int *source_nodes, int *neighbours, int mark, int number_of_x_cells, int number_of_y_cells) { int i, j, neighbours_count = 0; int x, y, node; int xses[4] = { 0, 0, 1, -1}; int yses[4] = {-1, 1, 0, 0}; for(i = 1; i <= source_nodes[0]; i++) { find_x_y_of_the_node(&x, &y, source_nodes[i], number_of_x_cells, number_of_y_cells); if(x != -1 && y != -1) { for(j = 0; j < 4; j++) { if(x + xses[j] >= 0 && x + xses[j] < number_of_x_cells && y + yses[j] >= 0 && y + yses[j] < number_of_y_cells) { node = find_node_by_coords(x + xses[j], y + yses[j], number_of_x_cells, number_of_y_cells); if((node != -1) && nodes[node] == 0) { nodes[node] = mark; neighbours[++neighbours_count] = node; } } } } } neighbours[0] = neighbours_count; return neighbours_count; } /* check if nodes are neighbours */ int is_neighbours(int node1, int node2, int xn, int yn) { int x1, y1, x2, y2; find_x_y_of_the_node(&x1, &y1, node1, xn, yn); find_x_y_of_the_node(&x2, &y2, node2, xn, yn); if((x1 == x2) && ((y1 == y2 + 1) || (y2 == y1 + 1))) { return 1; } else if((y1 == y2) && ((x1 == x2 + 1) || (x2 == x1 + 1))) { return 1; } return 0; } /* find the path between source_node and the target_node result stored in path returns 0 on failure and 1 on success */ int find_path(int *nodes, int source_node, int target_node, int *path, int number_of_x_cells, int number_of_y_cells) { int waves[number_of_x_cells * number_of_y_cells][number_of_x_cells * number_of_y_cells]; int i, j, k = 1, finish = 0; waves[0][0] = 1; waves[0][1] = source_node; nodes[source_node] = -1; while(!finish) { if(!mark_neighbours_of_the_nodes(nodes, waves[k - 1], waves[k], k, number_of_x_cells, number_of_y_cells)) { /* the destination can never be reached */ return 0; } for(i = 1; i <= waves[k][0]; i++) { if(waves[k][i] == target_node) { finish = 1; break; } } k++; } path[0] = k; path[1] = waves[k - 1][i]; for(j = k - 2; j > 0; j--) { finish = 0; for(i = 1; i <= waves[j][0]; i++) { if(is_neighbours(waves[j][i], path[k - j - 1], number_of_x_cells, number_of_y_cells)) { path[k - j] = waves[j][i]; break; } } } return 1; }