-
Notifications
You must be signed in to change notification settings - Fork 0
/
sketch.js
292 lines (234 loc) · 8.56 KB
/
sketch.js
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
// Atividade 3 da Matéria PLIA
// Aluno: Samuel Gadiel de Ávila
// Matricula: 11721EAU005
new p5();
// Tamanho do tabuleiro
const cols = 25;
const rows = 25;
var grid = new Array(cols);
// Tamanho da celula
const cellwidth = 650 / cols;
const cellHeight = 650 / rows;
// const squares = (cols * rows);
// Essas são as coordenadas dos obstaculos que serão usados
let [wallsX, wallsY] = addWalls();
// Permite diagonais
let allowDiagonals = false;
let outputFailureP = undefined;
let outputSuccessP = undefined;
let outputFailureContainer = undefined;
let outputSuccessContainer = undefined;
// Lista de pontos a checar
let openSet = [];
// Lista de pontos checados
let closedSet = [];
let start;
let end;
let current;
// Lista de pontos do melhor caminho
let path;
// Função que é chamada quando clica no checkbox de diagonais
setDiagonals = () => allowDiagonals = !allowDiagonals;
// Dada uma lista, nesse caso openSet, remove um dado elemento quando encontrar ele por index
function rmvFromOpen(lista, elemento) {
lista = lista.reverse();
for (var i = 0; i < lista.length; i++) {
if (lista[i] == elemento) {
lista.splice(i, 1);
}
}
lista = lista.reverse();
}
// Calcula a distancia entre dois pontos
heuristic = (a, b) => abs(a.x - b.x) + abs(a.y - b.y)
// Configurando quais vao ser as barreiras do grid
function addWalls() {
const numWalls = 200;
let wallX = [];
let wallY = [];
// Seleciona aleatoriamente pontos do grid e cria uma lista com esses pontos
for (let i = 0; i < numWalls; i++) {
x = random(cols);
y = random(rows);
wallX.push(Math.floor(x));
wallY.push(Math.floor(y));
}
return [wallX, wallY];
}
// Insere os obstaculos no grid
function placeWalls(start, end) {
for (let i = 0; i < wallsX.length; i++) {
currentX = wallsX[i];
currentY = wallsY[i];
// ponto inicial e final são pontos proibidos de serem obstaculos
disallowedWalls = [start, end];
// Se ponto inicial ou final fizerem parte dos pontos selecionados pula aquele ponto
// Se não fizer parte diz que aquele ponto será um obstaculo
if (disallowedWalls.includes(grid[currentX][currentY])) {
continue;
} else {
grid[currentX][currentY].isWall = true;
}
}
}
// Reinicia o loop
startPathfinding = () => loop()
// Reseta a aplicação para rodar um novo "jogo"
function clearPathfinding() {
openSet = [];
closedSet = [];
path = [];
outputFailureP.html(" ");
outputSuccessP.html("");
setup();
draw();
}
// Limpa toda a grid e cria novos obstaculos para essa grid
function newWalls() {
grid = [];
[wallsX, wallsY] = [];
// Seleciona novos pontos para serem os obstaculos
[wallsX, wallsY] = addWalls();
// reset do jogo
clearPathfinding();
}
// -----------------------------------------------------------------------------------------------------------
function setup() {
background(0);
frameRate(15);
// Captura as tags HTML
// allowDiagonals = select("#diagonals");
outputFailureP = select("#failureResultP");
outputSuccessP = select("#successResultP");
outputSuccessContainer = select(".success");
outputFailureContainer = select(".failure");
// allowDiagonals = diagInput.value();
let cnv = createCanvas(650, 650);
cnv.parent('canvasContainer');
// Cria a matriz da grid
for (var i = 0; i < cols; i++) {
grid[i] = new Array(rows);
}
// Para cada ponto do grid cria uma classe Square
for (var i = 0; i < cols; i++) {
for (var j = 0; j < rows; j++) {
grid[i][j] = new Square(i * cellwidth, j * cellHeight);
}
}
// Ponto inicial e final
start = grid[0][0];
end = grid[cols - 1][rows - 1];
// Toma os pontos selecionados a serem obstaculos e os coloca no grid
placeWalls(start, end);
// Para cada ponto define quais serao os vizinhos
for (var i = 0; i < cols; i++) {
for (var j = 0; j < rows; j++) {
grid[i][j].addNeighbors(grid);
}
}
// Adiciona o ponto inicial à lista de pontos a serem analisados (openSet)
openSet.push(start);
noLoop();
}
// ---------------------------------------------------------------------------------------------------------------
function draw() {
// Se houver pontos a serem analisados
if (openSet.length > 0) {
// Encontra o ponto com menor valor de F
let winner = 0;
for (let i = 0; i < openSet.length; i++) {
// Se houverem dois pontos com o mesmo custo de F
// toma aquele com maior gCost, ou seja, aquele que estiver mais longe do ponto inicial
if (openSet[i].fCost == openSet[winner].fCost) {
if (openSet[i].gCost > openSet[winner].gCost) {
winner = i;
}
}
}
// Proximo ponto avaliado será aquele com indice vencedor
let current = openSet[winner];
// QUando encontrar o final devemos mostrar o caminho
if (current == end) {
path = [];
var tmp = current;
path.push(tmp);
// Retorna do fim ao inicio adicionando os pontos percorridos
while (tmp.previous) {
path.push(tmp.previous);
tmp = tmp.previous;
}
// Mostra na tela quantos quadrados precisou percorrer
outputFailureP.html("")
outputSuccessP.html("")
outputSuccessP.html("Solução: <br>" + path.length + " Quadrados")
outputSuccessContainer.addClass("show")
noLoop();
}
// Se não tiver encontrado o final continua o programa
// Remove o ponto de openSet e adiciona em closedSet
rmvFromOpen(openSet, current);
closedSet.push(current);
// Define os vizinhos do ponto atual
const neighbors = current.neighbors;
for (var i = 0; i < neighbors.length; i++) {
var neighbor = neighbors[i];
// Checa se esse vizinho está no closedSet
// Se estiver quer dizer que aquele vizinho já foi analisado
if (!closedSet.includes(neighbor)) {
// Distancia do ponto atual até o inicio + distancia do ponto atual
// ao vizinho
const tempG = current.gCost + heuristic(neighbor, current);
// Se o vizinho não estiver no openSet, inclua para ser analisado depois
// Se não, checa se o G calculado é maior que do vizinho
// Se for, pula para o proximo indice pois esse é o melhor ponto
if (!openSet.includes(neighbor)) {
openSet.push(neighbor);
} else if (tempG >= neighbor.gCost) {
continue;
}
// Se não for maior define o G do vizinho como sendo o G calculado
neighbor.gCost = tempG;
// Define a distancia desse ponto ao final
neighbor.hCost = this.heuristic(neighbor, end);
// E calcula o valor de F para esse ponto
neighbor.fCost = neighbor.hCost + neighbor.gCost;
// Por fim o vizinho recebe o ponto atual como sendo o ponto anterior
// Tornando ele o ponto atual
neighbor.previous = current;
}
}
// Se nao houver mais pontos a serem analisados quer dizer que não tem solução
} else {
outputFailureP.html("")
outputSuccessP.html("")
outputFailureP.html("Sem Solução")
outputFailureContainer.addClass("show")
}
// stroke(0);
// Passa por todos os pontos pintando
for (var i = 0; i < cols; i++) {
for (var j = 0; j < rows; j++) {
grid[i][j].show(color(255, 255, 255));
}
}
// Pinta todosos pontos analisados de vermelho
for (var i = 0; i < closedSet.length; i++) {
closedSet[i].show(color(235, 64, 52));
}
// Pinta todos os pontos a serem analisados de verde
for (var i = 0; i < openSet.length; i++) {
openSet[i].show(color(50, 168, 82));
}
// Se houver um caminho do inicio ao fim
if (path) {
// Passa por todos os pontos deste caminho
for (var i = 0; i < path.length; i++) {
// Pinta cada ponto de azul
// path[i].show(color(168, 50, 136));
path[i].show(color(52, 223, 235));
}
}
// Mostra os pontos inicial e final
start.show(color(252, 186, 3));
end.show(color(66, 135, 245));
}