TProcuraAdversa
Algoritmos de procura adversa
Loading...
Searching...
No Matches
TProcuraAdversa.cpp
Go to the documentation of this file.
1#include "TProcuraAdversa.h"
2#include <stdio.h>
3#include <time.h>
4#include <math.h>
5
6// valor de infinito (vitoria/derrota), omissao 1000
8// controlo para indicar se a procura foi realizada de forma completa (c.c. foi cortada)
10// hashtable / valor e nível obtido
12// profundidade máxima no método iterativo
14// número de vezes que uma avaliação é reutilizada
16
17TProcuraAdversa::TProcuraAdversa(void) : minimizar(true), indiceHT(-1)
18{
19
20}
21
25
27{
28 static const char* nomesAlgoritmos[] = { "MiniMax", "MiniMax alfa/beta" };
30
31 // adicionar parâmetros da procura adversa
32 // alterar algoritmos
33 parametro[algoritmo] = { "Algoritmo",2,1,2,"Seleção do algoritmo de procura adversa base.", nomesAlgoritmos };
34
35 parametro[limite].valor = 0; // procura iterativa preferencial
36 parametro[estadosRepetidos].valor = 1; // nas procuras adversas, não utilizar este parametro (utilizar ordenar=2)
37 parametro[baralharSuc].valor = 0; // de omissão está com valor 0, para facilitar nos testes, mas deve ficar com 1 para obter jogos distintos
38
39 // O "infinito" é dependente do problema, não faz sentido alterar senão no código
40 parametro.Add({ "Ordenar",2,0,2, "0 não ordena sucessores, 1 ordena por heurística, 2 usa o melhor valor de procuras anteriores.",NULL });
41 parametro.Add({ "PodaHeuristica",0,0,1000, "0 não existe poda, caso contrário é o número máximo de sucessores a considerar (tem de se ordenar sucessores).",NULL });
42 parametro.Add({ "PodaCega",0,0,10000, "Igual a PodaHeuristica, mas é efetuado de forma aleátoria, sem calcular a heurística. Utilizar um valor sempre maior que Poda. ",NULL });
43}
44
45
47// Algoritmo MiniMax
49// retorna o valor do estado actual, apos procura de profundidade nivel
51{
53 // no final da árvore, retornar (valor da heuristica)
54 if (nivel == 1 || Parar()) {
55 completo = false; // árvore cortada, a procura deixa de ser completa
56 return NoFolha(true);
57 }
58
59 if (nivel == 0)
60 return MetodoIterativo(false);
61
62 // expandir o estado
63 TVector<TNo> sucessores;
64 Sucessores(sucessores);
65 // caso não existam sucessores, é como se fosse um nó folha
66 if (sucessores.Count() == 0)
67 return NoFolha(false);
68
69 TVector<int> id; // índice para ordenar os sucessores por heurística
70 OrdenarSucessores(sucessores, id, nivel);
71
72 int resultado = 0, melhor = -1;
73 // processar os sucessores
74 for (int i = 0; i < sucessores.Count(); i++) {
75 DebugExpansao(i, sucessores.Count(), minimizar);
76 int valor;
77 TValorEstado valorConhecido;
78
79 if (((TProcuraAdversa*)sucessores[id[i]])->ValorEstado(valorConhecido, ler) &&
80 valorConhecido.nivel >= nivel)
81 {
82 valor = valorConhecido.valor;
83 }
84 else {
85 // chamada recursiva, com um nível a menos, idêntico à procura em profundidade
86 valor = ((TProcuraAdversa*)sucessores[id[i]])->MiniMax(nivel - 1);
87 valorConhecido = { valor, nivel, exato };
88 ((TProcuraAdversa*)sucessores[id[i]])->ValorEstado(valorConhecido, gravar);
89 }
90
91 // pretende-se obter o melhor resultado, que oscila entre minimizar ou maximizar
92 if (i == 0 || (minimizar ? resultado > valor : resultado < valor)) {
93 resultado = valor;
94 melhor = id[i];
95 if (nivel > 1 && parametro[nivelDebug].valor >= 2) { // colocar valor actual alterado
96 NovaLinha();
97 printf("(%d)", resultado);
98 }
99 if (minimizar ? resultado <= custo + 1 - infinito : resultado >= infinito - custo - 1)
100 break; // nao e possivel melhorar
101 }
102 }
103 // todos os sucessores analizados, se houver uma solução melhor, retornar
104 if (melhor >= 0) {
105 if (solucao != NULL)
106 delete solucao;
107 solucao = sucessores[melhor];
108 }
109 DebugCorte(sucessores.Count(),minimizar);
110 LibertarVector(sucessores, melhor);
111 return resultado;
112}
113
115 TValorEstado calculado;
116 heuristica = TProcuraConstrutiva::Heuristica(); // incrementa avaliações e adiciona ruído se for caso disso
117 // valor da heurística já calculado, gravar
118 calculado = { heuristica,0,exato }; // valor da heurística com nível 0
119 ValorEstado(calculado, gravar);
120 return heuristica;
121}
122
123// chamar em CSubProblema::Heuristica() para verificar se a heurística já existe, ou precisa de ser calculada
125 TValorEstado calculado;
126 if (ValorEstado(calculado, ler)) {
127 heuristica = calculado.valor;
128 return true;
129 }
130 return false;
131}
132
134 TVector<TNo>& sucessores, TVector<int>& id, int nivel)
135{
136 if (parametro[podaCega].valor > 0 &&
137 sucessores.Count() > parametro[podaCega].valor)
138 {
139 // podar de forma aleatória, nem heurística deve ser calculada
140 while (sucessores.Count() > parametro[podaCega].valor) {
141 int id = TRand::rand() % sucessores.Count();
142 delete sucessores[id];
143 sucessores[id] = sucessores.Last();
144 sucessores.Pop();
145 }
146 }
147
148 id.Count(0);
149 if (nivel>2 && parametro[ordenarSucessores].valor >= 1) {
150 CalcularHeuristicas(sucessores, &id); // id fica ordenado por heurística
151
152 if (!minimizar)
153 id.Invert();
154
155 // podar sucessores
156 if (parametro[podaHeuristica].valor > 0 &&
157 parametro[podaHeuristica].valor < id.Count()) {
158 TVector<TNo> manterSuc;
159 for (int i = 0; i < parametro[podaHeuristica].valor; i++)
160 manterSuc.Add(sucessores[id[i]]);
161 for (int i = parametro[podaHeuristica].valor; i < id.Count(); i++)
162 delete sucessores[id[i]];
163 sucessores = manterSuc;
164 id.Count(0);
165 for (int i = 0; i < sucessores.Count(); i++)
166 id.Add(i);
167 }
168
169 }
170 else
171 for (int i = 0; i < sucessores.Count(); i++)
172 id.Add(i);
173}
174
175// iteração, aumentando o nível progressivamente
177 int resultado = 0, resOK = 0, nivel = 0;
178 nivelOK = 0;
179 TNo solOK = NULL;
180 do {
181 DebugIteracao(nivel + 1);
182 completo = true;
183 // chamar a profundidade nível 1, e se não resolver, o nível 2, e assim sucessivamente
184 resultado = (alfaBeta ? MiniMaxAlfaBeta(++nivel) : MiniMax(++nivel));
185 if (!Parar() || nivel == 0) {
186 // guardar a última solução realizada sem interrupções, bem como o resultado
187 if (solOK != NULL)
188 delete solOK;
189 solOK = solucao;
190 solucao = NULL;
191 resOK = resultado;
192 nivelOK = nivel;
193 if (parametro[nivelDebug].valor > 0 && solOK != NULL)
194 printf("\n%d: %s (%d)", nivel, Acao(solOK), resultado);
195 }
196 else
197 completo = false;
198 } while (!completo && !Parar());
199 if (solucao != NULL)
200 delete solucao;
201 solucao = solOK;
202 return resOK;
203}
204
205// Utilitário para calculo de uma heurística standard em jogos simples (tipicamente sem empates):
206// - calcular o número de ameaças de vitória, para cada lado, de menor comprimento:
207// - qMin - vetor com número de ameaças (1 ou mais) a 1 jogada (na primeira posição), a 2 (na segunda posição), e assim sucessivamente;
208// - qMax - vetor com número de ameaças (1 ou mais) a 1 jogada (na primeira posição), a 2 (na segunda posição), e assim sucessivamente;
210{
211 int pontos = 0, peso = 1;
212
213 // verificar situações de ganho imediato
214 if (!minimizar && qMax.First() > 0)
215 return infinito; // Vitória imediata para o max
216 if (minimizar && qMin.First() > 0)
217 return -infinito; // Vitória imediata para o min
218
219 // Ameaças iguais a maxAmeaca ou superior, valem 1, todas as outras valem conforme
220 if (maxAmeaca > qMin.Count())
221 peso <<= (maxAmeaca - qMin.Count());
222 for (int i = qMin.Count() - 1, peso = 1; i >= 0; i--) {
223 pontos -= qMin[i] * peso;
224 if (i < maxAmeaca) // peço começa a duplicar
225 peso <<= 1;
226 }
227 peso = 1;
228 if (maxAmeaca > qMax.Count())
229 peso <<= (maxAmeaca - qMin.Count());
230 for (int i = qMax.Count() - 1, peso = 1; i >= 0; i--) {
231 pontos += qMax[i] * peso;
232 if (i < maxAmeaca) // peço começa a duplicar
233 peso <<= 1;
234 }
235
236 return infinito * (2 / (1 + exp(-0.01 * pontos)) - 1);
237}
238
239// fim da procura, por corte de nível (ou não haver sucessores), retornar heurística
241 int resultado;
242 DebugCorte(nivel ? -1 : 0, minimizar);
243
244 resultado = Heuristica();
245
246 if (resultado >= infinito) {
247 resultado = infinito - custo; // subtrair
248 // jogo ganho pelo branco
249 // se o agente minimiza, tentar o jogo mais longo possível
250 // caso contrário, quanto maior o jogo pior, quer o jogo mais curto
251 // a minimizar, entre um nível 10 e 20, irá preferir o 20, já que -20 é menor que -10
252 // a maximizar, entre um nível 10 e 20, irá preferir o 10, já que 10 é menor que 20
253 }
254 else if (resultado <= -infinito) {
255 resultado = custo - infinito; // somar
256 // jogo ganho pelo preto
257 // se o agente maximiza, tentar o jogo mais longo possível
258 // caso contrário, quanto maior o jogo pior, quer o jogo mais curto
259 // a maximizar, entre 10 e 20, irá preferir 20, sempre é maior
260 // a minimizar, entre 10 e 20, irá preferir 10 que é menor
261 }
262 if (parametro[nivelDebug].valor > 1)
263 printf(" %d", resultado);
264 return resultado;
265}
266
268// Algoritmo MiniMaxAlfaBeta
270// retorna o valor do estado actual, apos procura de profundidade nivel
271// idêntico a MiniMax
272int TProcuraAdversa::MiniMaxAlfaBeta(int nivel, int alfa, int beta)
273{
274 DebugChamada();
275 if (nivel == 1 || Parar()) {
276 completo = false;
277 return NoFolha(true);
278 }
279
280 if (nivel == 0)
281 return MetodoIterativo(true);
282
283 TVector<TNo> sucessores;
284 Sucessores(sucessores);
285 if (sucessores.Count() == 0)
286 return NoFolha(false);
287
288 TVector<int> id; // índice para ordenar os sucessores por heurística
289 OrdenarSucessores(sucessores, id, nivel);
290
291 int resultado = 0, melhor = -1;
292 for (int i = 0; i < sucessores.Count(); i++) {
293 DebugExpansao(i, sucessores.Count(), minimizar);
294 int valor;
295 TValorEstado valorConhecido;
296
297 if (((TProcuraAdversa*)sucessores[id[i]])->ValorEstado(valorConhecido, ler) &&
298 Utilizavel(valorConhecido, nivel, alfa, beta))
299 {
300 valor = valorConhecido.valor;
301 }
302 else {
303 // chamada recursiva, com um nível a menos, idêntico à procura em profundidade
304 valor = ((TProcuraAdversa*)sucessores[id[i]])->MiniMaxAlfaBeta(nivel - 1, alfa, beta);
305 valorConhecido = { valor, nivel, exato };
306 if (valor <= alfa)
307 valorConhecido.tipo = upperbound; // Causado por corte alfa
308 else if (valor >= beta)
309 valorConhecido.tipo = lowerbound; // Causado por corte beta
310 // registar valor apenas se estiver dentro de alfa/beta (para não influenciarem o resultado)
311 ((TProcuraAdversa*)sucessores[id[i]])->ValorEstado(valorConhecido, gravar);
312 }
313
314 if (i == 0 || (minimizar ? resultado > valor : resultado < valor)) {
315 resultado = valor;
316 melhor = id[i];
317 if (nivel > 1 && parametro[nivelDebug].valor >= 2) {
318 // colocar valor actual alterado
319 NovaLinha();
320 printf("(%d)", resultado);
321 }
322 }
323 // corte alfa/beta bem como atualização
324 if (i < sucessores.Count() - 1) { // nao interessa cortar quando não há mais nada para cortar
325 if (CorteAlfaBeta(resultado, alfa, beta))
326 break;
327 }
328 }
329 if (melhor >= 0) {
330 if(solucao!=NULL)
331 delete solucao;
332 solucao = sucessores[melhor];
333 }
334 DebugCorte(sucessores.Count(),minimizar);
335 LibertarVector(sucessores,melhor);
336 return resultado;
337}
338
339bool TProcuraAdversa::Utilizavel(TValorEstado& valor, int nivel, int alfa, int beta) {
340 return valor.nivel >= nivel &&
341 (valor.tipo == exato ||
342 valor.tipo == lowerBound && valor.valor >= beta ||
343 valor.tipo == upperbound && valor.valor <= alfa);
344}
345
346
347// verifica se há um corte alfa/beta, atualizando alfa e beta
348bool TProcuraAdversa::CorteAlfaBeta(int valor, int& alfa, int& beta) {
349 if (minimizar) { // pretas
350 // ver se ja e maximo
351 if (valor <= custo + 1 - infinito)
352 return true;
353 if (alfa >= valor) {
354 // corte alfa
355 if (parametro[nivelDebug].valor > 1) {
356 // substituir o ultimo caracter por um corte
357 ramo.Last() = '>';
358 NovaLinha();
359 printf(" alfa(%d)",alfa);
360 }
361 return true; // as brancas tem uma alternativa, e escusado continuar a procurar aqui
362 }
363 // atualização beta
364 if (beta > valor)
365 beta = valor;
366 }
367 else { // brancas
368 // ver se atingiu o maximo
369 if (valor >= infinito - custo - 1)
370 return true;
371 if (beta <= valor) {
372 // corte beta
373 if (parametro[nivelDebug].valor > 1) {
374 ramo.Last() = '>';
375 NovaLinha();
376 printf(" beta(%d)",beta);
377 }
378 return true; // as pretas tem uma alternativa, e escusado continuar a procurar aqui
379 }
380 // atualização alfa
381 if (alfa < valor)
382 alfa = valor;
383 }
384 // não há corte
385 return false;
386}
387
388// utilizar para executar testes empíricos, utilizando todas as instâncias,
389// Utiliza as configurações existentes, ou parâmetros atuais
390// Efetua um torneio entre configurações
391void TProcuraAdversa::TesteEmpirico(int inicio, int fim, bool mostrarSolucoes) {
392 TVector<int> atual;
393 int backupID = instancia.valor;
394 if (inicio == NAO_LIDO)
395 inicio = instancia.min;
396 if (fim == NAO_LIDO)
397 fim = instancia.max;
400 ConfiguracaoAtual(atual, ler);
401 if (configuracoes.Count() == 0) {
402 // não foram feitas configurações, utilizar a atual
404 configuracoes.Last() = atual;
405 }
406 if (configuracoes.Count() == 1) {
407 // apenas há uma configuração, utilizar a atual como segunda
409 configuracoes.Last() = atual;
410 }
411
412 TVector<TVector<int>> torneio; // pares de configurações: 1 melhor, 0 igual -1 pior
413 TVector<int> tempoTotal; // tempo total de resposta, em todos os jogos
414 torneio.Count(configuracoes.Count());
415 for (int i = 0; i < configuracoes.Count(); i++) {
416 torneio[i].Count(configuracoes.Count());
417 torneio[i].Reset(0);
418 }
419 tempoTotal.Count(configuracoes.Count());
420 tempoTotal.Reset(0);
421
422 // dois jogadores, brancas é o primeiro a jogar, pretas é o segundo
423 for (int brancas = 0; brancas < configuracoes.Count(); brancas++)
424 for (int pretas = 0; pretas < configuracoes.Count(); pretas++)
425 if (brancas != pretas) {
426 printf("\nMatch %d vs %d:", brancas + 1, pretas + 1);
427 for (instancia.valor = inicio; instancia.valor <= fim; instancia.valor++) {
428 int resultado = -1, njogada=0;
429 clock_t inicioCorrida;
430 printf("\n Instância %d: ", instancia.valor);
431 // carregar instância
432 SolucaoVazia();
433 // jogar ora de brancas ora de pretas, até o jogo terminar
434 while (!SolucaoCompleta()) {
435 ConfiguracaoAtual(configuracoes[njogada % 2 == 0 ? brancas : pretas], gravar);
437 inicioCorrida = clock();
438 LimparEstatisticas(inicioCorrida);
439 resultado = ExecutaAlgoritmo();
440 tempoTotal[njogada % 2 == 0 ? brancas : pretas] += clock() - inicioCorrida;
441 if (solucao != NULL) { // efetuado um lance
442 const char* strAcao = Acao(solucao);
444 if (mostrarSolucoes) {
445 if (parametro[verAcoes].valor == 1 ||
446 njogada% parametro[verAcoes].valor==0) {
447 printf("\n%s %d %s",
448 (njogada % 2 == 0 ? "Brancas" : "Pretas"),
449 (njogada / 2) + 1, strAcao);
450 Debug();
451 printf(" f:%d ", resultado);
452 }
453 else // mostrar apenas a ação
454 printf(" %s", strAcao);
455 }
456 njogada++;
457 }
458 else {
459 break; // não há lance efetuado
460 resultado = 0; // erro, mas considerar empatado
461 }
462 }
463 // jogo terminou, registar resultdo
464 if (resultado != 0) {
465 bool inverter;
466 // brancas e minimizar ou pretas e maximizar, inverter
467 inverter = (njogada % 2 == 0) && minimizar ||
468 (njogada % 2 == 1) && !minimizar;
469 // vitória/derrota branca/preta
470 torneio[brancas][pretas] += (resultado < 0 ? -1 : 1) * (inverter ? -1:1);
471 printf(" Vitória %s", (inverter ? resultado < 0 : resultado > 0) ? "Branca" : "Preta");
472 }
473 else
474 printf(" Empate");
475 }
476 }
477
478 MostrarTorneio(torneio, true);
479 printf("\nTempos: ");
480 for (int i = 0; i < tempoTotal.Count(); i++)
481 printf("%.3fs ", 1.0 * tempoTotal[i] / CLOCKS_PER_SEC);
483 printf("\n");
485 instancia.valor = backupID;
487 SolucaoVazia();
488}
489
490
492 int resultado = -1;
493 if (parametro[ordenarSucessores].valor == 2) {
495 if (reutilizadoAvaliacao > 0 && parametro[nivelDebug].valor >= 1) {
496 float taxa = 1.0 * reutilizadoAvaliacao / colocadosHT;
497 LimparHT();
498 printf(" HT: reutilização %.2f vezes ", taxa);
499 } else
500 LimparHT();
503 }
504 switch (parametro[algoritmo].valor) {
505 case 1: resultado = MiniMax(Dominio(parametro[limite].valor, 0)); break;
506 case 2: resultado = MiniMaxAlfaBeta(Dominio(parametro[limite].valor, 0)); break;
507 }
508 return resultado;
509}
510
511// necessário redefinir para atualizar valorHT em caso de colisão
514 valorHT[indiceHT = indice].nivel = -1;
515}
516
518 // caso não exista, retorna falso e insere
519 // se existe retorna falso à mesma para não remover, dado que é uma alternativa para este lance concreto
520 // se estiver lá outro elemento, substitui
521 unsigned int original = Hash();
522 unsigned int indice = original % TAMANHO_HASHTABLE;
523 indiceHT = indice;
524 for (int i = 0; i < tamanhoCodificado; i++) {
525 if (elementosHT[indice][i] != estadoCodHT[i]) {
526 SubstituirHT(indice);
527 colocadosHT++;
528 return false; // não existia
529 }
530 }
531 return false; // é como se não existisse, mas está lá
532}
533
534
535bool TProcuraAdversa::ValorEstado(TValorEstado& valor, int operacao) {
536 if (parametro[ordenarSucessores].valor != 2)
537 return false;
538 ExisteHT(); // calcula indiceHT
539 if (operacao == ler) {
540 if (indiceHT >= 0 && valorHT[indiceHT].nivel >= 0) {
541 valor = valorHT[indiceHT];
543 return true;
544 }
545 return false;
546 }
547 // gravar
548 if (indiceHT >= 0 && valorHT[indiceHT].nivel < valor.nivel)
549 valorHT[indiceHT] = valor;
550
551 return true;
552}
553
554
555
@ podaHeuristica
permite cortar sucessores, mas calcula a heurística a todos, de modo a mantendo os melhores
@ podaCega
corta os sucessores, mesmo sem calcular a heurística, por ordem aleatória
@ ordenarSucessores
opção de ordenar sucessores por heurística, ou por último valor registado
@ upperbound
o valor foi afetado por um corte de alfa (ou seja, ele é no máximo esse valor, mas pode ser menor).
@ exato
o valor foi calculado sem cortes, ou seja, não sofreu influência de alfa ou beta;
@ lowerbound
o valor foi afetado por um corte de beta (ou seja, ele é pelo menos esse valor, mas pode ser maior);
@ limite
Valor dependente do algoritmo. Exemplo: Profundidade limitada.
@ estadosRepetidos
Forma de lidar com estados repetidos (ignorá-los, ascendentes, gerados).
@ verAcoes
Mostra estado a cada K ações. Se 1, mostra sempre estados e nunca ações.
@ seed
Semente aleatória para inicializar a sequência de números pseudo-aleatórios.
@ nivelDebug
Nível de debug, de reduzido a completo.
@ baralharSuc
Baralhar os sucessores ao expandir.
@ algoritmo
Algoritmo base a executar.
#define NAO_LIDO
@ gerados
estados são comparados com todos os gerados, e se forem repetidos são removidos
@ ignorados
ignorados os estados gerados repetidos
#define TAMANHO_HASHTABLE
Representa um estado no espaço de estados.
int NoFolha(bool nivel)
fim da procura, por corte de nível (ou não haver sucessores), retornar heurística
int MaiorAmeaca(TVector< int > &qMin, TVector< int > &qMax, int maxAmeaca)
Utilitário para calculo de uma heurística standard em jogos simples.
void OrdenarSucessores(TVector< TNo > &sucessores, TVector< int > &id, int nivel)
int MiniMax(int nivel=4)
retorna o valor do estado actual, apos procura de profundidade nivel
static bool completo
controlo para indicar se a procura foi realizada de forma completa (c.c. foi cortada)
bool minimizar
o jogador actual deve minimizar o custo (ou maximizar caso tenha o valor falso)
int Heuristica(void)
chamar após calcular a heurística (grava o valor, dependendo da parametrização)
int MetodoIterativo(int alfaBeta)
iteração, aumentando o nível progressivamente
bool CorteAlfaBeta(int valor, int &alfa, int &beta)
verifica se há um corte alfa/beta, atualizando alfa e beta
bool ValorEstado(TValorEstado &valor, int operacao)
ler ou gravar o melhor valor conhecido
bool ExisteHeuritica(void)
void ResetParametros()
Método para inicializar os parâmetros (redefinir se forem adicionados parâmetros específicos)
void SubstituirHT(int indice)
static int reutilizadoAvaliacao
bool Utilizavel(TValorEstado &valor, int nivel, int alfa, int beta)
ver se o valor obtido é utilizável no contexto atual
static int infinito
valor de infinito (vitoria/derrota), omissao 1000
static int nivelOK
profundidade máxima no método iterativo
int MiniMaxAlfaBeta(int nivel=4, int alfa=-infinito, int beta=+infinito)
retorna o valor do estado actual, apos procura de profundidade nivel. Idêntico a MiniMax
static TValorEstado valorHT[TAMANHO_HASHTABLE]
void TesteEmpirico(int inicio=-1, int fim=-1, bool mostrarSolucoes=true)
Executa testes empíricos, em todas as configurações guardadas, nas instâncias selecionadas.
int ExecutaAlgoritmo()
Executa o algoritmo com os parametros atuais.
Representa um estado no espaço de estados.
void DebugCorte(int sucessores=-1, bool duplo=false)
void MostrarTorneio(TVector< TVector< int > > &torneio, bool jogo=false)
void ConfiguracaoAtual(TVector< int > &parametros, int operacao)
static uint64_t elementosHT[TAMANHO_HASHTABLE][OBJETO_HASHTABLE]
void CalcularHeuristicas(TVector< TNo > &sucessores, TVector< int > *id=NULL, bool sortLB=false)
int Dominio(int &variavel, int min=INT_MIN, int max=INT_MAX)
void NovaLinha(bool tudo=true)
static void LibertarVector(TVector< TNo > &vector, int excepto=-1, int maiorQue=-1)
virtual void SubstituirHT(int indice)
void MostrarConfiguracoes(int detalhe, int atual=-1)
void DebugExpansao(int sucessor, int sucessores, bool duplo=false)
void LimparEstatisticas(clock_t &inicio)
void DebugIteracao(int iteracao)
static uint64_t estadoCodHT[OBJETO_HASHTABLE]
static unsigned int rand(int seq=0)
Definition TRand.cpp:61
static void srand(unsigned int seed, int seq=0)
Definition TRand.cpp:44
Item & First()
Definition TVector.h:68
void Add(Item a)
Definition TVector.h:54
Item & Pop()
Definition TVector.h:61
int Count()
Definition TVector.h:70
void Reset(Item const &i)
Definition TVector.h:309
Item & Last()
Definition TVector.h:69
virtual void Sucessores(TVector< TNo > &sucessores)
Coloca em sucessores a lista de estados sucessores.
virtual bool SolucaoCompleta(void)
Verifica se o estado actual é objectivo (é uma solução completa)
virtual void SolucaoVazia(void)
Coloca o objecto no estado inicial da procura.
virtual void Copiar(TNo objecto)
Fica com uma cópia do objecto.
virtual bool Parar(void)
Verifica se a procura deve ser interrompida.
virtual int Heuristica(void)
Função para calcular quanto falta para o final, o valor da heurística.
virtual void Debug(void)
Mostra o estado no ecrã, para debug.
virtual void ResetParametros()
Inicializa os parametros.
virtual const char * Acao(TNo sucessor)
Retorna a ação (movimento, passo, jogada, lance, etc.) que gerou o sucessor.
int heuristica
Estimativa para o custo até um estado objetivo, se disponível.
int custo
Custo total acumulado desde o estado inicial.
static int lowerBound
Valor mínimo que a solução pode apresentar, obtido pela procura.
static int tamanhoCodificado
Número de inteiros de 64 bits utilizados para codificar um objeto (≤ OBJETO_HASHTABLE).
static TVector< TVector< int > > configuracoes
Conjuntos de configurações para teste empírico.
static TVector< TParametro > parametro
Parâmetros a serem utilizados na configuração atual.
static TVector< unsigned char > ramo
static TNo solucao
Estado objetivo encontrado, retornado pela procura (deve ser libertado).
static TParametro instancia
ID da instância atual, a ser utilizado em SolucaoVazia().
int valor
valor do parametro
int max
valor máximo que o parametro pode tomar
int min
valor mínimo que o parametro pode tomar
registo do valor de um estado, em procuras anteriores
ETipoValor tipo