-
Notifications
You must be signed in to change notification settings - Fork 1
/
path.c
137 lines (124 loc) · 5.41 KB
/
path.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "main.h"
#include "path.h"
//Partindo do destino faz o caminho contrário e descobre o próximo passo a ser dado
NODE *nextStep(NODE (*map_node)[60], struct position destiny){
NODE *dest = &map_node[destiny.y][destiny.x];
while(dest->parent->parent != NULL){
dest = dest->parent;
}
return dest;
}
//Criação do mapa e cálculo do custo H
void createMap(NODE (*map_node)[60], char (*map_char)[60], struct position destiny){
for(int i=0; i<MAX_Y; i++){
for(int j=0; j<MAX_X; j++){
map_node[i][j].pos.y = i;
map_node[i][j].pos.x = j;
map_node[i][j].h = fabs(destiny.x - map_node[i][j].pos.x) + fabs(destiny.y - map_node[i][j].pos.y); //H é uma estimativa (superestimada) do quanto falta para chegar ao destino
map_node[i][j].parent = NULL;
map_node[i][j].status = 0;
if(map_char[i][j] == '1'){ //substituir '1' pelo char correspondente à parede
map_node[i][j].pass = 0;
}else{
map_node[i][j].pass = 1;
}
}
}
}
//Retorna os quadrados adjacentes. No caso de adjacente fora da área válida retorna um ponteiro NULL
void findAdjacents(struct position pos, NODE **adjacents, NODE (*map_node)[60]){
if(pos.y > 0){
adjacents[0] = &map_node[pos.y -1][pos.x];
}else{
adjacents[0] = NULL;
}
if(pos.x > 0){
adjacents[1] = &map_node[pos.y][pos.x -1];
}else{
adjacents[1] = NULL;
}
if(pos.y < 22){
adjacents[2] = &map_node[pos.y +1][pos.x];
}else{
adjacents[2] = NULL;
}
if(pos.x < 59){
adjacents[3] = &map_node[pos.y][pos.x +1];
}else{
adjacents[3] = NULL;
}
}
//Varre a matriz em busca do menor F
NODE *findLowerF(NODE (*map_node)[60]){
NODE *lower = map_node[0];
for(int i=0; i<MAX_Y; i++){
for(int j=0; j<MAX_X; j++){
if( (lower->status != 1) || (map_node[i][j].f < lower->f && map_node[i][j].status == 1)){
lower = &map_node[i][j];
}
}
}
return lower;
}
//Cálculo dos pesos G (passos dados desde o início) e F (soma de G e H)
void writeWeight(NODE currentNode, NODE **adjacent){
(*adjacent)->g = currentNode.g + 10;
(*adjacent)->f = (*adjacent)->g + (*adjacent)->h;
}
//Encontra qual possível parent é o melhor caminho através do custo G dos quadrados adjacentes
int isBetterWay(NODE *currentNode, NODE *adjacentParent){
return (currentNode->g < adjacentParent->g);
}
//Função principal
int findPath(NODE (*map_node)[60], struct position destiny){
NODE *currentNode = findLowerF(map_node); //Encontra menor F (nó corrente)
currentNode->status = -1; //Move para a lista fechada
NODE *adjacents[4]; //Array de ponteiros para os adjacentes
findAdjacents(currentNode->pos, adjacents, map_node); //Encontra Adjacentes
for (int i=0; i < 4; i++){ //Para cada adjacente...
if(adjacents[i] != NULL){ //ignora se for nulo, não passável ou se estiver na lista fechada
if(adjacents[i]->pass && adjacents[i]->status != -1){
if(adjacents[i]->status != 1){ //Se não estiver na lista aberta move o nó para a lista aberta, faz o quadrado corrente o pai dele e calcula os pesos F e G
adjacents[i]->status = 1;
adjacents[i]->parent = currentNode;
writeWeight(*currentNode, adjacents+i);
}else if(adjacents[i]->status == 1){ //Se já estiver na lista aberta verifica se o caminho atual não é melhor
if(isBetterWay(currentNode, adjacents[i]->parent)){ //se for, atualiza o parent e os custos F e G
adjacents[i]->parent = currentNode;
writeWeight(*currentNode, adjacents+i);
}
}
}
}
}
//Argumento de parada:
if (isDestinyInClosedList(map_node, destiny)){ //Procura destino na lista fechada, se estiver, o caminho foi encontrado
return 1;
}else if (isOpenListEmpty(map_node)){
return 0; //Se não, verifica se existe algum elemento na lista aberta, se não tiver, não existe um caminho
}else{
return findPath(map_node, destiny); //Se a lista aberta contém elementos, é possível que exista um caminho. Chamada recursiva para a função
}
}
//Procura destino na lista fechada
int isDestinyInClosedList(NODE (*map_node)[60], struct position destiny){
if(map_node[destiny.y][destiny.x].status == -1){
return 1;
}else{
return 0;
}
}
//Procura qualquer elemento na lista aberta
int isOpenListEmpty(NODE (*map_node)[60]){
for(int i=0; i<MAX_Y; i++){
for(int j=0; j<MAX_X; j++){
if(map_node[i][j].status==1){
return 0;
}
}
}
return 1;
}