# **Manual Técnico - Fase 2** <div align="center"> ## Projeto Fase 2 - Jogo do Cavalo ### Unidade Curricular de Inteligência Artificial Prof. Filipe Mariano e Prof. Joaquim Filipe >Realizado por Pedro Moura (202100110) e Rui Jesus (202100279) ![image](https://images.ctfassets.net/txbhe1wabmyx/60HyQr4qP5muAWtxgG6l3p/a8d870fed7c2e0bac46b72c6d6abcc23/pexels-tara-winstead-8386440.jpg) </div> --- ## **2. Arquitetura do Sistema** A arquitetura da presente solução encontra-se dividida em 4 ficheiros principais: - **Interact.lisp** - Carrega os restantes ficheiros - Efetua a leitura e escrita de ficheiros - Interação com o Utilizador - **Jogo.lisp** - Código relacionado com o problema específico - **Algoritmo.lisp** - Contém todos os algoritmos implementados no projeto - **Log.dat** - Contém os resultados do jogo executados A divisão em causa representa os 4 principais elementos lógicos do projeto, e visa acima de tudo, representar diversas camadas de abstração. Sendo este um problema teoria de jogos, com algoritmos concebidos para uma implementação genérica, procurámos desde início promover a máxima abstração entre as funções relativas a estas operações e à estrutura relativa ao Jogo do Cavalo, promovendo a capacidade de aplicar o sistema relacionado com o puzzle a qualquer outro problema. ## **3. Entidades e a sua Implementação** Para a realização do presente projeto, foi necessária a implementação de diferentes entidades e Tipos Abstratos de Dados, que permitissem a relação entre o código LISP e o domínio da aplicação. As mesmas serão enumeradas no presente capítulo, através da sua identificação e descrição ### **3.1. Estado** Elemento fundamental de qualquer algoritmo de procura, um estado visa caracterizar o problema num determinado momento da execução. Direcionado ao domínio da aplicação, neste projeto o estado representará o tabuleiro e os pontos dos jogadores, associados ao problema. Através dos operadores do problema, estes estados sofrerão alterações, até que se alcance um estado solução, neste caso representado pelo número de pontos <=0. Neste contexto, o estado vai igualmente servir o papel de nó, visto não existir necessidade de armazenar outras informações, como a profundidade. <p style="text-align: center;"><img src="https://i.brainking.com/rules/kfight/01.gif" alt="drawing" width="250" align="center"/></p> Recorrendo à notação BNF, o estado será representado através da expressão: ``` <Estado> ::= ( {<Pontos>} {<Tabuleiro>} ) <Tabuleiro> ::= ({Linha}*10) ``` E em lisp, tomará a forma seguinte: ``` (<PONTOSA> <PONTOSB> ( (< Linha 1 >) (< Linha 2 >) (< Linha 3 >) (< Linha 4 >) (< Linha 5 >) (< Linha 6 >) (< Linha 7 >) (< Linha 8 >) (< Linha 9 >) (< Linha 10 >) )) ``` Tomemos como exemplo a estrutura de um tabuleiro gerado aleatoriamente: ``` ( (0 0) ( (94 25 54 89 21 8 36 14 41 96) (78 47 56 23 5 49 13 12 26 60) (0 27 17 83 34 93 74 52 45 80) (69 9 77 95 55 39 91 73 57 30) (24 15 22 86 1 11 68 79 76 72) (81 48 32 2 64 16 50 37 29 71) (99 51 6 18 53 28 7 63 10 88) (59 42 46 85 90 75 87 43 20 31) (3 61 58 44 65 82 19 4 35 62) (33 70 84 40 66 38 92 67 98 97) )) ``` É importante frisar que, dada a necessidade de representar dois cavalos no tabuleiro, estes assumirão os dígitos: - -1 -> Cavalo Jogador 1 - -2 -> Cavalo Jogador 2 Este TAD visa assim representar o **Tabuleiro** no âmbito do domínio da aplicação, através dos seguintes operadores: - `estado-tabuleiro` - Devolve o tabuleiro do estado - `estado-pontos-jogador1` - Devolve o número de pontos do jogador1 - `estado-pontos-jogador2` - Devolve o número de pontos do jogador2 - `adicionar-pontos-jogador` - Adiciona pontos ao jogador passado por parâmetro ### **3.2 Movimento** Ao longo do desenvolvimento do programa, foi necessário em determinado momento, detetar a possibilidade de movimento ameaçado. Visto que as funções de sucessores estavam integradas na chamada de duplo-ou-simetrico, estas tornavam-se infinitamente recursivas, tendo sido necessária a criação de um TAD que guardasse um estado, a nova linha e a nova coluna do movimento Desta forma, o TAD em questão tem a seguinte estrutura: ``` Movimento :== ({<Estado>} {<Linha>} {<Coluna>} | ``` E podemos interagir com o mesmo através dos seletores: - `movimento-novo-estado` - Devolve o novo estado - `movimento-nova-linha` - Devolve a linha - `movimento-nova-coluna` - Devolve a coluna ### 3.3 Resultado Alfabeta Graças à necessidade de a cada iteração do algoritmo, mostrar as suas estatísticas, foi necessária a criação de um Tipo Abstrato de Dados responsável pelo armazenamento das informações devolvidas pelo alfabeta. Desta forma, este TAD tem a seguinte estrutura: ``` <Resultado-Alfabeta> ::= ( {<Valor>} {<Nos-Analisados>} {<Cortes-Alfa>} {<Cortes-Beta>} ) ``` Podemos interagir com este TAD através das seguintes operações: - `resultado-alfabeta-valor` - Devolve o valor do algoritmo - `resultado-alfabeta-nos-analisados` - Devolve o número de nós analisados - `resultado-alfabeta-cortes-alfa` - Devolve o número de cortes alfa - `resultado-alfabeta-cortes-beta` - Devolve o número de cortes beta ### 3.4 Jogada Computador Visto que o resultado do AlfaBeta é um Tipo Abstrato de Dados, limitado ás informações mostradas anteriormente, aquando das jogadas do computador, foi necessário também guardar a própria jogada executada, valor esse que não é retornado pelo alfabeta. Desta forma, procedemos à criação do Tipo Abstrato de Dados Jogada-Computador, com a seguinte estrutura: ``` <Jogada-Computador> ::= ( {<Resultado-Alfabeta>} {<Tempo-Execucao>} {<Jogada>} ) ``` ## **4. Algoritmos e a sua Implementação** O presente capítulo visa apresentar a descrição dos Algoritmos implementados na solução bem como a forma como os mesmos são executados. ### **4.1 Descrição Teórica** Antes de contextualizar a execução dos algoritmos, é necessária a introdução teórica ao conceito por detrás dos mesmos. Como é sabido, o processo de teoria de jogos é composto por diversos algoritmos que visam desenvolver inteligência artifical para jogos competitivos de soma zero, onde um jogador vence, e outro perde. O algoritmo minimax, utilizado no projeto, assenta num conceito de árvore de jogo, que recorrendo a nós efetua a análise das possibilidades a serem executadas. Sob este algoritmo, existem ainda os cortes alfa-beta, que permitem uma otimização ao mesmo através do conceito de cortes sem perda de informação relevante. ### **4.1.1 Minimax** O algoritmo Minimax caracteriza-se assim enquanto o mais importante algoritmo relativo à teoria de jogos, responsável pela iteração da árvore de jogo. O princípio deste algoritmo, caracteriza-se por "descer" na árvore de jogo, até chegar ao seu termino, verificando se o jogador em causa, perdeu, empatou ou ganhou. Após isto, o algoritmo sobe recursivamente os nós, atualizando os valores de min e max destas ramificações, repetindo isto até chegar ao nó raiz da árvore. Desta forma, o algoritmo minimax visa assim anteceder as jogadas de todos os caminhos possíveis no jogo, aconselhando aqueles que devolvem melhores resultados ao jogador max Este algoritmo, apresenta assim o seguinte pseudocódigo: ``` function MINIMAX-DECISION(state) returns an action  return arg max a ∈ ACTIONS(s) MIN-VALUE(RESULT(state, a)) function MAX-VALUE(state) returns a utility value  if TERMINAL-TEST(state) then return UTILITY(state)  v ← −∞  for each a in ACTIONS(state) do    v ← MAX(v, MIN-VALUE(RESULT(state, a)))  return v function MIN-VALUE(state) returns a utility value  if TERMINAL-TEST(state) then return UTILITY(state)  v ← ∞  for each a in ACTIONS(state) do    v ← MIN(v, MAX-VALUE(RESULT(state, a)))  return v ``` *Extraído do livro "Artificial Intelligence a Modern Approach, 3rd edition"* ### **4.1.2 AlphaBeta** Aquando da utilização do minimax, é perceptível que em grande parte dos problemas, com uma elevada quantidade de possíveis estados, torna-se incomportável avaliar todos os nós possíveis da árvore de jogo. Desta forma, torna-se necessário existir uma solução que permita o corte de nós cuja necessidade de avaliação seja nula, sem que isto afete o resultado final. Surge assim o alfabeta, enquanto complemento ao algoritmo minimax, que pára de avaliar os nós quando sabe que o mesmo possui resultados desfavoráveis. Este algoritmo apresenta o seguinte pseudocódigo: ``` function minimax(node, depth, isMaximizingPlayer, alpha, beta): if node is a leaf node : return value of the node if isMaximizingPlayer : bestVal = -INFINITY for each child node : value = minimax(node, depth+1, false, alpha, beta) bestVal = max( bestVal, value) alpha = max( alpha, bestVal) if beta <= alpha: break return bestVal else : bestVal = +INFINITY for each child node : value = minimax(node, depth+1, true, alpha, beta) bestVal = min( bestVal, value) beta = min( beta, bestVal) if beta <= alpha: break return bestVal ``` ### **4.2 Implementação** O presente capítulo visa detalhar a implementação da estrutura do projeto, efetuando uma ponte entre osfundamentos teóricos e a sua execução prática do AlfaBeta. #### 4.2.1 Geral Como descrito no ponto de arquitetura, o presente projeto possui 3 componentes principais, correspondentes aos seguintes ficheiros: - **Interact.lisp** - Carrega os restantes ficheiros - Efetua a leitura e escrita de ficheiros - Interação com o Utilizador - **Jogo.lisp** - Código relacionado com o problema específico - **Algoritmo.lisp** - Contém todos os algoritmos implementados no projeto De um ponto de vista lógico, o programa inicia na função `jogar`, no ficheiro **Interact.lisp**. Esta função é responsável pela chamada da interação inicial com o utilizadorm questionando o tipo de jogo a executar (computador-humano/computador-computador). Após isto, é chamada a função respetiva de entre as várias possibilidades: - `jogar-humano-computador` - `jogar-computador-computador` #### 4.2.1.1 Operadores No presente projeto, foram implementados 8 operadores, que visam representar os movimentos possíveis do cavalo em cada um dos estados. Estes foram implementados com base no seguinte código de exemplo, representativo do operador 1: ``` (defun operador-1 (estado peca) "Operador do problema, corresponde à jogada +2 linha e -1 coluna" (let* ( (tabuleiro (estado-tabuleiro estado)) (movimento (movimento-operador 'operador-1 estado peca)) (nova-linha (movimento-nova-linha movimento)) (nova-coluna (movimento-nova-coluna movimento)) (novo-estado (movimento-novo-estado movimento)) ) (cond (novo-estado (duplo-ou-simetrico (celula nova-linha nova-coluna tabuleiro ) novo-estado peca)) (T nil) ) )) ``` Como é possível verificar, este operador manipula assim o tabuleiro, visando devolver um novo estado com a nova posição do cavalo. É este operador o responsável pelo processo de movimento do cavalo, bem como de execução do operador `duplo-ou-simetrico`, que como frisado no enunciado do projeto: > *"Se a casa escolhida tiver um número com dois dígitos diferentes, por exemplo 57, então, em consequência, o número simétrico 75 é apagado do tabuleiro, tornando esta casa inacessível durante o resto do jogo. Ou seja, nenhum cavalo pode terminar outra jogada nessa casa."* > > *"Se um cavalo for colocado numa casa com um número "duplo", por exemplo 66, então qualquer outronúmero duplo pode ser removido e o jogador deve escolher qual em função da sua estratégia (por default remover a de maior valor). Depois de um jogador deixar a casa para se movimentar para outra, a casa onde estava fica também inacessível para o jogo, ficando o numero da casa apagado."* > in Projeto Nº 2: Época Normal - Inteligência Artificial #### 4.2.2 Minimax+Alfabeta Apresentada a estrutura geral do funcionamento da solução, analisemos a implementação do algoritmo no projeto. Esta, assentou assim no princípio teórico do mesmo, seguindo o pseudocódigo já apresentado A aplicação destes princípios resultou na função: ``` (defun alfabeta (no profundidade-max peca limite-tempo &optional (maximo T) (alfa most-negative-fixnum) (beta most-positive-fixnum) (nos-analisados 0) (cortes-alfa 0) (cortes-beta 0) (tempo-inicial (get-internal-real-time)) &aux (tempo-atual (get-internal-real-time)) (tempo-execucao ( - tempo-atual tempo-inicial ))) (cond ( (or (= profundidade-max 0) (no-terminalp no peca) (> tempo-execucao limite-tempo) ) (list (no-avaliacao no peca maximo) (1+ nos-analisados) cortes-alfa cortes-beta) ) (T (let* ( (jogadas (ordenar-nos-intermedios (remove nil (mapcar #'(lambda (operador) (funcall operador no peca) ) (operadores) )) peca maximo )) ) (if maximo (minimax-max jogadas profundidade-max peca alfa beta nos-analisados cortes-alfa cortes-beta limite-tempo tempo-inicial) (minimax-min jogadas profundidade-max peca alfa beta nos-analisados cortes-alfa cortes-beta limite-tempo tempo-inicial) ) ) ) ) ) ``` Esta função é assim responsável pela chamada das funções respetivas para o min e para o max: ``` (defun minimax-max (jogadas profundidade-max peca alfa beta nos-analisados cortes-alfa cortes-beta limite-tempo tempo-inicial &optional (valor most-negative-fixnum) (melhor-jogada nil)) (cond ((null jogadas) (progn (setq *jogada* melhor-jogada) (list valor nos-analisados cortes-alfa cortes-beta))) ; atualiza *jogada* com a melhor jogada (T (let* ( (jogada (car jogadas)) (resultado (alfabeta-memo jogada (1- profundidade-max) (trocar-peca peca) limite-tempo nil alfa beta nos-analisados cortes-alfa cortes-beta tempo-inicial )) (valor-resultado (resultado-alfabeta-valor resultado)) (nos-analisados-resultado (resultado-alfabeta-nos-analisados resultado) ) (novo-valor (max valor-resultado valor)) (novo-alfa (max alfa novo-valor)) (cortes-alfa-resultado (resultado-alfabeta-cortes-alfa resultado)) (cortes-beta-resultado (resultado-alfabeta-cortes-beta resultado)) (novo-cortes-alfa (if (>= novo-alfa beta) (1+ cortes-alfa-resultado) cortes-alfa-resultado)) ) (cond ((>= novo-alfa beta) (progn (setq *jogada* melhor-jogada) (list beta nos-analisados-resultado novo-cortes-alfa cortes-beta-resultado )) ) (T (if (> valor-resultado valor) (minimax-max (cdr jogadas) profundidade-max peca novo-alfa beta nos-analisados-resultado novo-cortes-alfa cortes-beta-resultado limite-tempo tempo-inicial valor-resultado jogada) ; atualiza a melhor jogada (minimax-max (cdr jogadas) profundidade-max peca novo-alfa beta nos-analisados-resultado novo-cortes-alfa cortes-beta-resultado limite-tempo tempo-inicial valor melhor-jogada)) ) ) ) ) ) ) (defun minimax-min (jogadas profundidade-max peca alfa beta nos-analisados cortes-alfa cortes-beta limite-tempo tempo-inicial &optional (valor most-positive-fixnum) ) (cond ((null jogadas) (list valor nos-analisados cortes-alfa cortes-beta)) (T (let* ( (jogada (car jogadas)) (resultado (alfabeta-memo jogada (1- profundidade-max) (trocar-peca peca) limite-tempo T alfa beta nos-analisados cortes-alfa cortes-beta tempo-inicial)) (valor-resultado (resultado-alfabeta-valor resultado)) (nos-analisados-resultado (resultado-alfabeta-nos-analisados resultado) ) (novo-valor (min valor-resultado valor)) (novo-beta (min beta novo-valor)) (cortes-alfa-resultado (resultado-alfabeta-cortes-alfa resultado)) (cortes-beta-resultado (resultado-alfabeta-cortes-beta resultado)) (novo-cortes-beta (if (>= alfa novo-beta ) (1+ cortes-beta-resultado) cortes-beta-resultado)) ) (cond ((>= alfa novo-beta ) (list alfa nos-analisados-resultado cortes-alfa-resultado novo-cortes-beta) ) (T (if (< valor-resultado valor ) (minimax-min (cdr jogadas) profundidade-max peca alfa novo-beta nos-analisados-resultado cortes-alfa-resultado novo-cortes-beta limite-tempo tempo-inicial valor-resultado) (minimax-min (cdr jogadas) profundidade-max peca alfa novo-beta nos-analisados-resultado cortes-alfa-resultado novo-cortes-beta limite-tempo tempo-inicial valor)) ) ) ) ) ) ) ``` Como explicado na descrição do TAD Resultado, este algoritmo, devolverá uma lista da forma: ``` <Resultado-Alfabeta> ::= ( {<Valor>} {<Nos-Analisados>} {<Cortes-Alfa>} {<Cortes-Beta>} ) ``` ## **5. Descrição das opções tomadas** Serve o presente capítulo para descrição e justificação de determinadas opções tomadas ao longo do projeto, no que toca à sua arquitetura, execução, entre outros. ### **5.1 Escolha da Função de Avaliação** Uma das componentes de elevada importância na execução do AlfaBeta, é a escolha de uma função de avaliação que permita quantificar determinado estado. Para tal, procedemos à implementação de uma função `no-avaliacao`, responsável por devolver um valor quantitativo, no intervalo -inf e +inf, com o qual o *alfabeta* irá operar Para tal, pensámos em avaliar o estado com base na seguinte operação: (PontosJogador1 - PontosJogador2) + (PróximosPontosJ1 - PróximosPontosJ2) * Multiplicador Tal, consiste no seguinte princípio teórico: É vista a diferença dos pontos entre jogadores, e somada aos pontos possíveis destes nas posições em seu redor. Nisto, é ainda multiplicado o valor 1 ou -1, consoante o jogador min ou max que estiver a jogar. ``` (defun no-avaliacao (no jogador maximo) ;pontos max - pontos min + todos ao pe do max - todos ao pe do min "identifica qual o valor heuristico do nó terminal para o jogador" (let* ( (pontos-jogador1 (estado-pontos-jogador no jogador)) (pontos-jogador2 (estado-pontos-jogador no (trocar-peca jogador))) (maximo-multiplicador (if maximo 1 -1)) ; serve para caso seja o minimo a vencer, inverte o sinal (proximos-pontos-jogador1 (pontos-possiveis-jogador no jogador) ) (proximos-pontos-jogador2 (pontos-possiveis-jogador no (trocar-peca jogador)) ) ) (* (+ (- pontos-jogador1 pontos-jogador2) (- proximos-pontos-jogador1 proximos-pontos-jogador2) ) maximo-multiplicador ) ) ) ``` ### **5.2 Procura Quiescente** Outra das necessidades de otimização do projeto, prende-se com a aplicação do conceito de procura quiescente. Esta, define-se pela aplicação da função de avaliação a posições com baixa probabilidade de terem variações bruscas no valor de f. Tal foi aplicado modificando a função de avaliação, explorando um nó abaixo do proposto, de forma a atestar a veracidade do valor em causa. Desta forma, modificámos a avaliação do nó terminal, de forma a permitir o cálculo da média entre o valor atual do nó, e o valor do melhor sucessor, obtendo uma precisão apurada do valor em causa. ``` (defun no-avalicao-terminal (no jogador maximo) (let ( (avaliacao (no-avaliacao no jogador maximo)) (jogadas (jogadas no jogador)) ) (cond ((null jogadas) avaliacao) (T (let* ( (valor-melhor-sucessor (melhor-jogada jogador maximo jogadas)) ) (/ (+ valor-melhor-sucessor avaliacao) 2) ) ) ) ) ) ``` ### **5.3 Memoização** Um dos importantes conceitos a ser utilizados neste tipo de algoritmos, é a existência de uma tabela hash, responsável pelo armazenamento de resultados de determinados estados, facilitanto assim o cálculo imediato destes sem que os seus sucessores tenham de ser gerados. Para tal, foi efetuada a memoização, onde optámos por recorrer à criação de uma tabela hash, responsável pelo armazenamento destes dados através do conceito de *closure*. Posto isto, aquando da execução do alfabeta, é chamada a função alfabeta-memo, que verifica se o valor para este estado já foi calculado previamente. ``` (let ( (tabela (make-hash-table)) ) (defun alfabeta-memo (no &rest argumentos) (or (gethash no tabela) (let ((val (apply #'alfabeta (cons no argumentos)))) (setf (gethash no tabela) val) val)) ) ) ``` ### **5.4 Ordenação dos nós** Em termos de eficiência, a ordenação dos nós mostrou-se como o principal fator de eficiência. Com esta implementação foi de notável observação, para um mesmo estado inicial, o aumento de número de cortes realizados em todas as jogadas. Esta consistiu na ordenação dos nós intermédios segundo o seu valor heurístico. Ou seja, sempre que se gera novas jogadas, a partir de uma outra, estas jogadas são ordenadas de acordo com o tipo de nó em que estão (max ou min). De seguida observa-se como foi implementado a ordenação dos nós intermédios da árvore de jogo. ``` ;; Odenação dos nós ; função que avalia o nó intermédio (defun no-avaliacao-intermedio (no jogador maximo) "Funcao de avaliação de nos intermedios" (no-avaliacao no jogador maximo) ) ; max -> de forma decrescente ; min -> crescente ; funcao auxiliar que ordena nos de acordo com o seu valor associado (defun ordenar-nos-com-valores (nos maximo) "ordena os nos de acordo com o seu valor associado, dependendo se é max ou min" (cond (maximo (sort nos #'(lambda (x y) (> (first x) (first y))))) (T (sort nos #'(lambda (x y) (< (first x) (first y))))) ) ) ;; Ordenar os nós intermediários (defun ordenar-nos-intermedios (nos jogador maximo) "Ordena os nos intermedios recebidos" (cond ((null nos) nil) (T (let* ( (valores-com-nos (mapcar #'(lambda (no) (cons (no-avaliacao-intermedio no jogador maximo) no) ) nos )) (ordenados-com-valor (ordenar-nos-com-valores valores-com-nos maximo)) (nos-ordenados (mapcar #'(lambda (no) (cdr no)) ordenados-com-valor )) ) nos-ordenados )) ) ) ``` E aqui é como é utilizado esta ordenação: ``` (jogadas (ordenar-nos-intermedios (remove nil (mapcar #'(lambda (operador) (funcall operador no peca) ) (operadores) )) peca maximo )) ``` ### **5.5 Movimento** Para cumprir a condição de verificação de peça ameaçada, foi necessário alterar a abordagem de movimento do programa. Para tal, os operadores foram sub-divididos, existindo uma função responsável pela chamada do movimento dos diferentes operadores: ``` (defun movimento-operador (operador estado peca) (cond ( (equal operador 'operador-1 ) (let* ( (tabuleiro (estado-tabuleiro estado)) (posicao (posicao-numero peca tabuleiro)) (linha-cavalo (first posicao)) (coluna-cavalo (second posicao)) (movimento-tabuleiro (substituir linha-cavalo coluna-cavalo estado )) (nova-linha (+ 2 linha-cavalo) ) (nova-coluna (1- coluna-cavalo)) (novo-estado (substituir nova-linha nova-coluna movimento-tabuleiro peca)) ) (list novo-estado nova-linha nova-coluna) ) ) ( (equal operador 'operador-2) (let* ( (tabuleiro (estado-tabuleiro estado)) (posicao (posicao-numero peca tabuleiro)) (linha-cavalo (first posicao)) (coluna-cavalo (second posicao)) (movimento-tabuleiro (substituir linha-cavalo coluna-cavalo estado)) (nova-linha (+ 2 linha-cavalo) ) (nova-coluna (1+ coluna-cavalo)) (novo-estado (substituir nova-linha nova-coluna movimento-tabuleiro peca)) ) (list novo-estado nova-linha nova-coluna) ) ) ((equal operador 'operador-3) (let* ( (tabuleiro (estado-tabuleiro estado)) (posicao (posicao-numero peca tabuleiro)) (linha-cavalo (first posicao)) (coluna-cavalo (second posicao)) (movimento-tabuleiro (substituir linha-cavalo coluna-cavalo estado)) (nova-linha (1+ linha-cavalo) ) (nova-coluna (+ 2 coluna-cavalo)) (novo-estado (substituir nova-linha nova-coluna movimento-tabuleiro peca )) ) (list novo-estado nova-linha nova-coluna) ) ) ((equal operador 'operador-4) (let* ( (tabuleiro (estado-tabuleiro estado)) (posicao (posicao-numero peca tabuleiro)) (linha-cavalo (first posicao)) (coluna-cavalo (second posicao)) (movimento-tabuleiro (substituir linha-cavalo coluna-cavalo estado)) (nova-linha (1- linha-cavalo) ) (nova-coluna (+ 2 coluna-cavalo)) (novo-estado (substituir nova-linha nova-coluna movimento-tabuleiro peca )) ) (list novo-estado nova-linha nova-coluna) ) ) ((equal operador 'operador-5) (let* ( (tabuleiro (estado-tabuleiro estado)) (posicao (posicao-numero peca tabuleiro)) (linha-cavalo (first posicao)) (coluna-cavalo (second posicao)) (movimento-tabuleiro (substituir linha-cavalo coluna-cavalo estado)) (nova-linha (- linha-cavalo 2) ) (nova-coluna (1+ coluna-cavalo)) (novo-estado (substituir nova-linha nova-coluna movimento-tabuleiro peca )) ) (list novo-estado nova-linha nova-coluna) ) ) ((equal operador 'operador-6) (let* ( (tabuleiro (estado-tabuleiro estado)) (posicao (posicao-numero peca tabuleiro)) (linha-cavalo (first posicao)) (coluna-cavalo (second posicao)) (movimento-tabuleiro (substituir linha-cavalo coluna-cavalo estado)) (nova-linha (- linha-cavalo 2) ) (nova-coluna (1- coluna-cavalo)) (novo-estado (substituir nova-linha nova-coluna movimento-tabuleiro peca )) ) (list novo-estado nova-linha nova-coluna) ) ) ((equal operador 'operador-7) (let* ( (tabuleiro (estado-tabuleiro estado)) (posicao (posicao-numero peca tabuleiro)) (linha-cavalo (first posicao)) (coluna-cavalo (second posicao)) (movimento-tabuleiro (substituir linha-cavalo coluna-cavalo estado)) (nova-linha (1- linha-cavalo) ) (nova-coluna (- coluna-cavalo 2)) (novo-estado (substituir nova-linha nova-coluna movimento-tabuleiro peca )) ) (list novo-estado nova-linha nova-coluna) ) ) ( (equal operador 'operador-8 ) (let* ( (tabuleiro (estado-tabuleiro estado)) (posicao (posicao-numero peca tabuleiro)) (linha-cavalo (first posicao)) (coluna-cavalo (second posicao)) (movimento-tabuleiro (substituir linha-cavalo coluna-cavalo estado)) (nova-linha (+ 1 linha-cavalo) ) (nova-coluna (- coluna-cavalo 2)) (novo-estado (substituir nova-linha nova-coluna movimento-tabuleiro peca )) ) (list novo-estado nova-linha nova-coluna) ) ) ) ) ``` ### **5.5 Execução da Medição do Tempo dentro do alfabeta** Foi inicialmente definido um limite temporal a ser estabelecido para a jogada do computador. Para que existisse sempre a devolução de um valor proveniente da execução do algoritmo alfabeta, foi necessário proceder à contagem deste tempo no interior da função, ao contrário do que vinha a ser feito durante a fase 1 do projeto, estando tal implementado da seguinte forma: ``` (defun alfabeta (no profundidade-max peca **limite-tempo** &optional (maximo T) (alfa most-negative-fixnum) (beta most-positive-fixnum) (nos-analisados 0) (cortes-alfa 0) (cortes-beta 0) (tempo-inicial (get-internal-real-time)) &aux (tempo-atual (get-internal-real-time)) (tempo-execucao ( - tempo-atual tempo-inicial ))) (cond ( (or (= profundidade-max 0) (no-terminalp no peca) (> **tempo-execucao limite-tempo**) ) (list (no-avaliacao no peca maximo) (1+ nos-analisados) cortes-alfa cortes-beta) (...) ``` ### **5.6 Duplo ou Simétrico é responsável por devolver o estado** Através da análise do código de cada operador, percebemos que o retorno do novo estado final do tabuleiro não é realizado pelo mesmo, sendo que a sua última instrução se refere a uma chamada à função `duplo-ou-simétrico`. No que toca à arquitetura destas funções, percebemos que faria todo o sentido ser esta a responsável pelo processamento do novo estado, visto que seria após a execução da mesma e das possíveis condições de duplo ou simétrico, que o tabuleiro final poderia ser devolvido e utilizado posteriormente no nó. Desta forma, a função `duplo-ou-simétrico` possui a seguinte estrutura: ``` (defun duplo-ou-simetrico (numero estado) "verifique se é duplo ou simetrico" (cond ((null numero) nil) (T (let*( (novoestado (list (- (estado-pontos estado) numero) (estado-tabuleiro estado)))) (cond ( (digitos-iguais-p numero) (duplo novoestado) ) ; se duplo (T (simetrico numero novoestado)) ;simetrico ) )) ) ) ``` ## **6. Limitações técnicas e ideias para desenvolvimento futuro** Efetuando um balanço final do projeto realizado, concluímos ter conseguido dar por executados todos os requisitos propostos, não só a nível funcional, mas inclusive na qualidade e estruturação de código, assumindo aquelas que são as boas práticas do Common LISP, recorrendo aos conceitos e estrutura do paradigma da programação funcional. Apesar disto, conseguimos detetar algumas possíveis melhorias a executar numa solução futura, prendendo-se as mesmas com os pontos seguintes: #### Interface com utilizador Para utilização da aplicação pelo utilizador comum, consideramos que o uso da atual interface LISP não se apresenta como acessível. Desta forma, entendemos que numa fase posterior do projeto, poderia ser interessante a construção de uma interface do utilizador. Para realizar tal funcionalidade, uma das possibilidades seria a utilização da solução [gtk+](https://www.gtk.org/), um projeto *open-source*, especializado na construção de elementos UI e compatível com a linguagem LISP. #### Refactoring de Código No atual projeto, reconhecemos a existência de determinado formulamento de código que pode não estar realizado da forma mais correta. Por exemplo, através utilização do conceito *negamax*, poderíamos reduzir a repetição de código no algoritmo minimax com cortes alfabeta, levando a um código consideravelmente mais legível. #### Utilização de uma superior quantidade de memória Apesar da resolução de grande parte dos problemas propostos, consideramos que se ultrapassássemos a limitação do *Lispworks Personal Edition* em relação à memória utilizada para contextos de *stack*, poderia ser possível verificar a eficácia dos algoritmos em problemas de maior extensão. Desta forma, em futuras versões do projeto, sentimos a necessidade de utilização de uma ferramenta que permita o uso de uma quantidade de memória superior. ## **7. Exemplo de aplicação** Como se pode observar abaixo, é realizado um jogo entre um utilizador humano e a máquina. O primeiro jogador é o humano, com um tempo máximo de jogada para a máquina de 5 segundos. Em termos de dificuldade, a máquina possui um limite máximo de horizonte de profundidade 6. ``` ___ |_ | | | ___ __ _ ___ | |/ _ \ / _` |/ _ \ /\__/ / (_) | (_| | (_) | \____/ \___/ \__, |\___/ __/ | |___/ _ _ | | | | __| | ___ ___ __ ___ ____ __| | ___ / _` |/ _ \ / __/ _` |\ \ / / _` | |/ _ \ | (_| | (_) | | (_| (_| | \ V / (_| | | (_) | \__,_|\___/ \___\__,_| \_/ \__,_|_|\___/ Escolha um jogo: 1 - Humano vs Computador 2 - Computador vs Computador 1 Escolha o primeiro a jogar: 1 - Humano 2 - Computador 1 Escolha o tempo limite para o computador jogar, entre 1000 a 5000 milissegundos: 5000 Tabuleiro inicial: |59|43|77|0 |10|45|2 |33|89|93| |21|47|92|38|69|14|95|61|37|76| |22|29|1 |27|65|54|58|8 |32|51| |44|19|25|42|13|4 |15|52|5 |16| |31|40|60|67|7 |73|90|68|82|18| |63|6 |23|41|56|85|9 |35|94|66| |26|53|12|30|46|78|87|34|17|48| |71|75|11|64|24|57|99|39|81|98| |96|74|49|72|79|86|50|88|70|91| |28|36|83|80|3 |55|62|20|84|97| ------------------------------- |59|43|77|0 |10|45|2 |33|89|-1| |21|47|92|38|69|14|95|61|37|76| |22|29|1 |27|65|54|58|8 |32|51| |44|19|25|42|13|4 |15|52|5 |16| |31|40|60|67|7 |73|90|68|82|18| |63|6 |23|41|56|85|9 |35|94|66| |26|53|12|30|46|78|87|34|17|48| |71|75|11|64|24|57|99| |81|98| |96|74|49|72| |86|50|88|70|91| |28|36|83|80|3 |55|62|20|84|-2| Turno do JOGADOR1 Pontos do jogador 1 : 93 pontos Pontos do jogador 2 : 97 pontos Indique a linha a selecionar De 1 a 10 2 Indique a coluna a selecionar De 1 a 10 8 |59|43|77|0 |10|45|2 |33|89| | |21|47|92|38|69|14|95|-1|37|76| |22|29|1 |27|65|54|58|8 |32|51| |44|19|25|42|13|4 |15|52|5 | | |31|40|60|67|7 |73|90|68|82|18| |63|6 |23|41|56|85|9 |35|94|66| |26|53|12|30|46|78|87|34|17|48| |71|75|11|64|24|57|99| |81|98| |96|74|49|72| |86|50|88|70|91| |28|36|83|80|3 |55|62|20|84|-2| Turno do JOGADOR2 Pontos do jogador 1 : 154 pontos Pontos do jogador 2 : 97 pontos Nos analisados: 450 Cortes alfa: 52 Cortes beta: 96 Tempo de execucao: 1.895 |59|43|77|0 |10|45|2 |33|89| | |21|47|92|38|69|14|95|-1|37|76| |22|29|1 |27|65|54|58|8 |32|51| |44|19|25|42|13|4 |15|52|5 | | |31|40|60|67|7 |73|90|68|82|18| |63|6 |23|41|56|85|9 |35|94|66| |26|53|12|30|46|78|87|34|17|48| |71|75|11|64|24|57| | |81|98| |96|74|49|72| |86|50|-2|70|91| |28|36|83|80|3 |55|62|20|84| | Turno do JOGADOR1 Pontos do jogador 1 : 154 pontos Pontos do jogador 2 : 185 pontos Indique a linha a selecionar De 1 a 10 3 Indique a coluna a selecionar De 1 a 10 6 |59|43|77|0 |10| |2 |33|89| | |21|47|92|38|69|14|95| |37|76| |22|29|1 |27|65|-1|58|8 |32|51| |44|19|25|42|13|4 |15|52|5 | | |31|40|60|67|7 |73|90|68|82|18| |63|6 |23|41|56|85|9 |35|94|66| |26|53|12|30|46|78|87|34|17|48| |71|75|11|64|24|57| | |81|98| |96|74|49|72| |86|50|-2|70|91| |28|36|83|80|3 |55|62|20|84| | Turno do JOGADOR2 Pontos do jogador 1 : 208 pontos Pontos do jogador 2 : 185 pontos Nos analisados: 529 Cortes alfa: 60 Cortes beta: 139 Tempo de execucao: 1.99 |59|43|77|0 |10| |2 |33|89| | |21|47|92|38|69|14|95| |37|76| |22|29|1 |27|65|-1|58|8 |32|51| |44|19|25|42|13|4 |15|52|5 | | |31|40|60|67|7 |73|90|68|82|18| |63|6 |23|41|56|85|9 |35|94|66| |26|53|12|30|46| |-2|34|17|48| |71|75|11|64|24|57| | |81|98| |96|74|49|72| |86|50| |70|91| |28|36|83|80|3 |55|62|20|84| | Turno do JOGADOR1 Pontos do jogador 1 : 208 pontos Pontos do jogador 2 : 272 pontos Indique a linha a selecionar De 1 a 10 5 Indique a coluna a selecionar De 1 a 10 7 |59|43|77|0 |10| |2 |33|89| | |21|47|92|38|69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|13|4 |15|52|5 | | |31|40|60|67|7 |73|-1|68|82|18| |63|6 |23|41|56|85| |35|94|66| |26|53|12|30|46| |-2|34|17|48| |71|75|11|64|24|57| | |81|98| |96|74|49|72| |86|50| |70|91| |28|36|83|80|3 |55|62|20|84| | Turno do JOGADOR2 Pontos do jogador 1 : 298 pontos Pontos do jogador 2 : 272 pontos Nos analisados: 1623 Cortes alfa: 223 Cortes beta: 349 Tempo de execucao: 5.021 |59|43|77|0 |10| |2 |33|89| | |21|47|92|38|69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|13|4 |15|52|5 | | |31|40|60|67|7 |73|-1| |82|18| |63|6 |23|41|56|85| |35|94|66| |26|53|12|30|46| | |34|17|48| |71|75|11|64|24|57| | |81|98| |96|74|49|72| |-2|50| |70|91| |28|36|83|80|3 |55|62|20|84| | Turno do JOGADOR1 Pontos do jogador 1 : 298 pontos Pontos do jogador 2 : 358 pontos Indique a linha a selecionar De 1 a 10 6 Indique a coluna a selecionar De 1 a 10 9 |59|43|77|0 |10| |2 |33|89| | |21|47|92|38|69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|13|4 |15|52|5 | | |31|40|60|67|7 |73| | |82|18| |63|6 |23|41|56|85| |35|-1|66| |26|53|12|30|46| | |34|17|48| |71|75|11|64|24|57| | |81|98| |96|74| |72| |-2|50| |70|91| |28|36|83|80|3 |55|62|20|84| | Turno do JOGADOR2 Pontos do jogador 1 : 392 pontos Pontos do jogador 2 : 358 pontos Nos analisados: 112 Cortes alfa: 12 Cortes beta: 74 Tempo de execucao: 0.509 |59|43|77|0 |10| |2 |33|89| | |21|47|92|38|69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|13|4 |15|52|5 | | |31|40|60|67|7 |73| | |82|18| |63|6 |23|41|56|85| |35|-1|66| |26|53|12|30| | | |34|17|48| |71|75|11|-2|24|57| | |81|98| |96|74| |72| | |50| |70|91| |28|36|83|80|3 |55|62|20|84| | Turno do JOGADOR1 Pontos do jogador 1 : 392 pontos Pontos do jogador 2 : 422 pontos Indique a linha a selecionar De 1 a 10 8 Indique a coluna a selecionar De 1 a 10 10 |59|43|77|0 |10| |2 |33| | | |21|47|92|38|69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|13|4 |15|52|5 | | |31|40|60|67|7 |73| | |82|18| |63|6 |23|41|56|85| |35| |66| |26|53|12|30| | | |34|17|48| |71|75|11|-2|24|57| | |81|-1| |96|74| |72| | |50| |70|91| |28|36|83|80|3 |55|62|20|84| | Turno do JOGADOR2 Pontos do jogador 1 : 490 pontos Pontos do jogador 2 : 422 pontos Nos analisados: 472 Cortes alfa: 26 Cortes beta: 240 Tempo de execucao: 1.451 |59|43|77|0 |10| |2 |33| | | |21|47|92| |69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|13|4 |15|52|5 | | |31|40|60|67|7 |73| | |82|18| |63|6 |23|41|56|85| |35| |66| |26|53|12|30| | | |34|17|48| |71|75|11| |24|57| | |81|-1| |96|74| |72| | |50| |70|91| |28|36|-2|80|3 |55|62|20|84| | Turno do JOGADOR1 Pontos do jogador 1 : 490 pontos Pontos do jogador 2 : 505 pontos Indique a linha a selecionar De 1 a 10 10 Indique a coluna a selecionar De 1 a 10 9 |59|43|77|0 |10| |2 |33| | | |21|47|92| |69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|13|4 |15|52|5 | | |31|40|60|67|7 |73| | |82|18| |63|6 |23|41|56|85| |35| |66| |26|53|12|30| | | |34|17| | |71|75|11| |24|57| | |81| | |96|74| |72| | |50| |70|91| |28|36|-2|80|3 |55|62|20|-1| | Turno do JOGADOR2 Pontos do jogador 1 : 574 pontos Pontos do jogador 2 : 505 pontos Nos analisados: 76 Cortes alfa: 5 Cortes beta: 28 Tempo de execucao: 0.246 |59|43|77|0 |10| |2 |33| | | |21|47|92| |69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|13|4 |15|52|5 | | |31|40|60|67|7 |73| | |82|18| |63|6 |23|41|56|85| |35| |66| |26|53|12|30| | | |34|17| | |71|-2|11| |24| | | |81| | |96|74| |72| | |50| |70|91| |28|36| |80|3 |55|62|20|-1| | Turno do JOGADOR1 Pontos do jogador 1 : 574 pontos Pontos do jogador 2 : 580 pontos Indique a linha a selecionar De 1 a 10 9 Indique a coluna a selecionar De 1 a 10 7 |59|43|77|0 |10| |2 |33| | | |21|47|92| |69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|13|4 |15|52| | | |31|40|60|67|7 |73| | |82|18| |63|6 |23|41|56|85| |35| |66| |26|53|12|30| | | |34|17| | |71|-2|11| |24| | | |81| | |96|74| |72| | |-1| |70|91| |28|36| |80|3 |55|62|20| | | Turno do JOGADOR2 Pontos do jogador 1 : 624 pontos Pontos do jogador 2 : 580 pontos Nos analisados: 296 Cortes alfa: 34 Cortes beta: 107 Tempo de execucao: 0.907 |59|43|77|0 |10| |2 |33| | | |21|47|92| |69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|13|4 |15|52| | | |31|40|60|67|7 |73| | |82|18| |-2|6 |23|41|56|85| |35| |66| |26|53|12|30| | | |34|17| | |71| |11| |24| | | |81| | |96|74| |72| | |-1| |70|91| |28| | |80|3 |55|62|20| | | Turno do JOGADOR1 Pontos do jogador 1 : 624 pontos Pontos do jogador 2 : 643 pontos Indique a linha a selecionar De 1 a 10 8 Indique a coluna a selecionar De 1 a 10 9 |59|43|77|0 |10| |2 |33| | | |21|47|92| |69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|13|4 |15|52| | | |31|40|60|67|7 |73| | |82| | |-2|6 |23|41|56|85| |35| |66| |26|53|12|30| | | |34|17| | |71| |11| |24| | | |-1| | |96|74| |72| | | | |70|91| |28| | |80|3 |55|62|20| | | Turno do JOGADOR2 Pontos do jogador 1 : 705 pontos Pontos do jogador 2 : 643 pontos Nos analisados: 103 Cortes alfa: 12 Cortes beta: 65 Tempo de execucao: 0.342 |59|43|77|0 |10| |2 |33| | | |21|47|92| |69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|13|4 |15|52| | | |31|40|-2|67|7 |73| | |82| | | | |23|41|56|85| |35| |66| |26|53|12|30| | | |34|17| | |71| |11| |24| | | |-1| | |96|74| |72| | | | |70|91| |28| | |80|3 |55|62|20| | | Turno do JOGADOR1 Pontos do jogador 1 : 705 pontos Pontos do jogador 2 : 703 pontos Indique a linha a selecionar De 1 a 10 6 Indique a coluna a selecionar De 1 a 10 10 |59|43| |0 |10| |2 |33| | | |21|47|92| |69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|13|4 |15|52| | | |31|40|-2|67|7 |73| | |82| | | | |23|41|56|85| |35| |-1| |26|53|12|30| | | |34|17| | |71| |11| |24| | | | | | |96|74| |72| | | | |70|91| |28| | |80|3 |55|62|20| | | Turno do JOGADOR2 Pontos do jogador 1 : 771 pontos Pontos do jogador 2 : 703 pontos Nos analisados: 87 Cortes alfa: 3 Cortes beta: 98 Tempo de execucao: 0.296 |59|43| |0 |10| |2 |33| | | |21|47|92| |69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|-2|4 |15|52| | | | |40| |67|7 |73| | |82| | | | |23|41|56|85| |35| |-1| |26|53|12|30| | | |34|17| | |71| |11| |24| | | | | | |96|74| |72| | | | |70|91| |28| | |80|3 |55|62|20| | | Turno do JOGADOR1 Pontos do jogador 1 : 771 pontos Pontos do jogador 2 : 716 pontos Indique a linha a selecionar De 1 a 10 7 Indique a coluna a selecionar De 1 a 10 8 |59| | |0 |10| |2 |33| | | |21|47|92| |69|14|95| |37|76| |22|29|1 |27|65| |58|8 |32|51| |44|19|25|42|-2|4 |15|52| | | | |40| |67|7 |73| | |82| | | | |23|41|56|85| |35| | | |26|53|12|30| | | |-1|17| | |71| |11| |24| | | | | | |96|74| |72| | | | |70|91| |28| | |80|3 |55|62|20| | | Turno do JOGADOR2 Pontos do jogador 1 : 805 pontos Pontos do jogador 2 : 716 pontos Nos analisados: 49 Cortes alfa: 4 Cortes beta: 58 Tempo de execucao: 0.209 |59| | |0 |10| |2 |33| | | |21|47|92| |69|14|95| |37|76| |22|29|1 |27|65| |-2|8 |32|51| |44|19|25|42| |4 |15|52| | | | |40| |67|7 |73| | |82| | | | |23|41|56| | |35| | | |26|53|12|30| | | |-1|17| | |71| |11| |24| | | | | | |96|74| |72| | | | |70|91| |28| | |80|3 |55|62|20| | | Turno do JOGADOR1 Pontos do jogador 1 : 805 pontos Pontos do jogador 2 : 774 pontos Indique a linha a selecionar De 1 a 10 5 Indique a coluna a selecionar De 1 a 10 9 |59| | |0 |10| |2 |33| | | |21|47|92| |69|14|95| |37|76| |22|29|1 |27|65| |-2|8 |32|51| |44|19|25|42| |4 |15|52| | | | |40| |67|7 |73| | |-1| | | | |23|41|56| | |35| | | |26|53|12|30| | | | |17| | |71| |11| |24| | | | | | |96|74| |72| | | | |70|91| | | | |80|3 |55|62|20| | | Turno do JOGADOR2 Pontos do jogador 1 : 887 pontos Pontos do jogador 2 : 774 pontos Nos analisados: 71 Cortes alfa: 14 Cortes beta: 33 Tempo de execucao: 0.219 |59| | |0 |10| |2 |33| | | |21|47|92| |69|14|95| | |76| |22|29|1 |27|65| | |8 |32|51| |44|19|25|42| |4 |15|52| | | | |40| |67|7 |-2| | |-1| | | | |23|41|56| | |35| | | |26|53|12|30| | | | |17| | |71| |11| |24| | | | | | |96|74| |72| | | | |70|91| | | | |80|3 |55|62|20| | | Turno do JOGADOR1 Pontos do jogador 1 : 887 pontos Pontos do jogador 2 : 847 pontos Indique a linha a selecionar De 1 a 10 3 Indique a coluna a selecionar De 1 a 10 10 |59| | |0 |10| |2 |33| | | |21|47|92| |69|14|95| | |76| |22|29|1 |27|65| | |8 |32|-1| |44|19|25|42| |4 | |52| | | | |40| |67|7 |-2| | | | | | | |23|41|56| | |35| | | |26|53|12|30| | | | |17| | |71| |11| |24| | | | | | |96|74| |72| | | | |70|91| | | | |80|3 |55|62|20| | | Turno do JOGADOR2 Pontos do jogador 1 : 938 pontos Pontos do jogador 2 : 847 pontos Nos analisados: 45 Cortes alfa: 0 Cortes beta: 41 Tempo de execucao: 0.101 |59| | |0 |10| |2 |33| | | |21|47|92| |69|14|95| | |76| |22|29|1 |27|-2| | |8 |32|-1| |44|19|25|42| |4 | |52| | | | |40| |67|7 | | | | | | | | |23|41| | | |35| | | |26|53|12|30| | | | |17| | |71| |11| |24| | | | | | |96|74| |72| | | | |70|91| | | | |80|3 |55|62|20| | | Turno do JOGADOR1 Pontos do jogador 1 : 938 pontos Pontos do jogador 2 : 912 pontos Indique a linha a selecionar De 1 a 10 4 Indique a coluna a selecionar De 1 a 10 8 |59| | |0 |10| |2 |33| | | |21|47|92| |69|14|95| | |76| |22|29|1 |27|-2| | |8 |32| | |44|19| |42| |4 | |-1| | | | |40| |67|7 | | | | | | | | |23|41| | | |35| | | |26|53|12|30| | | | |17| | |71| |11| |24| | | | | | |96|74| |72| | | | |70|91| | | | |80|3 |55|62|20| | | Turno do JOGADOR2 Pontos do jogador 1 : 990 pontos Pontos do jogador 2 : 912 pontos Nos analisados: 31 Cortes alfa: 3 Cortes beta: 26 Tempo de execucao: 0.071 |59| | |0 |10| |2 |33| | | |21|47|92| |69|14|95| | | | |22|29|1 |27| | | |8 |32| | |44|19| |42| |4 | |-1| | | | |40| |-2|7 | | | | | | | | |23|41| | | |35| | | |26|53|12|30| | | | |17| | |71| |11| |24| | | | | | |96|74| |72| | | | |70|91| | | | |80|3 |55|62|20| | | Turno do JOGADOR1 Pontos do jogador 1 : 990 pontos Pontos do jogador 2 : 979 pontos Indique a linha a selecionar De 1 a 10 2 Indique a coluna a selecionar De 1 a 10 7 | | | |0 |10| |2 |33| | | |21|47|92| |69|14|-1| | | | |22|29|1 |27| | | |8 |32| | |44|19| |42| |4 | | | | | | |40| |-2|7 | | | | | | | | |23|41| | | |35| | | |26|53|12|30| | | | |17| | |71| |11| |24| | | | | | |96|74| |72| | | | |70|91| | | | |80|3 |55|62|20| | | Turno do JOGADOR2 Pontos do jogador 1 : 1085 pontos Pontos do jogador 2 : 979 pontos Nos analisados: 38 Cortes alfa: 5 Cortes beta: 28 Tempo de execucao: 0.074 | | | |0 |10| |2 |33| | | | |47|92| |69|14|-1| | | | |22|29|1 |27| | | |8 |32| | |44|19| |42| |4 | | | | | | |40| | |7 | | | | | | | | |23|41| | | |35| | | |26|53|-2|30| | | | |17| | |71| |11| |24| | | | | | |96|74| |72| | | | |70|91| | | | |80|3 |55|62|20| | | Turno do JOGADOR1 Pontos do jogador 1 : 1085 pontos Pontos do jogador 2 : 991 pontos Indique a linha a selecionar De 1 a 10 3 Indique a coluna a selecionar De 1 a 10 9 | | | |0 |10| |2 |33| | | | |47|92| |69|14| | | | | |22|29|1 |27| | | |8 |-1| | |44|19| |42| |4 | | | | | | |40| | |7 | | | | | | | | | |41| | | |35| | | |26|53|-2|30| | | | |17| | |71| |11| |24| | | | | | |96|74| |72| | | | |70|91| | | | |80|3 |55|62|20| | | Turno do JOGADOR2 Pontos do jogador 1 : 1117 pontos Pontos do jogador 2 : 991 pontos Nos analisados: 21 Cortes alfa: 0 Cortes beta: 19 Tempo de execucao: 0.045 | | | |0 |10| |2 |33| | | | | |92| |69|14| | | | | |22|29|1 |27| | | |8 |-1| | |44|19| |42| |4 | | | | | | |40| | |7 | | | | | | | | | |41| | | |35| | | |26|53| |30| | | | |17| | |71| |11| |24| | | | | | |96|-2| |72| | | | |70|91| | | | |80|3 |55|62|20| | | Turno do JOGADOR1 Pontos do jogador 1 : 1117 pontos Pontos do jogador 2 : 1065 pontos Indique a linha a selecionar De 1 a 10 1 Indique a coluna a selecionar De 1 a 10 8 | | | |0 |10| |2 |-1| | | | | |92| |69|14| | | | | |22|29|1 |27| | | |8 | | | |44|19| |42| |4 | | | | | | |40| | |7 | | | | | | | | | |41| | | |35| | | |26|53| |30| | | | |17| | |71| |11| |24| | | | | | |96|-2| |72| | | | |70|91| | | | |80|3 | |62|20| | | Turno do JOGADOR2 Pontos do jogador 1 : 1150 pontos Pontos do jogador 2 : 1065 pontos Nos analisados: 18 Cortes alfa: 3 Cortes beta: 7 Tempo de execucao: 0.029 | | | |0 |10| |2 |-1| | | | | |92| |69|14| | | | | |22|29|1 |27| | | |8 | | | |44|19| |42| |4 | | | | | | |40| | |7 | | | | | | | | | |41| | | |35| | | |-2|53| |30| | | | |17| | |71| |11| |24| | | | | | |96| | |72| | | | |70|91| | | | |80|3 | | |20| | | Turno do JOGADOR1 Pontos do jogador 1 : 1150 pontos Pontos do jogador 2 : 1091 pontos Indique a linha a selecionar De 1 a 10 2 Indique a coluna a selecionar De 1 a 10 6 | | | |0 |10| |2 | | | | | | |92| |69|-1| | | | | |22|29|1 |27| | | |8 | | | |44|19| |42| |4 | | | | | | |40| | |7 | | | | | | | | | | | | | |35| | | |-2|53| |30| | | | |17| | |71| |11| |24| | | | | | |96| | |72| | | | |70|91| | | | |80|3 | | |20| | | Turno do JOGADOR2 Pontos do jogador 1 : 1164 pontos Pontos do jogador 2 : 1091 pontos Nos analisados: 19 Cortes alfa: 12 Cortes beta: 8 Tempo de execucao: 0.035 | | | |0 |10| |2 | | | | | | |92| |69|-1| | | | | |22|29|1 |27| | | |8 | | | |44|19| |42| | | | | | | | |-2| | |7 | | | | | | | | | | | | | |35| | | | |53| |30| | | | |17| | |71| |11| |24| | | | | | |96| | |72| | | | |70|91| | | | |80|3 | | |20| | | Turno do JOGADOR1 Pontos do jogador 1 : 1164 pontos Pontos do jogador 2 : 1131 pontos Indique a linha a selecionar De 1 a 10 3 Indique a coluna a selecionar De 1 a 10 8 | | | |0 |10| |2 | | | | | | |92| |69| | | | | | |22|29|1 |27| | | |-1| | | |44|19| |42| | | | | | | | |-2| | |7 | | | | | | | | | | | | | |35| | | | |53| |30| | | | |17| | |71| |11| |24| | | | | | |96| | |72| | | | |70|91| | | | | |3 | | |20| | | Turno do JOGADOR2 Pontos do jogador 1 : 1172 pontos Pontos do jogador 2 : 1131 pontos Nos analisados: 8 Cortes alfa: 0 Cortes beta: 9 Tempo de execucao: 0.016 | | | |0 |10| |2 | | | | | | |92| |69| | | | | | |22|29|1 |27| | | |-1| | | |44|19| |-2| | | | | | | | | | | |7 | | | | | | | | | | | | | |35| | | | |53| |30| | | | |17| | |71| |11| | | | | | | | |96| | |72| | | | |70|91| | | | | |3 | | |20| | | Turno do JOGADOR1 Pontos do jogador 1 : 1172 pontos Pontos do jogador 2 : 1173 pontos Indique a linha a selecionar De 1 a 10 1 Indique a coluna a selecionar De 1 a 10 7 | | | |0 |10| |-1| | | | | | |92| |69| | | | | | |22|29|1 |27| | | | | | | |44|19| |-2| | | | | | | | | | | |7 | | | | | | | | | | | | | |35| | | | |53| |30| | | | |17| | |71| |11| | | | | | | | |96| | |72| | | | |70|91| | | | | |3 | | | | | | Turno do JOGADOR2 Pontos do jogador 1 : 1174 pontos Pontos do jogador 2 : 1173 pontos Nos analisados: 5 Cortes alfa: 0 Cortes beta: 2 Tempo de execucao: 0.008 | | | |0 |10| |-1| | | | | | |-2| |69| | | | | | |22| |1 |27| | | | | | | |44|19| | | | | | | | | | | | | |7 | | | | | | | | | | | | | |35| | | | |53| |30| | | | |17| | |71| |11| | | | | | | | |96| | |72| | | | |70|91| | | | | |3 | | | | | | Turno do JOGADOR1 Pontos do jogador 1 : 1174 pontos Pontos do jogador 2 : 1265 pontos Indique a linha a selecionar De 1 a 10 2 Indique a coluna a selecionar De 1 a 10 5 | | | |0 |10| | | | | | | | |-2| |-1| | | | | | |22| |1 |27| | | | | | | |44|19| | | | | | | | | | | | | |7 | | | | | | | | | | | | | |35| | | | |53| |30| | | | |17| | |71| |11| | | | | | | | | | | |72| | | | |70|91| | | | | |3 | | | | | | Turno do JOGADOR2 Pontos do jogador 1 : 1243 pontos Pontos do jogador 2 : 1265 pontos Nos analisados: 4 Cortes alfa: 1 Cortes beta: 1 Tempo de execucao: 0.007 | | | |0 |10| | | | | | | | | | |-1| | | | | | |22| |1 |27| | | | | | | |44|-2| | | | | | | | | | | | | |7 | | | | | | | | | | | | | |35| | | | |53| |30| | | | |17| | |71| |11| | | | | | | | | | | |72| | | | |70| | | | | | |3 | | | | | | Turno do JOGADOR1 Pontos do jogador 1 : 1243 pontos Pontos do jogador 2 : 1284 pontos Indique a linha a selecionar De 1 a 10 3 Indique a coluna a selecionar De 1 a 10 3 | | | |0 | | | | | | | | | | | | | | | | | | |22| |-1|27| | | | | | | |44|-2| | | | | | | | | | | | | |7 | | | | | | | | | | | | | |35| | | | |53| |30| | | | |17| | |71| |11| | | | | | | | | | | |72| | | | |70| | | | | | |3 | | | | | | Turno do JOGADOR2 Pontos do jogador 1 : 1244 pontos Pontos do jogador 2 : 1284 pontos Nos analisados: 2 Cortes alfa: 1 Cortes beta: 0 Tempo de execucao: 0.002 | | | |0 | | | | | | | | | | | | | | | | | | |22| |-1|-2| | | | | | | |44| | | | | | | | | | | | | | |7 | | | | | | | | | | | | | |35| | | | |53| |30| | | | |17| | |71| |11| | | | | | | | | | | | | | | | |70| | | | | | |3 | | | | | | Turno do JOGADOR1 Pontos do jogador 1 : 1244 pontos Pontos do jogador 2 : 1311 pontos Indique a linha a selecionar De 1 a 10 4 Indique a coluna a selecionar De 1 a 10 1 | | | |0 | | | | | | | | | | | | | | | | | | | | | |-2| | | | | | | |-1| | | | | | | | | | | | | | |7 | | | | | | | | | | | | | |35| | | | |53| |30| | | | |17| | |71| |11| | | | | | | | | | | | | | | | |70| | | | | | |3 | | | | | | Turno do JOGADOR2 Pontos do jogador 1 : 1288 pontos Pontos do jogador 2 : 1311 pontos Nos analisados: 1 Cortes alfa: 0 Cortes beta: 0 Tempo de execucao: 0.0 | | | |0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |-1| | | | | | | | | | | | | | |-2| | | | | | | | | | | | | |35| | | | |53| |30| | | | |17| | |71| |11| | | | | | | | | | | | | | | | | | | | | | | |3 | | | | | | Turno do JOGADOR1 Pontos do jogador 1 : 1288 pontos Pontos do jogador 2 : 1318 pontos Sem jogadas, ceder jogada! | | | |0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |-1| | | | | | | | | | | | | | |-2| | | | | | | | | | | | | |35| | | | |53| |30| | | | |17| | |71| |11| | | | | | | | | | | | | | | | | | | | | | | |3 | | | | | | Turno do JOGADOR2 Pontos do jogador 1 : 1288 pontos Pontos do jogador 2 : 1318 pontos Nos analisados: 1 Cortes alfa: 0 Cortes beta: 0 Tempo de execucao: 0.001 | | | |0 | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |-1| | | | | | | | | | | | | | | | | | | | | | | | | | | | |35| | | | |53| |-2| | | | |17| | |71| |11| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | O jogo terminou! Vencedor é o JOGADOR2 Pontos do jogador 1 : 1288 pontos Pontos do jogador 2 : 1348 pontos ---------------------------------------------- ``` ## **8. Conclusão** É com satisfação que apresentamos como concluída a segunda fase deste projeto, integrando no Jogo do Cavalo os conceitos referentes à Teoria de Jogos, com os algoritmos Minimax com cortes AlfaBeta. Consideramos que esta fez cumprir todos os requisitos propostos aquando do início do projeto, possibilitando a consolidação dos conteúdos teóricos relativos à Teoria de Jogos, implementando não só o algoritmo alfabeta, como as suas otimizações mais recorrentes, como a memoização, a procura quiescente e a ordenação de nós. O presente projeto permitiu a aplicação real do conceito de teoria de jogos, direcionado ao Jogo do Cavalo, um problema clássico no ramo da Inteligência Artificial, que revelou o enorme potencial da implementação deste algoritmo e do uso dos cortes alfa-beta na árvore de jogo. Damos assim por concluída a segunda e última fase deste projeto, apresentando como concluídos os objetivos do projeto, possibilitando o jogo Humano-Computador e Computador-Computador no âmbito do Jogo do Cavalo.