Estrutura de Dados – IF63C Professores Vida e Hilton 1 Pesquisas em Árvores 1. O que é? Pesquisar em uma árvore é navegar em seus nós até que um específico nó seja localizado. Dos diversos algoritmos encontrados na literatura, pode-se destacar dois algoritmos que são facilmente implementados com o conceito de lista. Esses dois algoritmos são muito utilizados pela Inteligência Artificial na resolução de problemas e são conhecidos por algoritmos de força bruta. Esses algoritmos são : Busca em Amplitude Busca em Profundidade Além desses dois algoritmos, também destaca-se um terceiro algoritmo realizar pesquisas, o Best-First Search. Esse algortimo é heurístico e diferencia-se pouco dos dois anteriores. O Best-First Search faz uso de uma função heurística de avaliação para ordenar as possíveis soluções em uma lista. Ordenadas essas soluções, seleciona-se a “melhor” solução para ser analisada antes das demais. Exemplo: A Figura 1, exemplifica uma árvore binária. Figura 1-Exemplo de Árvore Binária 2. Tipos de Busca: A árvore da Figura 1 pode ser percorrida conforme ilustram as Figuras 2 e 3. Na Figura 2, ela é percorrida com a Busca em Amplitude. Investiga-se todos os nós de uma profundidade N antes de iniciar a busca na profundidade N+1. Na Figura 3, ela é percorrida com a Busca em Profundidade. Nessa busca, investigase em seqüência cada ramo da árvore. Tanto a pesquisa ou busca em Profundidade quanto em Amplitude permitem navegar na árvore. Essas duas técnicas apresentam o inconveniente da explosão de nós, ou seja, muitos nós são gerados enquanto a solução não é encontrada. Estrutura de Dados – IF63C Professores Vida e Hilton 2 Figura 2-Busca em Amplitude Figura 3- Busca em Profundidade 2.1 Algoritmos Algoritmo de Busca em Amplitude (Breadth-First Search) 1) Criar uma lista e adicionar o primeiro nó. Esse nó representa o estado inicial da busca ou o nó raiz da árvore. 2) Loop: 3) Se a lista está vazia, então fim. 4) Remover o primeiro elemento da lista. Esse elemento é chamado de SearchNode 5) Se SearchNode contém o objetivo, então finalize com SearchNode como solução e fim. 6) Para cada filho do atual SearchNode, adicione esses elementos no final da lista. Estrutura de Dados – IF63C Professores Vida e Hilton 3 Algoritmo de Busca em Profundidade (Depth-First Search) 1. Criar uma lista e adicionar o primeiro nó. Esse nó representa o estado incial da busca ou o nó raiz da árvore. 2. Loop: 3. Se a lista está vazia, então fim. 4. Remover o primeiro elemento da lista. Esse elemento é chamado de SearchNode 5. Se SearchNode contém o objetivo, então finalize com SearchNode como solução e fim 6. Para cada filho do atual SearchNode, adicione esses elementos no início da lista. 2.2 Exemplo de Aplicação do Algoritmo Busca em Amplitude O quadro 1, a seguir, apresenta um programa C que busca pela solução do 8-puzzle utilizando a Busca em Amplitude. Esse programa foi, inicialmente, utilizado para obter os nós da árvore representados parcialmente na Figura 4. Destaca-se nesse quadro, a instrução da linha 195. Nessa instrução, busca-se limitar o nível de profundidade para conter a explosão do número excessivo de tabuleiros. O número escolhido de forma aleatória foi 5. Esse número pode ser aumentado e o algoritmo irá buscar por soluções além do quinto nível de profundidade. Esse número não deve ser grande devido a explosão combinatória. Em condições de teste, obteve-se um bom desempenho com esse número indo até 15. Quadro 1 – Exemplo de programa que utiliza a busca em Amplitude. /*1*/ /////utiliza a busca em Amplitude. /*2*/ #include<stdio.h> /*3*/ #include<stdlib.h> /*4*/ #include<string.h> /*5*/ #define TRUE 1 /*6*/ #define FALSE 0 /*7*/ /*8*/ /*9*/ /*10*/ /*11*/ /*12*/ /*13*/ struct tabuleiro { int LinhasColunas [3][3]; int nivel; //nivel do tabuleiro na arvore struct tabuleiro *next; struct tabuleiro *father; } *tabuleiro; struct tabuleiro GoalState, *CurrentState; /*14*/ /*15*/ /*16*/ /*17*/ /*18*/ /*19*/ /*20*/ /*21*/ /*22*/ void defineGoalState(); void defineCurrentState(); void inicializa(); int salvar(struct tabuleiro *t); int ehIgual(struct tabuleiro *v1, struct tabuleiro *v2); int insereNaLista(struct tabuleiro *v); void copie(struct tabuleiro *origem , struct tabuleiro *destino); int jogar(); Estrutura de Dados – IF63C Professores Vida e Hilton /*23*/ /*24*/ /*25*/ /*26*/ /*27*/ /*28*/ /*29*/ /*30*/ /*31*/ /*32*/ /*33*/ /*34*/ void defineGoalState() { GoalState.LinhasColunas[0][0]=1; GoalState.LinhasColunas[0][1]=2; GoalState.LinhasColunas[0][2]=3; GoalState.LinhasColunas[1][0]=8; GoalState.LinhasColunas[1][1]=0; GoalState.LinhasColunas[1][2]=4; GoalState.LinhasColunas[2][0]=7; GoalState.LinhasColunas[2][1]=6; GoalState.LinhasColunas[2][2]=5; } /*35*/ /*36*/ /*37*/ /*38*/ /*39*/ /*40*/ /*41*/ /*42*/ /*43*/ /*44*/ /*45*/ /*46*/ /*47*/ /*48*/ /*49*/ void defineCurrentState() { CurrentState = (struct tabuleiro *) malloc(sizeof(struct tabuleiro)); CurrentState->LinhasColunas[0][0]=1; CurrentState->LinhasColunas[0][1]=4; CurrentState->LinhasColunas[0][2]=3; CurrentState->LinhasColunas[1][0]=7; CurrentState->LinhasColunas[1][1]=0; CurrentState->LinhasColunas[1][2]=6; CurrentState->LinhasColunas[2][0]=5; CurrentState->LinhasColunas[2][1]=8; CurrentState->LinhasColunas[2][2]=2; CurrentState->nivel=0; } /*50*/ /*51*/ /*52*/ /*53*/ /*54*/ /*55*/ /*56*/ /*57*/ /*58*/ /*59*/ /*60*/ /*61*/ /*62*/ void inicializa() { tabuleiro = NULL; defineGoalState(); defineCurrentState(); insereNaLista(CurrentState); FILE *fp; if ( (fp= fopen("tabuleiro.txt","w")) == NULL) {printf( "\nERRO: Nao foi possivel escrever dados no arquivo"); printf("'tabuleiro.txt' !");}; fclose(fp); } /*63*/ /*64*/ /*65*/ /*66*/ /*67*/ /*68*/ /*69*/ /*70*/ int salvar(struct tabuleiro *t) { FILE *fp; if ( (fp= fopen("tabuleiro.txt","a+")) == NULL) { printf( "\nERRO: Nao foi possivel escrever dados no arquivo"); printf("'tabuleiro.txt' !"); 4 Estrutura de Dados – IF63C Professores Vida e Hilton /*71*/ /*72*/ /*73*/ /*74*/ /*75*/ /*76*/ /*77*/ /*78*/ /*79*/ /*80*/ /*81*/ /*82*/ /*83*/ /*84*/ /*85*/ /*86*/ /*87*/ return FALSE; /*FALSO*/ } fprintf(fp ,"\n\nTabuleiro: Nivel %i:\n\t+---+---+---+" ,t->nivel); for (int linha=0; linha < 3; linha++) { fprintf(fp,"\n\t|"); for (int coluna=0; coluna<3; coluna++) if ( t->LinhasColunas[linha][coluna] != 0) { fprintf(fp," %i |" ,t->LinhasColunas[linha][coluna]);} else { fprintf(fp," |");} fprintf(fp,"\n\t+---+---+---+"); } fclose(fp); return TRUE; } /*88*/ /*89*/ /*90*/ /*91*/ /*92*/ /*93*/ /*94*/ int ehIgual(struct tabuleiro *v1, struct tabuleiro *v2) { for (int linha=0; linha<3; linha++) for (int coluna=0; coluna < 3; coluna++) if (v1->LinhasColunas[linha][coluna] != v2->LinhasColunas[linha][coluna]) {return FALSE;} return TRUE;} /*95*/ /*96*/ /*97*/ /*98*/ /*99*/ /*100*/ /*101*/ /*102*/ /*103*/ /*104*/ /*105*/ /*109*/ /*110*/ /*111*/ /*112*/ /*113*/ int insereNaLista(struct tabuleiro *v) { if (tabuleiro == NULL) {v->next = NULL; tabuleiro = v; return TRUE; } struct tabuleiro *andarilho; andarilho=tabuleiro; while ((andarilho->next) != NULL) {andarilho=andarilho->next;} if (andarilho->next == NULL) { v->next = NULL; andarilho->next=v;} return TRUE; } void copie(struct tabuleiro *origem , struct tabuleiro *destino) { for (int linha=0; linha<3; linha++) for ( int coluna=0; coluna<3; coluna++) destino->LinhasColunas[linha][coluna]= origem->LinhasColunas[linha][coluna]; } /*114*/ /*115*/ /*116*/ /*117*/ struct tabuleiro *retirePrimeiro() { struct tabuleiro *saida = tabuleiro; tabuleiro=tabuleiro->next; return saida; /*106*/ /*107*/ /*108*/ 5 Estrutura de Dados – IF63C Professores Vida e Hilton /*118*/ } /*119*/ /*120*/ /*121*/ /*122*/ /*123*/ /*124*/ /*125*/ /*126*/ /*127*/ /*128*/ /*129*/ /*130*/ /*131*/ /*132*/ /*133*/ /*134*/ /*135*/ /*136*/ /*137*/ /*138*/ /*139*/ int jogar() { int linha=0, coluna=0; int aux; int nivelExpandido; CurrentState = retirePrimeiro(); nivelExpandido = CurrentState->nivel; salvar(CurrentState); if (ehIgual(CurrentState,&GoalState)==TRUE) {printf("\n\n\t\tfim achei a solucao!"); exit(0);} struct tabuleiro *aux2 = (struct tabuleiro *) malloc(sizeof(struct tabuleiro)); copie(CurrentState,aux2); int achei=FALSE; for (linha=0; linha<3; linha++) { for ( coluna=0; coluna<3; coluna++) if ( aux2->LinhasColunas[linha][coluna] == 0){achei=TRUE; break;} if ( achei ){break;} } if ((achei) && (coluna>2)){coluna=2;} if ((achei) && (linha>2)){linha=2;} /*140*/ /*141*/ /*142*/ /*143*/ /*144*/ /*145*/ /*146*/ /*147*/ /*148*/ /*149*/ /*150*/ /*151*/ /*152*/ // move o buraco para cima if (linha>0) { aux = aux2->LinhasColunas[linha-1][coluna]; aux2->LinhasColunas[linha-1][coluna]= aux2->LinhasColunas[linha][coluna]; aux2->LinhasColunas[linha][coluna]=aux; aux2->father = CurrentState; aux2->nivel = CurrentState->nivel+1; insereNaLista(aux2); aux2 = (struct tabuleiro *) malloc(sizeof(struct tabuleiro)); copie(CurrentState,aux2); } /*153*/ /*154*/ /*155*/ /*156*/ /*157*/ /*158*/ /*159*/ /*160*/ /*161*/ /*162*/ /*163*/ /*164*/ /*165*/ // move o buraco para direita if (coluna<2) { aux = aux2->LinhasColunas[linha][coluna+1]; aux2->LinhasColunas[linha][coluna+1]= aux2->LinhasColunas[linha][coluna]; aux2->LinhasColunas[linha][coluna]=aux; aux2->father = CurrentState; aux2->nivel = CurrentState->nivel+1; insereNaLista(aux2); aux2 = (struct tabuleiro *) malloc(sizeof(struct tabuleiro)); copie(CurrentState,aux2); } 6 Estrutura de Dados – IF63C Professores Vida e Hilton /*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*/ // move o buraco para baixo if (linha<2) { aux = aux2->LinhasColunas[linha+1][coluna]; aux2->LinhasColunas[linha+1][coluna]= aux2->LinhasColunas[linha][coluna]; aux2->LinhasColunas[linha][coluna]=aux; aux2->father = CurrentState; aux2->nivel = CurrentState->nivel+1; insereNaLista(aux2); aux2 = (struct tabuleiro *) malloc(sizeof(struct tabuleiro)); copie(CurrentState,aux2); } // move o buraco para esquerda if (coluna>0) { aux = aux2->LinhasColunas[linha][coluna-1]; aux2->LinhasColunas[linha][coluna-1]= aux2->LinhasColunas[linha][coluna]; aux2->LinhasColunas[linha][coluna]=aux; aux2->father = CurrentState; aux2->nivel = CurrentState->nivel+1; insereNaLista(aux2); } return nivelExpandido; } /*191*/ /*192*/ /*193*/ /*194*/ /*195*/ void main(void) { inicializa(); int nivel = jogar(); while (nivel < 5) {nivel=jogar(); } printf("\n ********* FIM do PROGRAMA"); /*196*/ /*197*/ } 7 Estrutura de Dados – IF63C Professores Vida e Hilton Figura 4-Exemplo de Árvore de Jogos para o 8-puzzle 8 Estrutura de Dados – IF63C Professores Vida e Hilton 9 2.3 Pesquisa Heurística A Figura 4, parcialmente, apresenta uma árvore. Nessa árvore são representados alguns dos possíveis movimentos do jogo 8-puzzle. A quantidade de jogadas que podem ser produzidas, nesse jogo, é um número muito elevado. Para problemas deste tipo, pode-se utilizar outros tipos de buscas além das buscas em Amplitude e Profundidade. Dos algoritmos disponíveis na literarutra, destaca-se o Best-First Search. Nesse algoritmo, as buscas necessitam ser mais refinadas ou inteligentes. Nesse contexto, ele utiliza uma função heurística h(jogada) como elemento “inteligente” para identificar qual é a melhor jogada. Identificada essa melhor jogada, analisa-se ela em primeiro lugar. A função h(jogada) deve avaliar uma possível solução e compará-la com todas as outras soluções possíveis. Após comparadas, seleciona-se a “melhor” solução e repte-se o processo até encontrar a solução final. Esse algoritmo é conhecido Busca Gulosa e pertence à categoria de algoritmos heurísticos Best-First. Algoritmo de Busca Gulosa O Melhor Primeiro (Best-First Search) 1) Criar uma lista e adicionar o primeiro nó. Esse nó representa o estado inicial da busca ou o nó raiz da árvore. 2) Loop: 3) Se a lista está vazia, então fim. 4) Remover o primeiro elemento da lista. Esse elemento é chamado de SearchNode 5) Se SearchNode contém o objetivo, então finalize com SearchNode como solução e fim. 6) Para cada filho do atual SearchNode, insira esse filho de maneira ordenada na lista. Outros algoritmos possíveis de serem utilizados nesse problema são MiniMax, Means-End, Greedy, A*, entre outros. 2.4 Exemplo do Algoritmo de Busca Gulosa O programa do Quadro 1 foi modificado e é apresentado no Quadro 2. Nessa modificação a função h(jogada) foi inserida para definir um critério de ordenamento para a lista de tabuleiros. – h(jogada) = distância de cada peça ao seu local correto. Com essa ordenação, cada tabuleiro analisado deverá ser o tabuleiro com maiores chances de sucesso. Logo, deve-se ordenar a lista dos nós expandidos ou soluções em ordem crescente a cada nó expandido da árvore. Nesse exemplo, quanto menor for o valor de h(jogada), melhor será a solução. /*1*/ /*2*/ /*3*/ /*4*/ /*5*/ Quadro 2 – Exemplo de programa que utiliza a Busca Gulosa. // utiliza a Busca Gulosa . #include<stdio.h> #include<stdlib.h> #include<string.h> #include<conio.h> Estrutura de Dados – IF63C Professores Vida e Hilton /*6*/ #define TRUE 1 /*7*/ #define FALSE 0 /*8*/ struct tabuleiro /*9*/ { int LinhasColunas [3][3]; /*10*/ int custo; /*11*/ int nivel; /*12*/ int numero; /*13*/ int numeroPai; /*14*/ struct tabuleiro *next; /*15*/ struct tabuleiro *father; /*16*/ } *inicio; /*17*/ int contador=0; /*18*/ struct tabuleiro GoalState, *CurrentState; /*19*/ /*20*/ /*21*/ /*22*/ /*23*/ /*24*/ /*25*/ /*26*/ /*27*/ /*28*/ /*29*/ /*30*/ /*31*/ /*32*/ void void void void int int int void /*33*/ /*34*/ /*35*/ /*36*/ /*37*/ /*38*/ /*39*/ /*40*/ /*41*/ /*42*/ /*43*/ /*44*/ /*45*/ /*46*/ /*47*/ /*48*/ /*49*/ /*50*/ /*51*/ /*52*/ /*53*/ /*54*/ /*55*/ /*56*/ int h(struct tabuleiro *v) { int h1=0; int i,j,k,m; for (i=0; i < 3; i++) for (j=0; j < 3; j++) { for (k=i; k < 3; k++) for ( m=j; m < 3; m++) if (GoalState.LinhasColunas[i][j] == v->LinhasColunas[k][m]) {h1 = h1 + abs(abs(k-i)+abs(m-j));} } return (h1); } void defineGoalState() { GoalState.LinhasColunas[0][0]=1; GoalState.LinhasColunas[0][1]=2; GoalState.LinhasColunas[0][2]=3; GoalState.LinhasColunas[1][0]=8; GoalState.LinhasColunas[1][1]=0; GoalState.LinhasColunas[1][2]=4; GoalState.LinhasColunas[2][0]=7; GoalState.LinhasColunas[2][1]=6; imprime(struct tabuleiro *t); defineGoalState(); defineCurrentState(); inicializa(); salvar(struct tabuleiro *t); ehIgual(struct tabuleiro *v1, struct tabuleiro *v2); insereNaLista(struct tabuleiro *v); copie(struct tabuleiro *origem , struct tabuleiro *destino); int jogar(); int insereOrdenado(struct tabuleiro *v); int h(struct tabuleiro *v); int jahVisitei(struct tabuleiro *v); void imprimeCaminhoSolucao(); 10 Estrutura de Dados – IF63C Professores Vida e Hilton 11 /*57*/ /*58*/ } GoalState.LinhasColunas[2][2]=5; /*59*/ /*60*/ /*61*/ /*62*/ /*63*/ /*64*/ /*65*/ /*66*/ /*67*/ /*68*/ /*69*/ /*70*/ /*71*/ void defineCurrentState() { CurrentState = (struct tabuleiro *) malloc(sizeof(struct tabuleiro)); CurrentState->LinhasColunas[0][0]=5; CurrentState->LinhasColunas[0][1]=0; CurrentState->LinhasColunas[0][2]=1; CurrentState->LinhasColunas[1][0]=2; CurrentState->LinhasColunas[1][1]=6; CurrentState->LinhasColunas[1][2]=8; CurrentState->LinhasColunas[2][0]=7; CurrentState->LinhasColunas[2][1]=3; CurrentState->LinhasColunas[2][2]=4; /*72*/ /*73*/ /*74*/ /*75*/ /*76*/ /*77*/ /*78*/ /*79*/ CurrentState->next=NULL; CurrentState->father=NULL; CurrentState->custo=h(CurrentState); CurrentState->nivel=0; CurrentState->numero=contador++; CurrentState->numeroPai=-1; inicio=CurrentState; } /*80*/ /*81*/ /*82*/ /*83*/ /*84*/ /*85*/ /*86*/ /*87*/ /*88*/ /*89*/ /*90*/ /*91*/ void inicializa() { defineGoalState(); defineCurrentState(); FILE *fp; if ( (fp= fopen("tabuleiro.txt","w")) == NULL) {printf( "\nERRO: Nao foi possivel escrever dados no arquivo"); printf("'tabuleiro.txt' !"); }; fclose(fp); } /*92*/ /*93*/ /*94*/ /*95*/ /*96*/ /*97*/ /*98*/ /*99*/ /*100*/ void imprimeCaminhoSolucao() { FILE *fp; struct tabuleiro *solucao = CurrentState; if ( (fp= fopen("tabuleiro.txt","a+")) == NULL) {printf( "\nERRO: Nao foi possivel escrever dados no arquivo"); printf("'tabuleiro.txt' !"); return;}; /*101*/ o estado /*102*/ /*103*/ /*104*/ /*105*/ /*106*/ /*107*/ fprintf(fp, "\n Lista de tabuleiros a partir da Solucao ate inicial:"); fclose(fp); int x=0; while (solucao) { x++; salvar(solucao); Estrutura de Dados – IF63C Professores Vida e Hilton 12 /*108*/ /*109*/ /*110*/ /*111*/ /*112*/ /*113*/ /*114*/ solucao = solucao->father; } if ( (fp= fopen("tabuleiro.txt","a+")) == NULL) {printf( "\nERRO: Nao foi possivel escrever dados no arquivo"); printf("'tabuleiro.txt' !"); return;}; /*115*/ /*116*/ /*117*/ fprintf(fp, "\n ***** Quantidade de Tabuleiros :%i",x); fclose(fp); } /*118*/ void imprime(struct tabuleiro *t) /*119*/ { /*120*/ printf("\n\nTabuleiro: nivel: %i custo: %i Numero:%i, Filho de: %i\n\t+---+---+---+" /*121*/ ,t->nivel,t->custo,t->numero,t->numeroPai); /*122*/ for (int linha=0; linha < 3; linha++) /*123*/ { printf("\n\t|"); /*124*/ for (int coluna=0; coluna<3; coluna++) /*125*/ if ( t->LinhasColunas[linha][coluna] != 0) /*126*/ { printf(" %i |",t->LinhasColunas[linha][coluna]);} /*127*/ else { printf(" |");} /*128*/ printf("\n\t+---+---+---+"); /*129*/ } /*130*/ } /*131*/ int salvar(struct tabuleiro *t) /*132*/ { /*133*/ FILE *fp; /*134*/ if (!t) return FALSE; /*135*/ if ( (fp= fopen("tabuleiro.txt","a+")) == NULL) /*136*/ {printf("\nERRO: Nao foi possivel escrever arquivo"); /*137*/ printf("'tabuleiro.txt' !"); /*138*/ return FALSE; /*FALSO*/}; dados no /*139*/ fprintf(fp,"\n\nTabuleiro: Nivel %i: Custo(funcao h): %i Numero: %i, Filho de : %i \n\t+---+---+---+",t->nivel,t->custo,t>numero,t->numeroPai); /*140*/ for (int linha=0; linha < 3; linha++) /*141*/ { fprintf(fp,"\n\t|"); /*142*/ for (int coluna=0; coluna<3; coluna++) /*143*/ if ( t->LinhasColunas[linha][coluna] != 0) /*144*/ { fprintf(fp," %i |",t->LinhasColunas[linha][coluna]);} /*145*/ else { fprintf(fp," |");} /*146*/ fprintf(fp,"\n\t+---+---+---+"); /*147*/ } /*148*/ fclose(fp); /*149*/ return TRUE; /*150*/ } /*151*/ /*152*/ /*153*/ /*154*/ /*155*/ int ehIgual(struct tabuleiro *v1, struct tabuleiro *v2) { for (int linha=0; linha<3; linha++) for (int coluna=0; coluna < 3; coluna++) if (v1->LinhasColunas[linha][coluna] != v2- Estrutura de Dados – IF63C Professores Vida e Hilton >LinhasColunas[linha][coluna]) /*156*/ {return FALSE;} /*157*/ return TRUE; /*158*/ } /*159*/ /*160*/ /*161*/ /*162*/ int jahVisitei(struct tabuleiro *v) { struct tabuleiro *andarilho = CurrentState; if (ehIgual(CurrentState,v)) return TRUE; /*163*/ /*164*/ /*165*/ /*166*/ /*167*/ /*168*/ /*169*/ /*170*/ while (andarilho) { if (ehIgual(andarilho,v)) return TRUE; else { andarilho=andarilho->father; } } return FALSE; } /*171*/ /*172*/ /*173*/ /*174*/ int insereNaLista(struct tabuleiro *v) { return insereOrdenado(v); } /*175*/ /*176*/ /*177*/ /*178*/ int insereOrdenado(struct tabuleiro *v) { struct tabuleiro *andarilho, *anterior; int com,com2; /*179*/ if (jahVisitei(v)) return FALSE; /*180*/ /*181*/ v->custo=h(v); v->father = CurrentState; /*182*/ /*183*/ /*184*/ /*185*/ /*186*/ /*187*/ /*188*/ /*189*/ /*190*/ anterior=NULL; andarilho = inicio; v->numero = contador++; if (inicio==NULL) { v->next = NULL; inicio =v; return TRUE; } /*191*/ /*192*/ /*193*/ /*194*/ while(andarilho) { if (ehIgual(andarilho, v )) {return FALSE;} com = v->custo - andarilho->custo; /*195*/ /*196*/ /*197*/ /*198*/ /*199*/ /*200*/ /*201*/ /*202*/ if (com >= 0) { anterior=andarilho; andarilho=andarilho->next;} else { v->next = andarilho; if (anterior) anterior->next = v; else {inicio=v;} return TRUE; } 13 Estrutura de Dados – IF63C Professores Vida e Hilton 14 /*203*/ /*204*/ /*205*/ /*206*/ /*207*/ /*208*/ } // insere no final. anterior->next = v; v->next = NULL; return TRUE; } /*209*/ /*210*/ /*211*/ /*212*/ /*213*/ /*214*/ /*215*/ /*216*/ /*217*/ /*218*/ /*219*/ /*220*/ void copie(struct tabuleiro *origem , struct tabuleiro *destino) { for (int linha=0; linha<3; linha++) for ( int coluna=0; coluna<3; coluna++) { destino->LinhasColunas[linha][coluna]= origem->LinhasColunas[linha][coluna]; destino->nivel=origem->nivel; destino->custo=origem->custo; destino->next=origem->next; destino->father=origem->father; } /*221*/ } /*222*/ /*223*/ /*224*/ /*225*/ /*226*/ struct tabuleiro *retirePrimeiro() { struct tabuleiro *saida = inicio; inicio=inicio->next; return saida; } /*227*/ /*228*/ /*229*/ /*230*/ /*231*/ /*232*/ /*233*/ /*234*/ /*235*/ void vitoria(struct tabuleiro *v) { clrscr(); imprime(v); if (ehIgual(v,&GoalState)==TRUE) {printf("\n\n\t\t *****Fim achei a solucao!"); imprimeCaminhoSolucao(); exit(0);} } /*236*/ /*237*/ /*238*/ /*239*/ /*240*/ /*241*/ int jogar() { int linha=0, coluna=0; int aux; int nivelExpandido; int custo=1000; // armazena o custo da jogada! /*242*/ /*243*/ /*244*/ CurrentState = retirePrimeiro(); vitoria(CurrentState); nivelExpandido = CurrentState->nivel; /*245*/ struct tabuleiro *aux2 malloc(sizeof(struct tabuleiro)); /*246*/ copie(CurrentState,aux2); /*247*/ int achei=FALSE; /*248*/ /*249*/ /*250*/ = (struct tabuleiro for (linha=0; linha<3; linha++) { for ( coluna=0; coluna<3; coluna++) if ( aux2->LinhasColunas[linha][coluna] == 0) *) Estrutura de Dados – IF63C Professores Vida e Hilton /*251*/ /*252*/ /*253*/ 15 {achei=TRUE; break;} if ( achei ){break;} } /*254*/ if ((achei) && (coluna>2)){coluna=2;} (linha>2)){linha=2;} /*255*/ // move o buraco para cima /*256*/ if (linha>0) /*257*/ {aux = aux2->LinhasColunas[linha-1][coluna]; /*258*/ aux2->LinhasColunas[linha-1][coluna]=aux2>LinhasColunas[linha][coluna]; /*259*/ aux2->LinhasColunas[linha][coluna]=aux; /*260*/ aux2->father = CurrentState; /*261*/ aux2->numeroPai = CurrentState->numero; /*262*/ aux2->nivel = CurrentState->nivel+1; if ((achei) && /*263*/ if (insereNaLista(aux2)) /*264*/ { if (custo > aux2->custo) custo = aux2->custo; /*265*/ if (CurrentState->next == NULL) CurrentState->next = aux2; /*266*/ } /*267*/ aux2 = (struct tabuleiro *) malloc(sizeof(struct tabuleiro)); /*268*/ copie(CurrentState,aux2); /*269*/ } /*270*/ // move o buraco para direita /*271*/ if (coluna<2) /*272*/ {aux = aux2->LinhasColunas[linha][coluna+1]; /*273*/ aux2->LinhasColunas[linha][coluna+1]=aux2>LinhasColunas[linha][coluna]; /*274*/ aux2->LinhasColunas[linha][coluna]=aux; /*275*/ aux2->father = CurrentState; /*276*/ aux2->nivel = CurrentState->nivel+1; /*277*/ aux2->numeroPai = CurrentState->numero; /*278*/ if (insereNaLista(aux2)) /*279*/ {if (custo > aux2->custo) custo = aux2->custo; /*280*/ if (CurrentState->next == NULL) CurrentState->next = aux2; /*281*/ } /*282*/ aux2 = (struct tabuleiro *) malloc(sizeof(struct tabuleiro)); /*283*/ copie(CurrentState,aux2); /*284*/ } /*285*/ // move o buraco para baixo /*286*/ if (linha<2) /*287*/ {aux = aux2->LinhasColunas[linha+1][coluna]; /*288*/ aux2->LinhasColunas[linha+1][coluna]=aux2>LinhasColunas[linha][coluna]; /*289*/ aux2->LinhasColunas[linha][coluna]=aux; /*290*/ aux2->father = CurrentState; /*291*/ aux2->nivel = CurrentState->nivel+1; /*292*/ aux2->numeroPai = CurrentState->numero; /*293*/ if (insereNaLista(aux2)) /*294*/ { /*295*/ if (custo > aux2->custo) custo = aux2->custo; /*296*/ if (CurrentState->next == NULL) CurrentState->next = aux2; /*297*/ } /*298*/ aux2 = (struct tabuleiro *) malloc(sizeof(struct tabuleiro)); /*299*/ copie(CurrentState,aux2); /*300*/ } /*301*/ // move o buraco para esquerda Estrutura de Dados – IF63C Professores Vida e Hilton /*302*/ if (coluna>0) /*303*/ {aux = aux2->LinhasColunas[linha][coluna-1]; /*304*/ aux2->LinhasColunas[linha][coluna-1]=aux2>LinhasColunas[linha][coluna]; /*305*/ aux2->LinhasColunas[linha][coluna]=aux; /*306*/ aux2->father = CurrentState; /*307*/ aux2->nivel = CurrentState->nivel+1; /*308*/ aux2->numeroPai = CurrentState->numero; /*309*/ if (insereNaLista(aux2)) /*310*/ {if (custo > aux2->custo) custo = aux2->custo; /*311*/ if (CurrentState->next == NULL) CurrentState->next = aux2; /*312*/ } /*313*/ } /*314*/ return custo; /*315*/ } /*316*/ /*317*/ /*318*/ /*319*/ /*320*/ /*321*/ /*322*/ /*323*/ /*324*/ void printFila() { struct tabuleiro *andarilho = inicio; while (andarilho) { salvar(andarilho); andarilho=andarilho->next; } } /*325*/ /*326*/ /*327*/ /*328*/ /*329*/ /*330*/ /*331*/ /*332*/ /*333*/ void main(void) { inicializa(); int nivel = 0, n=0; while ( (nivel++) < 20000) { jogar(); } imprimeCaminhoSolucao(); printf("FIM!"); } /*334*/ 16 Estrutura de Dados – IF63C Professores Vida e Hilton 17 77 Figura 5-Exemplo de Execução do Programa de Busca Gulosa Estrutura de Dados – IF63C Professores Vida e Hilton Figura 6-Exemplo de Saída do Programa de Busca Gulosa - parte 1 18 Estrutura de Dados – IF63C Professores Vida e Hilton 19 Figura 7-Exemplo de Saída do Programa de Busca Gulosa - parte 2 Tarefa: 1) Copie o trecho de código do Quadro 1 para o ambiente de desenvolvimento C. Compile e execute esse programa. O programa foi capaz de encontrar a solução? 2) Modifique o programa do Quadro 1 para a busca em Profundidade. 3) Pesquise, também, outros algoritmos que estão disponíveis na literatura ou na internet para o jogo 8-puzzle. Um bom exercício de programação é tentar implementar cada um desses algoritmos.