Instituto Politécnico do Porto
Instituto Superior de Engenharia
Departamento de Engenharia Informática
Implementação de um
Agente Inteligente para jogar
Elaborado por:
Marlene da Graça Santos nº 980975
Ramo de Computadores e Sistemas
Orientador
Eng. António Jorge dos Santos Pereira
Setembro 2004
Marlene Santos nº 980975
II
Realizado por
Marlene da Graça Santos
Aluna nº 980975
Ramo Computador e Sistemas
Setembro 2004
Orientador
Eng. António Jorge dos Santos Pereira
III
IV
Resumo
Este projecto consiste no desenvolvimento de um agente inteligente que seja capaz
de jogar o Dvonn, sendo que o Dvonn é um jogo de tabuleiro para dois jogadores.
Para que o agente possa “substituir” um jogador humano necessita de possuir
algumas capacidades de raciocínio que lhe permitam tomar “boas” decisões
relativamente às jogadas a realizar. Esta tomada de decisão por parte do agente,
deverá ser feita tendo em conta diferentes níveis de abstracção, designadamente,
estratégico, táctico e operacional. Cada um destes níveis compreende diferentes
objectivos ou metas a cumprir.
No que diz respeito ao projecto em questão, foram considerados os seguintes
aspectos em cada um dos níveis. No operacional, são representadas as estruturas de
dados de baixo nível que suportam a implementação do jogo bem como as regras do
jogo e validações necessárias. No nível táctico são definidas e estruturadas as metas
atingir a curto prazo, designadamente “jogadas” envolvendo um conjunto de
movimentos. No nível estratégico são definidos objectivos a atingir a longo prazo,
sendo necessário considerar elementos difusos de raciocínio como por exemplo,
jogada “boa” ou “má”, para além disso é levada em consideração a necessidade de
ponderar não só os ganhos imediatos mas também os ganhos a obter no final do
jogo. Este último nível, por dificuldades várias é aquele que se encontra num estado
mais insipiente. Finalmente, para atingir a vitória, objectivo último do jogo, os níveis
teriam de cooperar entre si.
No desenvolvimento do agente foi utilizada a linguagem Prolog, principalmente
devido ao nível de abstracção que a linguagem proporciona para a representação de
diferentes camadas de conhecimento e também pelo facto de fornecer um motor de
raciocínio nativo. O interpretador de Prolog utilizado foi Win-Prolog 4.32 por ser a
existe disponível no ISEP e também pelo facto de disponibilizar bibliotecas que
permitem a implementação facilitada de agentes.
V
VI
Dedicatória
À minha querida mãe, aos meus irmãos e toda a minha família em Cabo Verde.
VII
VIII
Agradecimentos
Em primeiro lugar quero agradecer a Jeová Deus de todo o coração pela força, ânimo
e consolo que me deu durante estes últimos meses que foram muito difíceis e
decisivos para mim a nível pessoal e também por todas as bênçãos que tive durante
todo o meu percurso escolar aqui em Portugal.
Agradeço também ao meu orientador pelos esclarecimentos, pelo apoio na fase de
implementação do projecto, pelas ideias que me transmitiu e pelo seu empenho em
me ajudar neste projecto.
Gostaria de agradecer a minha querida irmã Natasha que tem me aturado bastante
durante estes últimos meses e a toda a minha família que também mesmo de longe
me tem motivado a seguir em frente e não desistir.
Quero agradecer aos meus irmãos do peito Ricardo e João, e também as minhas
queridas amigas Rosa e Anabela e também ao Miguel pela paciência e amizade que
tiveram por mim durante estes anos de muita luta.
À todos os meus irmãos na congregação que de uma forma prática têm me ajudado
em especial a Filomena e a Alcina, um obrigado de coração.
Quero agradecer a todos os meus colegas de casa que me têm apoiado mais de
perto e viveram estes momentos de stress comigo.
E de uma forma geral, quero agradecer a todos aqueles que de uma forma directa ou
indirecta contribuíram para a realização deste projecto.
IX
Índice
Capítulo 1 ________________________________________________1
Introdução __________________________________________________1
1.1 -
Motivação para a escolha do projecto _____________________________2
1.2 -
Organização do relatório _______________________________________3
1.3 -
Notação utilizada no relatório ___________________________________4
Capítulo 2 ________________________________________________7
Teoria dos Jogos ______________________________________________7
2.1 -
Conceitos associados __________________________________________9
2.2 -
Tipo de jogos de estratégia ____________________________________11
2.2.1 -
Jogos de soma zero _______________________________________12
2.2.2 -
Jogos de soma não zero ___________________________________14
2.3 -
Equilíbrio de Nash ___________________________________________15
Capítulo 3 _______________________________________________19
Técnicas de busca para exploração de árvores de decisão _____________19
3.1 -
Estratégias de Busca Tradicionais _______________________________22
3.1.1 -
Busca por largura ________________________________________22
3.1.2 -
Busca em profundidade ____________________________________24
3.1.3 -
Busca bidirecional ________________________________________25
3.1.4 -
Busca de custo uniforme ___________________________________26
3.1.5 -
Busca heurística _________________________________________26
3.2 -
Análise de algoritmos de busca _________________________________27
Capítulo 4 _______________________________________________31
O Algoritmo MiniMax e alguns refinamentos _______________________31
4.1 -
Descrição do algoritmo MiniMax ________________________________31
X
4.2 -
Cortes ALFA-BETA ___________________________________________38
4.3 -
Desvantagens do MiniMax _____________________________________42
4.4 -
Jogos implementados usando o MiniMax __________________________43
Capítulo 5 _______________________________________________45
Implementação de um agente inteligente para o Dvonn ______________45
5.1 -
Regras do Dvonn ____________________________________________45
5.2 -
Descrição do Problema a resolver _______________________________50
5.3 -
Análise de espaço do problema _________________________________51
5.4 -
Estruturação do problema proposto______________________________52
5.5 -
Implementação das regras do jogo ______________________________58
5.5.1 -
Validação das jogadas _____________________________________58
5.5.2 -
Como calcular os benefícios de uma jogada? ___________________61
5.5.3 -
Calcular o Isolamento de peças______________________________63
5.5.4 -
Fim do Jogo _____________________________________________69
5.6 -
Tácticas propostas para o jogo _________________________________69
5.6.1 5.7 -
Implementação das tácticas propostas ________________________71
Comunicação do agente com o servidor de jogos na Internet__________77
Capítulo 6 _______________________________________________79
Conclusão __________________________________________________79
Bibliografia e Referências ______________________________________81
Acrônimos__________________________________________________83
XI
Índice de figuras
Figura 1 - Busca em largura ___________________________________________23
Figura 2 – Busca em profundidade ______________________________________25
Figura 3 - Método MiniMax ____________________________________________33
Figura 4 – Busca numa árvore uma e duas posições a frente [1]_______________34
Figura 5 – Cortes Alfa e Beta [1]________________________________________39
Figura 6 – Corte usando o valor de Alfa __________________________________39
Figura 7 – Corte usando o valor Beta ____________________________________39
Figura 8 - Peças no tabuleiro que não podem ser movidas____________________47
Figura 9 - Movimento das peças ________________________________________48
Figura 10 - Perda de peças ____________________________________________48
Figura 11 – Fim do jogo ______________________________________________49
Figura 12 - Diferentes níveis de abstração no jogo Dvonn ____________________52
Figura 13 – Organização dos ficheiros____________________________________54
Figura 14 – Tabuleiro Dvonn [19] _______________________________________56
Figura 15 – Formato de apresentação do tabuleiro__________________________57
Figura 16 – Direcções para onde uma pilha pode movimentar _________________59
Figura 17 – Movimentar uma pilha ______________________________________60
Figura 18 – Isolamento de peças _______________________________________63
Figura 19 – Tabuleiro inicial gerado pelo servidor___________________________63
Figura 20 – Divisão do tabuleiro em áreas ________________________________64
Figura 21 – Movimentar pilhas entre áreas ________________________________67
Figura 22 – Comunicação entre os participantes do jogo _____________________78
XII
XIII
Capítulo 1
Introdução
Os jogos exercem um fascínio inexplicável sobre muitas pessoas. Desde o
surgimento dos computadores que os especialistas se aperceberam das grandes
hipóteses de poder usar o computador para criar programas de jogos capazes de
competir com humanos.
Assim desde esse tempo muito se tem feito para concretizar a ideia de que
programas de computador seriam capazes de jogar e aprender com os seus próprios
erros melhorando o seu próprio desempenho.
A Inteligência Artificial tem um papel relevante neste contexto contribuindo com
métodos e algoritmos para que possam ser criados programas com capacidades de
agir cada vez mais como humanos podendo assim actuar e tomar boas decisões ao
longo do jogo. Na área dos jogos, estas técnicas foram inicialmente aplicadas a jogos
como xadrez, damas e jogo do galo. Actualmente, as técnicas de Inteligência
Artificial aplicadas em jogos de computador estão mais desenvolvidas, permitindo a
criação de jogos mais complexos, que permitem a criação de programas mais
inteligentes e de ambientes mais reais para interagir com os mesmos.
Tendo em conta o desenvolvimento acelerado das tecnologias computacionais, quer
a nível de hardware e software há cada vez mais melhores condições técnicas e
computacionais que permitem a exploração da inteligência artificial em jogos muito
pesados.
Os jogos de computador são uma excelente plataforma para testes e validações de
novas metodologias e algoritmos, devido a própria natureza dos jogos e a
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
1
Instituto Superior de Engenharia do Porto
Capítulo 1 - Introdução
complexidade dos ambientes que requerem, bem como a existência de inúmeros
voluntários humanos para a realização dos testes. Uma vez que estes ambientes são
controlados, proporcionam as condições ideais para teste de procedimentos
complexos.
Através dos jogos de computador pode-se verificar a validade das mais diversas
técnicas de inteligência artificial, desde o reconhecimento da linguagem natural,
modelos de cognição e interacção, até mecanismos complexos de planeamento,
busca e aprendizagem.
Muitos pioneiros da ciência da informação e computação contribuíram para uma
nascente literatura sobre jogos em computador. Muitos descreveram mecanismos
que poderiam ser usados em programas para diversos tipos de jogos tais como
xadrez e damas. Os problemas principais que se colocam nos jogos são sem dúvida
que tácticas e estratégias poderão ser usados para ganhar o adversário [1].
Tendo em conta que muitos desses problemas obviamente já foram resolvidos ao
longo do tempo, assim este projecto foi proposto com o objectivo de desenvolver um
estudo e a implementação de um agente inteligente capaz de jogar o Dvonn, um
jogo de tabuleiro que se encontra disponível na Internet para dois jogadores on-line.
Pretende-se uma implementação do jogo onde um jogador possa jogar com o
próprio computador, neste caso o agente inteligente. Mais importante ainda do que a
implementação do próprio agente inteligente, será o estudo pormenorizado dos
algoritmos já existentes sobre teoria de jogos, avaliação do desempenho desses
algoritmos, as tácticas e estratégias de jogo usados em geral, e como poderiam ser
adaptados ao jogo Dvonn. Após esse estudo, escolher um algoritmo que melhor se
adapta ao problema específico ou então optar por adaptar um determinado algoritmo
ao problema em especifico, ou até mesmo criar um algoritmo próprio para o
problema de acordo com as teorias disponíveis.
1.1 -
Motivação para a escolha do projecto
A primeira vista, na listagem de projectos propostos pelos professores nenhum dos
projectos me despertou muito interesse. Confesso que no início tive muitos
problemas em escolher o projecto devido ao facto da questão muitas vezes
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
2
Instituto Superior de Engenharia do Porto
Capítulo 1 – Introdução
levantada quanto a possibilidade de os alunos que escolhessem projectos com uma
grande componente prática serem penalizados por essa mesma escolha. Depois dos
esclarecimentos dados pelo responsável Paulo Ferreira e de falar muita abertamente
com o orientador sobre o problema decidi ir em frente com o projecto. A explicação
inicial que o orientador me deu, e a simpatia e empenho que demonstrou
motivou-me muito na mesma escolha, apesar de considerar que o projecto seria
bastante difícil e exigiria de mim um grande empenho tanto na componente prática
como teórica. Contudo decidi aceitar o desafio uma vez que é uma coisa diferente
que não estou habituada a fazer. E também porque na altura quando estudei a
cadeira Computação gráfica percebi realmente a quantidade de trabalho envolvido a
nível gráfico nos jogos e isso me fascinou. Neste trabalho não teria que trabalhar
com computação gráfica mas teria que trabalhar com estratégias e tácticas de jogo,
e isso também me despertam muito interesse.
1.2 -
Organização do relatório
Este relatório encontra-se subdividido em 6 capítulos que serão descritos a seguir.
Capítulo 1
Faz uma introdução ao projecto e descreve de uma forma resumida o problema
proposto.
Capitulo 2
Este capítulo se dedica essencialmente ao estudo da teoria dos jogos de uma forma
que nos permite ter um conhecimento mais abrangente sobre o tipo de problemas
que podemos deparar ao tentarmos analisar o que se encontra por detrás de um
jogo de computador. Descreve os conceitos e termos mais utilizados nesta área e em
outras áreas onde a tomada de decisões pode ser comparada a um jogo. O capítulo
faz também uma pequena distinção entre os vários tipos de jogos existentes, e os
mais estudados. Descreve também de uma forma de fácil perceptibilidade como os
estudos efectuados por Nash e a própria teoria desenvolvida por ele são de uma
forma prática usados em jogos.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
3
Instituto Superior de Engenharia do Porto
Capítulo 1 - Introdução
Capítulo 3
Este capítulo faz uma introdução relacionado com Inteligência Artificial, Agentes
inteligentes e a necessidade dos agentes terem alguma inteligência que lhes
possibilita tomar decisões por si próprio. Também, descreve-se algumas estratégias
de busca em árvores, suas vantagens e desvantagens a nível de requisitos de
hardware e capacidade de processamento.
Capítulo 4
Este capítulo é dedicado ao algoritmo MiniMax que é o algoritmo mais conhecido e
mais usado em teoria dos jogos. Faz-se uma descrição pormenorizada do algoritmo,
como foi pensado, as vantagens, as desvantagens, o grau de desempenho, as
condições de processamento e requisitos de memória que exige e alguns
melhoramentos.
Capítulo 5
De uma forma resumida este capítulo faz uma análise do problema proposto, avalia
as situações possíveis de implementação, estrutura a organização da informação que
será preciso para o próprio funcionamento do agente, e descreve a implementação
feita e alguns predicados mais importantes.
Capítulo 6
Este capítulo é destinado para a conclusão, a descrição das dificuldades encontradas
na elaboração e implementação do projecto, aspectos interessantes e considerações
sobre
como
poderia
melhorar
o
desempenho
do
agente,
ou
ainda
que
funcionalidades poderiam ser acrescentado futuramente.
1.3 -
Notação utilizada no relatório
Ao longo do relatório foi utilizada a font Verdana tamanho 10 e alinhamento
justificado. Para termos em inglês e a descrição de conceitos foi usada o mesmo tipo
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
4
Instituto Superior de Engenharia do Porto
Capítulo 1 – Introdução
de letra mas com o estilo Itálico. Para a descrição de métodos ou predicados usados
na implementação do agente foi usada a font Fixedsys tamanho 10 com estilo Itálico.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
5
Instituto Superior de Engenharia do Porto
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
Capítulo 1 - Introdução
6
Capítulo 2
Teoria dos Jogos
A Teoria dos Jogos foi criada na década de 40 pelo matemático John Von Neumann e
recentemente, o matemático John Nash fez um novo estudo sobre o equilíbrio em
jogos não cooperativos e conseguiu obter o prémio Nobel de economia em 1994.
Esta teoria com base matemática é uma ferramenta muito importante na tomada de
decisões [4].
A teoria dos jogos trata de situações de concorrência ou competição entre dois ou
mais participantes cada um com os seus próprios objectivos e estratégias definidas.
Nestas situações de concorrência ou competição cada participante terá que ter
alguma capacidade de tomar decisões acertadas. Estas decisões são muito
importantes porque são elas que irão permitir ou não que os objectivos predefinidos
pelos participantes sejam atingidos.
De acordo com a referência [11], esta é uma teoria baseada em conflitos porque
existe uma concorrência entre os diversos participantes. Ao mesmo tempo a teoria
pode ser considerada de colaboração entre os vários participantes, quando existe a
possibilidade de haver um acordo entre os participantes. Tendo em vista que cada
um dos intervenientes tem como objectivo tirar o máximo ganho, ou seja, cumprir
com os seus objectivos anteriormente delineados, então as jogadas poderão
favorecer ou contrariar as decisões de jogadas uns dos outros. Em relação aos jogos
em si, a escolha das jogadas deve ter em conta as possibilidades de jogadas dos
outros jogadores, e se necessário uma mudança de estratégia de acordo com o
estado do jogo. Para que um jogador consiga obter bons resultados é preciso
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
7
Instituto Superior de Engenharia do Porto
Capítulo 2 – Teoria dos Jogos
considerar todas as hipóteses de jogadas dos adversários e assim poderá fazer uma
avaliação minuciosa dessa informação e tomar decisões que favoreçam os seus
objectivos anteriormente delineados.
Para alguns jogos, a teoria pode indicar uma solução para o jogo, isto é, pode indicar
as melhores jogadas para cada jogador. No entanto, na maioria dos jogos que
descrevem problemas reais, a teoria apenas fornece uma visão geral da situação,
desprezando jogadas que não levarão a bons resultados.
Existem inúmeras situações que podem ser tratadas como jogos. John Von Newmann
desenvolveu esta teoria com o intuito de poder ser aplicada em muitas outras
situações e não apenas aos jogos. Qualquer situação onde existem interesses
competitivos, onde cada envolvente procura maximizar os seus ganhos e perdas dos
outros é considerado um problema de teoria dos jogos. Nesta descrição se encaixam
as tácticas de guerra, a política nacional e internacional, os problemas económicos,
problemas de competitividade comercial e até mesmo a evolução biológica, que tem
factores facilmente quantificáveis. De salientar que a teoria dos jogos não envolve a
componente humana e emocional que poderão afectar problemas reais tal como nos
conflitos militar.
Devido a natureza dos jogos, os jogadores ou participantes estão constantemente a
alterar as suas estratégias de jogo. Quando se toma uma decisão de efectuar uma
determinada jogada, pode-se calcular qual será a reacção dos adversários e preparar
uma jogada ou estratégia para contra-atacar os adversários.
Quanto mais
adversários existirem mais difícil será a tomada de decisões.
Ao contrário dos jogos, em ambientes reais onde existem factores humanos a ter em
conta, é muito mais difícil determinar qual a jogada que o adversário fará, uma vez
que os humanos são muito imprevisíveis devido a componente emocional que não
existe nos jogos. Isto acontece porque na maioria das vezes não estão dispostos a
acordo, ou então uma ou mais partes não segue o princípio acordado. Isto aplica-se
na maior parte das vezes em casos de conflito militar.
No que diz respeito aos jogos em si, existem jogos com dois ou mais jogadores,
cooperativos ou não. Entre os tipos de jogos possíveis estão os recreativos, tais
como póquer, monopólio e jogo do galo, os jogos de tabuleiro, como xadrez, damas,
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
8
Instituto Superior de Engenharia do Porto
Capítulo 2 – Teoria dos Jogos
nos quais se inclui o Dvonn, e os de problemas económicos, políticos e sociológicos.
Os jogos podem ser representados através de uma árvore ou através de matrizes de
payoff (utilidade, ganho).
De acordo com a referência [6] para que a teoria dos jogos possa ser usada em
diversas situações é preciso pressupor que:
™ Os jogadores sejam racionais e que pretendem vencer (ou maximizar seus
resultados) acima de tudo, e tenham a preocupação de adivinhar o próximo
passo do adversário;
™ Cada jogo possui um conjunto de regras próprias e pré-definidas;
™ Existe uma paridade de conhecimento e habilidade entre todos os jogadores;
™ Os jogos acontecem em ambientes abertos e integrados;
™ Deve existir uma interdependência entre os movimentos dos jogadores, em
que cada escolha sucessiva de um jogador incita o outro a alterar suas
escolhas subsequentes;
™ Recompensas que podem ter significados diferentes para cada jogador
dependendo de seus sistemas de valores.
2.1 -
Conceitos associados
Na teoria de jogos, a palavra jogo refere-se a um tipo especial de conflito no qual
tomam parte n indivíduos ou grupos (conhecidos como os jogadores). Há certas
regras do jogo, que dão as condições para que este comece e definem as jogadas
consideradas válidas durante as diferentes fases do jogo. É necessário considerar
também o tipo de informação que temos que poderá ser completa ou incompleta,
consoante as funções de payoff (tácticas e estratégias) dos jogadores são ou não de
conhecimento geral e também é preciso saber se a informação é perfeita ou
imperfeita. A informação é perfeita se em cada jogada, o jogador que vai jogar
sabe toda a história do jogo, caso contrário então a informação é imperfeita.
De acordo com o projecto em desenvolvimento, na implementação do agente para
jogar o Dvonn temos o terreno que no nosso caso é o tabuleiro, temos um jogador
que se encontra do outro lado do servidor e o agente inteligente. Temos as jogadas,
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
9
Instituto Superior de Engenharia do Porto
Capítulo 2 – Teoria dos Jogos
as regras do jogo que definem as jogadas válidas, as tácticas de jogo definidos como
payoff (que serão definidas a curto prazo, ou seja, beneficio da jogada no momento)
e as estratégias de jogo (definidas a longo prazo, ou seja, a avaliação do efeito de
uma jogada após o progresso do jogo a nível global).
Podemos definir esses elementos essenciais do seguinte modo:
Jogada – é a maneira segundo a qual o jogo progride de um estado para o outro.
Podem ser alternadas entre os jogadores de uma forma especificada ou ocorrer
simultaneamente. Existem jogos onde um jogador vai jogando um número
indeterminado de vezes seguido até chegar a uma situação em que é obrigado a
passar a jogada ao(s) adversário(s). Uma jogada então é a decisão de um dos
jogadores de concretizar um determinado objectivo de jogo mediante a avaliação dos
benefícios das várias hipóteses de jogo. Atenção que no caso do Dvonn um dos
jogadores pode jogar mais do que uma vez seguida, se o adversário não tiver
hipótese de realizar jogadas válidas, no caso de nenhum dos dois possuir jogadas
válidas o jogo termina. Tirando estas excepções as jogadas são efectuadas
alternadamente entre os jogadores.
Payoff – benefício de uma jogada. Esse benefício é o pagamento da jogada.
Dependendo do tipo de jogo, os valores de payoff terão uma interpretação diferente.
Pode tomar um valor negativo, nulo ou positivo. Se esse benefício for negativo
significa que se efectuarmos esta jogada teremos uma perda nesse valor. Nos jogos
de soma zero, essa perda será um ganho para o adversário desse valor.
No caso do Dvonn, foi definida no âmbito deste projecto uma fórmula que permite
atribuir um determinado peso a uma jogada. Este peso será calculado em função dos
ganhos e perdas não só do agente inteligente mas também do adversário, porque
para uma determinada jogada, tanto o jogador pode ganhar peças como também
poderá perder peças se a jogada provocar o isolamento de algumas peças (ficam
sem ligação a pelo menos um Dvonn). Essas peças isoladas tanto podem ser do
jogador como do adversário.
Estratégias – descrição das decisões a tomar em todas as situações possíveis.
Nesta fase, ao contrário do custo beneficio a curto prazo, faz-se uma avaliação a
longo prazo de uma determinada jogada sempre com o objectivo de ganhar o jogo.
Dependendo do tipo de jogo a analisar, o desenvolvimento das estratégias de jogo é
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
10
Instituto Superior de Engenharia do Porto
Capítulo 2 – Teoria dos Jogos
bastante difícil e complicado e exige bastante recurso de memória e do processador
uma vez que exige a criação de uma árvore ou um grafo com todas as jogadas
possíveis. Mais a frente falaremos melhor de alguns algoritmos de busca utilizados
na maior parte dos jogos de tabuleiro.
De uma forma matemática, temos associado a um jogo os seguintes elementos, o
conjunto dos jogadores que podemos representar por G = {g1, g2, g3, ..., gn}. Cada
jogador gi ∈ G possui um conjunto finito Si = {s1, s2, s3, ..., smi} de hipóteses de
jogada, que são denominadas de estratégias puras do jogador gi (mi ≥ 2 porque
logicamente o jogador tem que ter pelo menos duas opções de jogada). Após termos
as estratégias puras de cada jogador, então transforma-se estes conjuntos num só.
O novo conjunto será o S que é a combinação de todas as hipóteses de jogada dos n
jogadores, ou seja, isto é obtido através do produto cartesiano. Este conjunto
resultante é denominado espaço de estratégia pura do jogo [23].
S =
n
∏S
i
i =1
Também associado as jogadas de cada jogador podemos ter um peso que
identificará os ganhos das mesmas jogadas. Este peso é representado por ui.
µi : S → ℜ
S → µ i (S )
2.2 -
Tipo de jogos de estratégia
A teoria de jogos distingue vários tipos de jogos, de acordo com o número de
jogadores e com as circunstâncias do jogo. Existem diferentes tipos de jogos e estes
são caracterizados de acordo com o tipo de informação que os jogadores têm acesso,
e com as características dessa mesma informação.
Podemos distinguir vários tipos de jogos entre os quais destacam-se os seguintes:
™ Jogos de soma zero
™ Jogos de soma não zero
™ Jogos de informação completa
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
11
Instituto Superior de Engenharia do Porto
Capítulo 2 – Teoria dos Jogos
™ Jogos de informação incompleta
De entre estes serão descritos muito abreviadamente os jogos de soma zero e jogos
de soma não zero por serem os mais estudados.
2.2.1 -
Jogos de soma zero
Os jogos de soma zero são aqueles onde o ganho de um jogador é a perda do
adversário (considerando jogos de dois jogadores). Deste modo o jogo é de soma
zero porque o total dos ganhos no final da partida é nulo, isto é, o total de ganhos é
igual ao total de perdas. Os jogos de soma zero com dois jogadores são o principal
objecto de estudo da teoria matemática dos jogos.
Este tipo de jogo envolve um intenso esforço competitivo entre dois jogadores,
porque os jogadores ganham às custas um do outro. Desta maneira não existe
vantagem nenhuma na colaboração por parte dos jogadores. Não importa o que os
jogadores façam, o valor que um jogador ganha é sempre igual ao valor que o seu
adversário perde, de modo que o ganho total de ambos os jogadores é
necessariamente zero. De acordo com os conceitos associados à teoria dos jogos, e
com as características dos jogos de soma zero, pode-se definir a seguinte matriz de
payoff [9], se considerar que existem dois jogadores A e B com m e n estratégias
cada um respectivamente. Para o jogador A, o jogo poderá ser representado pela
matriz de payoff que se encontra a seguir. Esta representação indica que se A usa
uma estratégia i e B usa uma estratégia j, o payoff para A é pij e consequentemente
o payoff para B é -pij.
B1
B2
...
Bn
A1
P11
P12
...
P1m
A2
P21
P22
...
P2m
...
:
:
:
:
Am
Pm1
Pm2
...
Pmn
Após a definição da matriz de payoff, os jogadores terão que analisar o jogo e definir
a melhor estratégia. As referências [9] e [13] demonstram a utilização do algoritmo
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
12
Instituto Superior de Engenharia do Porto
Capítulo 2 – Teoria dos Jogos
MiniMax neste tipo de jogos. Este algoritmo que será descrito pormenorizadamente
no capítulo 4 corresponde ao seguinte: o adversário tenta minimizar o Máximo que o
outro jogador poderá ganhar. E este por sua vez tenta maximizar o mínimo possível
de ganho. Considere um exemplo de concorrência no mercado de venda de marcas
de vacina para gripe, onde temos as companhias A e B.
A companhia A pode anunciar o seu produto na rádio (estratégia A1), na televisão
(estratégia A2) ou no jornal (estratégia A3). A companhia B pode anunciar o seu
produto na rádio (estratégia B1), na televisão (estratégia B2), no jornal (estratégia
B3) ou mala directa (estratégia B4). Dependendo da criatividade e da intensidade
dos anúncios, cada companhia pode ganhar uma porção do mercado da outra
companhia. A matriz de payoff a seguir resume a percentagem de mercado ganho ou
perdido pela companhia A.
B1
B2
B3
B4
A1
8
-2
9
-3
A2
6
5
6
8
A3
-2
4
-9
5
Para a companhia A, o critério de escolha das estratégias é considerar o “Melhor
resultado entre os piores” que a companhia pode obter. Assim, para a estratégia A1
o pior resultado que a companhia A poderá obter é –3 se a companhia B escolher a
estratégia B4. Para a estratégia A2 o pior resultado possível é 5, e para A3 o pior
resultado é –9. Avaliando então estes resultados, o melhor dos piores resultados é a
companhia A optar-se pela estratégia A2. No entanto, para a companhia B, o critério
de escolha já é diferente, ou seja, pretende-se o “Pior resultado entre os melhores”
que a concorrência poderá ter. Então, a melhor escolha para a companhia B seria o
pior resultado que a companhia A poderá obter se aplicar a estratégia A2. A solução
óptima para o jogo é A2 – B2, ambas as companhias devem anunciar os seus
produtos na televisão.
O payoff será a favor da companhia A, porque seu mercado ganhará 5% do mercado
de B. Quando os valores “Melhor resultado entre os piores” e “Pior resultado entre os
melhores” forem iguais diz-se que existe um ponto de equilíbrio. Neste caso como
esses valores são iguais a 5 diz-se que o valor do jogo é 5.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
13
Instituto Superior de Engenharia do Porto
Capítulo 2 – Teoria dos Jogos
A solução de equilíbrio garante que nenhuma companhia tentará seleccionar uma
estratégia melhor porque poderá acontecer o que em vez de ganhar perca. Se B
escolher outra estratégia (B1, B3 ou B4), a companhia A pode ficar com a estratégia
A2, que garante que B perderá mais mercado para A (6% ou 8%). Da mesma
maneira, A não quer usar uma estratégia diferente (A1 ou A3) porque se escolher
A3, B poderá escolher B3 e ganhar 9% do mercado de A. Também se A escolher a
estratégia A1, B poderá escolher B3 e então ganha 9% do mercado de A.
Para o caso de os valores “Melhor resultado entre os piores” e “Pior resultado entre
os melhores” não serem iguais John Von Newmann sugeriu a utilização de
estratégias mistas. Nesta situação não é vantajoso para nenhum dos jogadores usar
as mesmas estratégias a cada novo jogo.
Cada vez que um novo jogo começa, os jogadores escolhem aleatoriamente qual
estratégia adoptar. Deve-se observar que o uso deste tipo de estratégia exige que o
jogo seja jogado repetidas vezes.
2.2.2 -
Jogos de soma não zero
Os jogos de soma não zero se diferenciam dos de soma zero pelo facto de que neste
tipo de jogos os jogadores não são completamente opostos uns aos outros, ou seja,
a relação de ganho e perda que existe nos jogos de soma zero não se aplica para
todos os resultados para este tipo de jogos. Ao contrário dos jogos de soma zero, os
jogos de soma não zero se baseiam apenas no princípio “Melhor resultado entre os
piores”. Isto quer dizer que tanto um jogador como o outro pretendem sempre
melhorar os seus ganhos, ou seja, ambos os jogadores optam por estratégias que
maximizam seus payoffs mínimos. O que B ganha não é necessariamente igual ao
que A perde.
Então, a grande diferença entre os jogos de soma zero e os de soma não zero é que
neste último não há um conceito óbvio de solução do jogo, como o que foi descrito
para os de soma zero.
Enquanto que para estes últimos a solução é garantida pelo Teorema MiniMax, para
os jogos de soma não zero, John Nash provou, em 1951, uma generalização desse
teorema, utilizando o conceito de pares de equilíbrio. De notar que a teoria de
equilíbrio de Nash que será desenvolvida mais pormenorizadamente na secção
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
14
Instituto Superior de Engenharia do Porto
Capítulo 2 – Teoria dos Jogos
2.3, não se restringe aos jogos de soma não zero, na realidade pode-se constatar
que também se aplica aos jogos de soma zero, por verificar que neste caso esta
teoria é equivalente ao teorema MiniMax.
Concluindo o raciocínio, apesar de a teoria do equilíbrio garantir que existe sempre
pelo menos um par de equilíbrio no jogo, ele não diz como encontrá-lo. Assim
torna-se difícil construir algoritmos para determinar todos os pares de equilíbrio de
um jogo de soma não zero com dois jogadores. [15]
2.3 -
Equilíbrio de Nash
Partindo do pressuposto de que cada jogador desenvolve sempre a melhor estratégia
para fazer face as estratégias dos seus adversários, pode-se definir o equilíbrio de
Nash da seguinte forma:
Para um jogo com dois Jogadores (A e B), um par de estratégias (a*, b*) representa
uma solução de equilíbrio, se a* for uma estratégia óptima para o Jogador A
enfrentar a estratégia b*, e se simultaneamente b* for a estratégia óptima para o
Jogador B enfrentar a estratégia a*.
Para demonstrar este teorema de Nash considere o exemplo mais conhecido da
teoria dos jogos, o dilema dos prisioneiros. Este foi formulado por Albert W. Tucker
em 1950 num seminário para psicólogos na Universidade de Stanford, para ilustrar a
dificuldade de se analisar certos tipos de jogos.
A situação é a seguinte: dois ladrões Al e Bob são capturados e acusados cada um
individualmente do mesmo crime. São presos em celas separadas e sem poderem se
comunicar entre si e são confrontados com a seguinte proposta do chefe da polícia:
cada um pode escolher entre confessar ou negar o crime. Se nenhum deles
confessar, ambos serão submetidos a uma pena de 1 ano. Se os dois confessarem o
crime, então ambos serão condenadas a cumprir uma pena de 5 anos. Mas se um
dos ladrões confessar e o outro negar, então o ladrão que confessou é liberto e o
outro é condenado a dez anos de prisão.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
15
Instituto Superior de Engenharia do Porto
Capítulo 2 – Teoria dos Jogos
Esquematizando o problema usando estratégias puras temos:
G = {Al, Bob}
SAl = {confessar, negar}
SBob = {confessar, negar}
S = {(confessar, confessar), (confessar, negar), (negar, confessar), (negar, negar)}
As combinações possíveis que podemos ter são:
Para AL
uAl(confessar, confessar) = −5, uAl(confessar, negar) = 0,
uAl(negar, confessar) = −10, uAl(negar, negar) = −1,
Para BOB
uBob(confessar, confessar) = −5, uBob(confessar, negar) = 0,
uBob(negar, confessar) = −10, uBob(negar, negar) = −1
De acordo com as combinações estabelecidas para cada ladrão e respectiva pena que
terão de cumprir mediante as suas escolhas, define-se a seguinte matriz de payoff.
Bob
Al
confessar
Negar
confessar
(-5,-5)
(0,-10)
negar
(-10,0)
(-1,-1)
Assim sendo, qual é a melhor estratégia a escolher por cada ladrão?
Considerando que cada uma dos ladrões pretende minimizar a sua pena, então para
encontrar uma solução favorável para os ladrões, pode-se fazer uma previsão das
consequências de cada escolha dos ladrões. Para isso, analise primeiramente a
situação de Al.
Podemos raciocinar da seguinte forma:
Duas coisas podem acontecer: Bob pode confessar ou pode negar. Se Bob confessar,
então é melhor para AL confessar. Se Bob não confessar, então AL fica livre se
confessar. Em qualquer dos casos, é melhor para AL confessar. Então, a melhor
estratégia é confessar.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
16
Instituto Superior de Engenharia do Porto
Capítulo 2 – Teoria dos Jogos
Pode-se também aplicar o mesmo raciocínio para Bob e chegar a conclusão que a
melhor estratégia para os dois ladrões é ambos confessarem o crime e cumprirem a
pena de 5 anos cada.
Existem vários conceitos para encontrar uma solução de equilíbrio para este tipo de
problemas mas neste relatório só iremos referir ao conceito de Nash.
O conceito de Nash define uma solução estratégica ou equilíbrio de Nash de um jogo
como um ponto onde cada jogador não tem incentivo para mudar a sua estratégia se
os demais jogadores não o fizerem. Ou seja, se um dos participantes mudar a
estratégia poderá piorar a sua situação porque o outro poderá mudar a sua
estratégia e vencer.
Considerando o dilema de prisioneiros, o perfil de estratégia (confessar, confessar) é
a única combinação que podemos considerar como equilíbrio de Nash porque é a
única estratégia boa para os dois ladrões. Os dois cumprirão uma pena de 5 anos,
caso contrário um dos dois poderia sair em desvantagem em relação ao outro.
Considere o exemplo da Batalha dos sexos onde existem mais do que uma solução
de equilíbrio.
Problema: Um homem e a sua mulher desejam sair para passear. O homem prefere
assistir a um jogo de futebol enquanto que sua mulher prefere ir ao cinema. Se eles
forem juntos ver o futebol, então o homem tem satisfação maior do que a mulher.
Por outro lado, se eles forem juntos ao cinema, então a mulher tem satisfação maior
do que o homem. Finalmente, se eles saírem sozinhos, então ambos ficam
igualmente insatisfeitos.
G = {Homem, Mulher}
SHomen = {Futebol, Cinema}
SMulher = {Futebol, Cinema}
S = {(Futebol, Futebol), (Futebol, Cinema), (Cinema, Futebol), (Cinema, Cinema)}
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
17
Instituto Superior de Engenharia do Porto
Capítulo 2 – Teoria dos Jogos
Considere para a satisfação máxima o valor 10 e insatisfação o valor 0. Define-se a
seguinte matriz de payoff:
Mulher
Homem
futebol
cinema
futebol
(10,5)
(0,0)
cinema
(0,0)
(5,10)
Neste caso, pode-se verificar que existem duas estratégias de equilíbrio (Futebol,
Futebol) e (Cinema, Cinema) porque para as outras duas estratégias tanto o homem
como a mulher ficam insatisfeitos. Portanto a melhor escolha poderá ser uma das
duas estratégias de equilíbrio. Ainda existem casos em que não é possível chegar a
um ponto de equilíbrio usando estratégias puras. Isto acontece quando todas as
estratégias possíveis apresentam valores parecidos ou idênticos. Neste caso há um
conflito que impossibilita a escolha de uma estratégia.
Para resolver este tipo de problemas Nash propôs a utilização de estratégias mistas
onde se recorre ao uso de distribuições de probabilidade.
Sobre cada estratégia pura definida é atribuída uma medida de probabilidade. Essa
medida de probabilidade varia de 0 a 1, sendo que a soma das probabilidades de
todas as estratégias possíveis para o mesmo jogador é 1.
A referência [23] especifica mais pormenorizadamente fórmulas que permitem
chegar a soluções usando o teorema de Nash para estratégias mistas.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
18
Capítulo 3
Técnicas de busca para exploração de árvores de
decisão
Os jogos de computador têm cativado há muito tempo o interesse da comunidade de
sistemas inteligentes, especialmente os jogos tradicionais, como xadrez e damas.
Depois da vitória do computador Deeper Blue sobre Kasparov, tanto a comunidade
científica como o público perceberam a relevância do uso de IA em jogos de
computador. Esta vitória não se deve apenas as inovações no campo de sistemas
inteligentes (SI), mas principalmente aos avanços de hardware. Estes avanços
tecnológicos permitiram aos computadores usar de “força bruta” para ganhar os
opositores humanos.
Por outro lado, os jogos modernos de computador se apresentam como uma nova
plataforma desafiadora para testes de técnicas mais avançadas de sistemas
inteligentes, provendo ambientes altamente dinâmicos e complexos, com múltiplos
objectivos e decisões a serem tomadas em tempo real, sendo assim muito diferentes
dos jogos tradicionais. Para estes tipos de jogos são necessárias outras técnicas de
SI mais apropriadas, como a inteligência computacional e a inteligência artificial
distribuída. [16]
Apesar de se conseguir atingir grandes resultados através do uso da IA, quando se
pretende construir um determinado sistema depara-se com vários problemas
tipicamente relacionados com a IA. A referência [1] dá alguns exemplos das técnicas
que a IA oferece para resolver tais problemas. A mesma referência define três
passos principais que são necessários para resolver um problema em particular que
de seguida serão destacados:
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
19
Instituto Superior de Engenharia do Porto
Capítulo 3 – Sistemas Inteligentes em Jogos
™ Definir o problema com precisão. Esta definição deverá incluir especificações
precisas do que será a situação inicial, bem como que situações finais
constituem soluções aceitáveis para o problema.
™ Analisar o problema. Alguns recursos muito importantes podem ter um forte
impacto sobre a adequação de várias técnicas possíveis para resolver o
problema.
™ Escolher a melhor técnica e aplicá-la ao problema em particular.
Muitos dos problemas que se enquadram dentro do âmbito da inteligência artificial
são demasiadamente complexos para serem resolvidos por técnicas directas. No
entanto, para a resolução de tais problemas deverão ser usados métodos
apropriados, com o auxílio de qualquer técnica directa disponível de busca. Além
disso, as capacidades da máquina a usar condicionam decisivamente a resolução do
problema. Para jogos simples talvez não seja relevante, mas para jogos mais
complexos já teriam algumas complicações. Por exemplo, considere o exemplo do
xadrez:
™ O factor de ramificação médio está ao redor de 35. Isto significa que o
número de jogadas em média para um determinado estado do tabuleiro é 35.
™ No jogo em média cada jogador poderá efectuar 50 movimentos, ou seja,
cada jogador faz em média 50 jogadas durante o jogo todo.
™ Assim, para examinar a árvore completa do jogo, teria que examinar 35100
posições. Este número corresponde a analisar 35 jogadas possíveis para cada
2 jogadores. Sendo que cada jogador faz em média 50 movimentos logo o
total serão 100 jogadas. E assim a árvore terá 35100 nós.
Desta forma consegue-se perceber que um programa que pretenda tirar conclusões
através de uma árvore não poderá fazer simplesmente uma busca directa da árvore
de jogo. A busca na árvore seria praticamente impossível de ser feita e o programa
não conseguiria tomar decisões. Deste modo será necessária a utilização de algum
tipo de procedimento de busca heurística.
Uma heurística é uma técnica auxiliar na descoberta de soluções de problemas,
apesar de que não dá nenhuma garantia de que ela nos guiará sempre na direcção
certa [1]. Existem técnicas heurísticas de aplicabilidade muito geral e outras que
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
20
Instituto Superior de Engenharia do Porto
Capítulo 3 – Sistemas Inteligentes em Jogos
representam conhecimentos específicos, relevantes para a solução de um problema
em particular.
Segundo a referência [1] existem duas formas principais em que a informação
heurística específica pode ser incorporada dentro de um procedimento de busca
baseado em regras:
™ Nas próprias regras, por exemplo, as regras para um sistema de jogo de
xadrez poderiam descrever não só o conjunto de movimentos válidos, mas
também desse conjunto quais os movimentos mais apropriados.
™ Pode-se ter também uma função heurística que avalia todos os estados do
problema individualmente e determina um peso, que representará se o
estado é favorável ou não. Este peso normalmente é definido em números,
podendo ser negativo, positivo ou nulo.
Tendo estas ajudas torna-se mais fácil num processo de busca num nó, dado a
estimativa feita pela função heurística, consegue-se saber se o nó está no melhor
caminho para a solução.
Neste sentido torna-se claro a importância que é pensar bem no problema a
resolver, descrever de forma pormenorizada o problema e assim estudar a situação
de modo a definir heurísticas simples capazes de fornecer estimativas boas. É
importante a confiança que se tem nas heurísticas porque serão elas a nos dar as
orientações no processo de busca de soluções. É através dos valores fornecidos pelas
heurísticas que se sabe se um determinado caminho é bom ou não.
Em outras situações, devem ser utilizadas funções heurísticas mais complexas.
A finalidade de uma função heurística é orientar o processo de busca na direcção
mais lucrativa, sugerindo qual o caminho seguir quando existem mais do que um
caminho disponível. Quanto mais precisas e concretas forem as estimativas da
função heurística de cada nó na árvore ou grafo de busca, tanto mais directo será
encontrar a solução. Assim quanto mais boa for a função tanto menos busca será
preciso efectuar para se chegar a solução. E assim o sistema de uma forma directa
encontra uma solução. No entanto, para muitos programas, o custo de calcular o
valor de tal função seria maior que o despendido no processo de busca. Em geral, há
um ajuste entre o custo de avaliar uma função heurística e a economia de tempo de
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
21
Instituto Superior de Engenharia do Porto
Capítulo 3 – Sistemas Inteligentes em Jogos
busca que a função fornece. A seguir iremos descrever de uma forma resumida
algumas técnicas de busca tradicionais.
3.1 -
Estratégias de Busca Tradicionais
De forma genérica, as estratégias de busca tradicionais envolvem busca em árvores
que descrevem todos os estados possíveis do jogo a partir do estado inicial.
Formalmente, o espaço de busca é constituído por nós n, ligados através de arcos
(ligação entre dois nós). Cada arco pode ter ou não associado um valor, que
corresponde ao custo c de transição de um nó para outro. Cada nó tem associado
uma profundidade p, sendo que a mesma tem valor 0 se for o nó raiz e um valor
diferente de zero que corresponde ao número de nós percorrida da raiz até ao nó.
A aridade a de um nó é a quantidade de filhos que o nó possui, e a aridade de uma
árvore é a maior aridade de qualquer um de seus nós. O objectivo da busca é assim
encontrar um caminho (óptimo ou não) do estado inicial até a um estado final,
explorando sucessivamente os nós ligados aos nós já explorados até a obtenção de
uma solução para o problema. As técnicas mais comuns são:
™ Busca em largura
™ Busca em profundidade
™ Busca bidirecional
™ Busca por custo uniforme
™ Busca heurística
De notar que as estratégias de busca tradicionais são amplamente utilizadas em
jogos tradicionais (xadrez e damas), especialmente porque nos mesmos o ambiente
é determinístico e não dinâmico. [16]
3.1.1 -
Busca por largura
Esta técnica de busca consiste em efectuar a busca inicialmente no nó raiz, e depois
explorar todos os nós filhos do mesmo, e em seguida todos os filhos dos filhos, e
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
22
Instituto Superior de Engenharia do Porto
Capítulo 3 – Sistemas Inteligentes em Jogos
assim sucessivamente (Figura 1). Desta forma todos os nós de profundidade n são
percorridos antes que os nós de profundidade n+1 sejam percorridos.
Vantagens
O algoritmo garante encontrar a solução mais "rasa" (se existir), e a solução óptima
se o custo de um caminho for crescente e dependa apenas da profundidade do nó.
Uma das grandes vantagens desta busca é que está não cairá na armadilha de
explorar um beco sem saída.
Desvantagens
No entanto, apesar das vantagens apresentadas, a busca em largura apresenta um
grande problema: todos os nós explorados devem ser armazenados para futura
expansão, o que pode ser extremamente custoso em termos de memória,
especialmente para problemas de elevada aridade. Além disso, o tempo de execução
também é relativamente alto: para uma árvore de aridade a, e a profundidade da
solução possua um valor d, o algoritmo possui complexidade de O(ad), ou seja, é
exponencial com relação à profundidade da solução. [16]
Figura 1 - Busca em largura
Algoritmo recursivo: Busca em Largura ([17])
1. Crie uma variável Lista-de-nós e ajuste-a para o estado inicial.
2. Até ser encontrado um estado meta ou Lista-de-nós ficar vazia, faça o
seguinte:
(a) Remova o primeiro elemento da Lista-de-nós e chame-o de E. Se
Lista-de-nós estiver vazia, termina.
(b) Para cada maneira como cada regra pode ser casada com o estado
descrito em E, faça o seguinte:
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
23
Instituto Superior de Engenharia do Porto
Capítulo 3 – Sistemas Inteligentes em Jogos
i.
Aplique a regra para gerar um novo estado.
ii.
Se o novo estado for um estado meta, saia e retorne este estado.
iii.
Caso contrário, acrescente o novo estado ao final da Lista-de-nós.
3.1.2 -
Busca em profundidade
No processo de busca em profundidade é analisado sempre o nó com maior
profundidade, ou seja, explora-se o caminho para o objectivo, dando preferência aos
nós mais distantes da raiz.
Esta estratégia garante que uma solução será encontrada, mas não garante a
solução óptima. Em termos de complexidade é a mesma da busca em largura O(ad),
onde a é a aridade e d é a profundidade máxima das soluções.
Vantagens
Em termos de requisitos de memória, esta estratégia de busca consome menos
memória do que a busca em largura, pois só é preciso armazenar o caminho
corrente. Na prática, para problemas com muitas soluções a busca em profundidade
tende a ser mais rápida que a busca em largura.
Desvantagens
Para problemas com muitas soluções a busca pode ficar presa em ramos que não
contenham a solução, o que pode se tornar ainda pior se a árvore tiver profundidade
infinita. Para resolver este problema, para árvores muito profundas, ou ainda árvores
de profundidade infinita, o que se faz é limitar a profundidade de busca, de forma a
permitir que toda a árvore até a profundidade escolhida seja explorada.
Entretanto, surge outro problema que é escolher a profundidade adequada para se
encontrar uma solução. Este problema pode ser melhorado permitindo que a
profundidade limite aumente iterativamente. Entretanto surge a necessidade de se
definir de forma adequada o grau de aumento do limite de profundidade, valor este
que dependente dos recursos computacionais disponíveis e do problema específico a
ser analisado [16].
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
24
Instituto Superior de Engenharia do Porto
Capítulo 3 – Sistemas Inteligentes em Jogos
Figura 2 – Busca em profundidade
Algoritmo recursivo: Busca em profundidade ([17])
1. Se o estado inicial é um estado de meta, sair e retornar sucesso.
2. Caso contrário, faça o seguinte até a sinalização de sucesso ou fracasso:
(a) Gere um sucessor, E, do estado inicial. Se não houver mais
sucessores, sinalize fracasso.
(b) Chame Busca em Profundidade com E como estado inicial.
(c) Se for retornado sucesso, sinalize sucesso. Caso contrário, continue
em ciclo explorando outros sucessores.
3.1.3 -
Busca bidirecional
Na busca bidirecional a busca é realizada de forma concorrente uma a partir do
estado inicial e outra do estado solução. Para cada uma das buscas a ser realizada,
pode-se adoptar uma estratégia diferente. É interessante notar que é preciso obter
operadores que realizem tanto o percurso de ida (à partir do estado inicial) quanto
de volta (partindo do(s) estado(s) final(is)). Além disso, deve ser possível verificar
rapidamente se um estado já foi analisado, para saber se já foi encontrada ou não
solução foi encontrada. Esta forma de busca requer que sejam conhecidos de
antemão os estados solução, informação que em alguns casos pode não estar
disponível [16].
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
25
Instituto Superior de Engenharia do Porto
3.1.4 -
Capítulo 3 – Sistemas Inteligentes em Jogos
Busca de custo uniforme
Na busca de custo uniforme cada arco possui um custo dado por uma função g(n), e
é escolhido sempre o nó de menor custo total acumulado até o momento para ser
explorado. Assim, a busca de custo uniforme é similar à busca em largura, com
profundidade igual ao último custo total calculado.
A busca de custo uniforme também garante que uma solução seja encontrada, e
ainda
garante
que
esta
solução
será
óptima,
caso
um
caminho
seja
monotonicamente crescente. Entretanto, a busca de custo uniforme continua a
apresentar os mesmos problemas que a busca em largura em relação ao seu custo
computacional.
3.1.5 -
Busca heurística
Na busca heurística procura-se associar a cada arco (ligação entre dois nós) um
custo determinado por uma função heurística, que determina a distância do nó até
uma solução. A estratégia mais simples baseada em heurística consiste em realizar
uma busca egoísta, na qual segue-se sempre o nó (obtido através da função
heurística h(n)) que se julga mais próximo do objectivo.
No entanto, tal estratégia não garante nem a solução óptima nem garante que seja
encontrada uma solução.
Para melhorar a busca egoísta descrita acima pode-se aliar a esta busca à busca por
custo uniforme, que apesar de ser ineficiente, garante resultados óptimos. O
algoritmo A* [1] é o resultado dessa união, sendo razoavelmente eficiente, e
garantindo resultados óptimos para funções h(n) adequadas.
A estratégia A* trabalha de forma similar à busca de custo uniforme, com a diferença
que a função para determinação do próximo nó a ser explorado é dada por:
onde g(n) é o custo total do estado inicial ao estado corrente, e h(n) é o custo
estimado até um estado final escolhido. A função f(n) representa o custo estimado
da solução de menor custo do estado inicial até a solução (nó final), passando pelo
nó n.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
26
Instituto Superior de Engenharia do Porto
Capítulo 3 – Sistemas Inteligentes em Jogos
Como referido acima, o algoritmo A* garante a obtenção de uma solução óptima.
Além disso, o algoritmo é optimamente eficiente, isto é, nenhum outro algoritmo que
obtenha uma solução óptima garantidamente explora menos nós que o A*.
Apesar disso o A* possui algumas limitações, a sua complexidade é exponencial, e o
algoritmo pode consumir rapidamente grandes volumes de armazenamento uma vez
que precisa guardar todos os nós explorados.
Para atenuar este problema foi criado o Iterative Deepening A* (IDA*) – A* iterativo
com níveis de corte – que usa o algoritmo A* até um valor fixo de f(n), valor este
que aumenta iterativamente. Este algoritmo é usado para evitar a exploração de
caminhos que podem vir a contribuir apenas para tornar a pesquisa mais demorada.
Assim, para o IDA* define-se um patamar de custo, ou seja, só se aceita uma
solução com um custo inferior ou igual ao desse patamar. Sempre que a soma g + h
for superior ao patamar, então rejeita-se esse caminho. Se no final não houver
solução então aumenta-se o valor do patamar.
O processo repete-se até que seja encontrada uma solução. Deste modo as
preocupações na criação do IDA* foram no sentido de poupar memória durante a
pesquisa. O IDA* não garante que se possa voltar a qualquer nó que ficou para trás
e há problemas que este não consegue resolver.
Neste seguimento, surge outro algoritmo que procura corrigir alguns problemas
presentes com o IDA*. Este é o Simplified memory-bounded A* (SMA*). Necessita
de mais memória que o IDA*, mas usa menos memória que o A* puro.
Resumidamente o IDA* pode ser óptimo, completo e optimamente eficiente, dados
certos requisitos de memória.
De notar ainda que o A* e suas variantes constituem actualmente os algoritmos mais
utilizado nos jogos para resolver problemas de determinação de caminho em
ambientes bidimensional e tridimensional. [16]
3.2 -
Análise de algoritmos de busca
As perguntas que poderão ser levantadas, nesta altura quanto as técnicas de busca
anteriormente referidas são: Será que são boas e eficientes? Será que as soluções
fornecidas são óptimas? Tradicionalmente, o que se faz é codificar os algoritmos,
processá-los no computador e observar o seu comportamento em alguns problemas
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
27
Instituto Superior de Engenharia do Porto
Capítulo 3 – Sistemas Inteligentes em Jogos
e assim verificar o seu desempenho. Isto contrasta com algumas outras áreas da
ciência da computação, onde se dá maior ênfase a análise matemática dos
algoritmos. Em outros casos faz-se uma análise estatística do desempenho do
algoritmo após terem sido efectuados testes tendo em conta um conjunto de
problemas cuidadosamente escolhidos. Os especialistas dão duas razões para o
processo de análise dos algoritmos serem feitos desta maneira:
™ É mais estimulante ver o funcionamento do programa e assim visualizar o seu
desempenho na prática do que provar teoricamente que o programa tem
capacidades para fazer algo.
™ Os domínios de problemas da IA são suficientemente complexos para impedir
que se produza uma prova analítica convincente de que um procedimento
funcionará. Muitas vezes nem é possível descrever a gama de problemas de
modo a tornar significativas as análises estatísticas do comportamento do
programa.
Segundo a referência [1] esta segunda razão é de extrema importância. Devido a
complexidade das estruturas usadas para o conhecimento a maior parte dos
programas de IA torna-se praticamente impossível a análise matemática dos
programas dos programas.
A referência também salienta a importância de se ter como prioridade principal
manter as questões de desempenho sempre em primeiro lugar ao se pensar em
projectar aplicações que utiliza algoritmos e técnicas de busca. Deve-se ter em
mente sempre estas questões mesmo que não seja possível cumpri-las com
exactidão.
Uma das análises mais importantes, embora desmoralizante, do processo de busca é
o facto de o número de nós numa árvore de busca completa, de profundidade D e de
ramificação F ser FD. Esta análise leva a dois pontos importantes:
™ Necessidade de aperfeiçoar o procedimento de busca exaustiva, pois um
processo
cujo
tempo
de
busca
cresce
exponencialmente
não
é
computacionalmente viável.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
28
Instituto Superior de Engenharia do Porto
Capítulo 3 – Sistemas Inteligentes em Jogos
™ Necessidade de estabelecer um limite superior para o tempo de busca que
será gasto, de modo a que seja possível comparar melhoramentos propostos
num procedimento de busca exaustiva.
Existem várias maneiras de proceder que são melhores do que uma busca exaustiva.
Elas podem ser divididas em três classes, de acordo com os principais problemas
colocados por cada uma delas.
™ Métodos gerais que tenham a garantia de encontrar uma resposta tão boa
como a que seria encontrada pela busca exaustiva, mas em menos tempo.
Qual o método mais rápido que se pode encontrar nesta área?
™ Métodos que poderão levar tanto tempo quanto a busca exaustiva nalguns
problemas, mas que operam bem mais rápido para a maior parte dos
problemas mais comuns. Que velocidade esperar para que tais métodos
processem um conjunto de problemas?
™ Métodos que poderão encontrar uma solução pior do que a que seria
encontrada pela busca exaustiva. Para obter essa resposta dentro de algum
tempo desejado, quanta discrepância poderá haver entre a solução que se
encontrou e a melhor solução? [1]
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
29
Instituto Superior de Engenharia do Porto
Capítulo 3 – Sistemas Inteligentes em Jogos
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
30
Capítulo 4
O Algoritmo MiniMax e alguns refinamentos
Este capítulo descreve o algoritmo MiniMax, um dos algoritmos mais utilizados em
jogos de tabuleiro (xadrez e damas) e também algumas variantes do mesmo
algoritmo. Este algoritmo se baseia na busca de uma solução numa árvore de
jogadas possíveis, sendo que a profundidade da árvore poderá ser elevada ou não de
acordo com as possibilidades de jogo. A aridade dos nós poderá ser variável de
acordo com as possibilidades de jogada numa determinada posição. Além da
descrição dos algoritmos iremos fazer uma análise do desempenho do mesmo
algoritmo, requisitos de memória e computacionais que exige, algumas vantagens e
desvantagens. Por fim faremos uma avaliação deste algoritmo, com respeito a
implementação do agente inteligente que terá que ser desenvolvido neste projecto.
4.1 -
Descrição do algoritmo MiniMax
Este algoritmo é muito usado em teoria dos jogos, apesar de poder ser usado em
muitas outras situações onde se pode supor a existência de um jogador e um ou
mais adversários. Este é muito usado quando se pretende tomar decisões sobre que
estratégias e tácticas usar para se defender de ataques dos inimigos ou
concorrentes.
O MiniMax [1] é um procedimento de pesquisa em profundidade limitada. A busca é
feita numa árvore de movimentos possíveis, onde supomos que em níveis alternados
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
31
Instituto Superior de Engenharia do Porto
Capítulo 4 – O Minimax e alguns refinamentos
tentaremos maximizar a probabilidade de vencer, enquanto o adversário tentará
minimizar a probabilidade de ganharmos o jogo.
Este algoritmo parte do principio de que o jogador efectua sempre a jogada que
maximiza o seu próprio ganho enquanto que o adversário jogará sempre a jogada
que minimiza o ganho do outro.
O acto de jogar pode ser visto como sendo o desenvolvimento de uma árvore onde
os nós representam estados do jogo e os ramos representam jogadas possíveis. Os
ramos poderão ter associado um peso que ajudará na escolha de qual a melhor
jogada a efectuar em determinado instante. A figura 3 mostra de uma forma clara a
ideia do procedimento.
Os níveis onde há uma maximização dos pesos dos nós filhos correspondem as
nossas jogadas e os níveis onde há uma minimização correspondem as jogadas do
adversário. De acordo com o peso1 dos nós, que corresponde ao valor de uma
determinada jogada, decide-se qual a melhor sequência de jogadas que deve ser
efectuado para obter vantagens sobre o adversário.
O procedimento MiniMax consiste no seguinte:
Partindo da posição actual (neste caso a raiz da árvore), usa-se um gerador de
movimentos que produz o conjunto de posições sucessoras possíveis. Poderia se
aplicar uma função de avaliação estática a cada posição e escolher a posição que
apresenta a melhor avaliação. Retorna-se esse valor de avaliação a posição inicial de
busca como forma de representar a avaliação feita do nó.
A posição actual é tão importante quanto a posição gerada como melhor movimento
a executar a seguir. Assume-se que a função de avaliação estática retorna valores
altos para indicar situações favoráveis, assim a meta a atingir será maximizar o valor
da função de avaliação estática na próxima posição do tabuleiro.
1
Valor calculado sempre com relação ao jogador em questão.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
32
Instituto Superior de Engenharia do Porto
Capítulo 4 – O Minimax e alguns refinamentos
Figura 3 - Método MiniMax
Uma vez que a função de avaliação estática não é totalmente precisa por ser uma
avaliação feita apenas a um nível de profundidade. Esta avaliação apenas uma
jogada a frente não dá garantias de que a meta estipulada que é ganhar o jogo será
atingida. Desta forma a busca deveria continuar para além de uma jogada e poder
obter resultados mais satisfatórios. Isto pode ser muito importante, por exemplo, em
jogos de tabuleiro tais como o xadrez, as damas, e também no caso do Dvonn.
Falando directamente do Dvonn consideremos o que acontece numa jogada.
Após o movimento de uma peça, a situação poderá parecer favorável, mas se
analisar um movimento a frente, vê-se que a escolha não foi realmente boa porque
se calhar já não existem hipóteses de jogadas válidas ou a jogada que o adversário
possa fazer faça com que se perca o jogo. Portanto a situação não era tão favorável
quanto parecia. Assim é útil e prudente olhar e analisar o que acontecerá com cada
uma das novas posições no movimento a ser feito a seguir pelo adversário. Desta
maneira teoricamente quando maior for a profundidade de visualização melhor serão
as hipóteses de ter sucesso na escolha das jogadas. Como refere a referência, a
avaliação dos nós apenas usando os valores da função estática (de forma directa)
deixa de fazer sentido. Será preciso a partir daqui explorar as ramificações dos nós.
Isso é possível por usar um gerador que vai gerando um conjunto de nós sucessores
de um nó inicial até uma profundidade predefinida. Depois de atingir essa
profundidade então aplica-se a função de avaliação estática para se saber qual o
estado do jogador nesse estado do tabuleiro [17].
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
33
Instituto Superior de Engenharia do Porto
Capítulo 4 – O Minimax e alguns refinamentos
Figura 4 – Busca numa árvore uma e duas posições a frente [1]
Na figura 4 pode-se ver melhor qual a diferença entre avaliar uma jogada um nível a
frente (alínea a da figura) e dois níveis a frente (alínea b da figura).
Pode-se ver na alínea b que a tomada de decisão na escolha da jogada é feita tendo
em conta a jogada que o adversário poderá efectuar a seguir a nossa. Em cada nó
temos um peso que nos ajudará a tomar decisões de qual a melhor jogada.
Suponha que se jogue o movimento B. Então o adversário terá que escolher entre os
movimentos E, F e G. O objectivo do adversário é minimizar o valor da função de
avaliação, assim é de esperar que escolha o movimento F. De acordo com os valores
apresentados na Figura 4b, se efectuarmos o movimento B, então após a jogada do
adversário (F), estaremos numa posição muito desfavorável. Apesar da posição E a
primeira vista representar um valor bom para nós, contudo será ruim para nós após
a jogada do adversário.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
34
Instituto Superior de Engenharia do Porto
Capítulo 4 – O Minimax e alguns refinamentos
Como se pode ver na Figura 4c, em resultado de uma análise dois níveis a frente,
passam a existir novos valores para A, B, C e D. Estes valores foram escolhidos
tendo em conta que o jogador maximiza os seus ganhos e o adversário minimiza o
ganho do jogador.
Portanto, uma vez retornados os valores da segunda jogada, fica claro que o
movimento correcto nesse primeiro nível, dadas as informações que se tem
disponíveis, é C, já que não há nada que o adversário possa fazer para produzir um
valor pior que -2.
Tendo em conta o exemplo apresentado na figura 4 vê-se que quanto maior for a
nossa capacidade de visão no jogo (ter uma visão dos ganhos e perdas uma, duas ou
n jogadas a frente), maior será a probabilidade de vencer o jogo, por escolher
jogadas que trarão benefícios a longo prazo. Contudo, este processo de escolha da
melhor jogada através de uma árvore precisa de algumas restrições. Até que
profundidade deve ser efectuada a busca, ou durante quanto tempo deve-se
continuar a busca para encontrar uma jogada boa?
De seguida será descrito de uma forma mais precisa os pontos essenciais a ter em
conta neste algoritmo.
A Referência [17] propõe um algoritmo genérico que é um procedimento recursivo
directo, e que toma por base dois procedimentos auxiliares, especifico do jogo que
está sendo jogado:
1. GERMOV(Posição, Jogador) – o gerador de movimentos que retorna uma lista
de nós que representam os movimentos que podem ser feitos por Jogador em
Posição. No caso do jogo Dvonn chama-se os jogadores pelo nome de WHITE
(w) e BLACK (b).
2. ESTÁTICA(Posição, Jogador) – a função de avaliação estática, que retorna um
número que representa a qualidade de posição do ponto de vista de Jogador.2
2
Em todos os exemplos apresentados (Figura 4b e 4c) foi assumido que todos os valores de ESTÁTICA
são do ponto de vista do jogador inicial (maximização). Porém, é mais fácil, na hora de definir o
algoritmo, que ESTÁTICA alterne as perspectivas, para que não seja preciso escrever procedimentos
separados para os dois níveis (jogador e adversário). É mais fácil modificar ESTÁTICA para essa
finalidade. Simplesmente calculamos o valor de Posição do ponto de vista de WHITE, depois invertemos o
valor caso o parâmetro de ESTÁTICA seja BLACK.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
35
Instituto Superior de Engenharia do Porto
Capítulo 4 – O Minimax e alguns refinamentos
Como em qualquer programa recursivo, um problema crítico com relação ao
desenvolvimento do procedimento MiniMax é quando parar a recursão e chamar a
função de avaliação estática. Há vários factores que podem influenciar essa decisão,
estes são:
™ Algum dos jogadores já ganhou?
™ Quantas jogadas já foram exploradas?
™ Qual a precisão desse caminho? Será que este é o ideal?
™ Quanto tempo nos resta?
™ Qual o grau de estabilidade dessa configuração?
Pretende-se que o procedimento MiniMax descrito anteriormente, efectue uma
procura profunda o suficiente e assumindo que o procedimento faz uma avaliação de
todos os factores referidos anteriormente, então retorna TRUE se a busca tiver de
ser interrompida ao nível corrente, ou FALSE nos casos contrários.
Para isso foi preciso criar a função PROFUNDO_O_SUFICIENTE com dois parâmetros
(Posição, Profundidade). Esta função ignora o parâmetro Posição e simplesmente
retorna TRUE caso o parâmetro Profundidade exceder o valor da constante de
interrupção.
Assumindo que o procedimento recursivo MiniMax retorna uma estrutura de dados
com o valor do caminho escolhido e o caminho em si, a seguir apresenta-se o
algoritmo descrito pela mesma referência [17].
O Algoritmo MiniMax
MiniMax(Posição, Profundidade, Jogador)
1. Se PROFUNDO_O_SUFICIENTE(Posição, Profundidade), então retorna a
estrutura
VALOR = ESTATICA(Posição, Jogador)
CAMINHO = nil
2. Caso contrário, gere mais uma camada da árvore chamando a função
GERMOV(Posição, Jogador) e atribuindo a SUCESSORES a lista que ela
retornar.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
36
Instituto Superior de Engenharia do Porto
Capítulo 4 – O Minimax e alguns refinamentos
3. Se SUCESSORES estiver vazio, então não há nenhum movimento a fazer.
Retorne a mesma estrutura em 1.
4. Se SUCESSORES não estiver vazio, então examine cada elemento e
mantenha o registro do melhor. Inicialize MELHOR_CONTAGEM com o valor
mínimo que ESTATICA consiga retornar. Ele será actualizado para reflectir o
melhor valor que pode ser atingido por qualquer elemento de SUCESSORES.
Para cada SUC de SUCESSORES, faz-se o seguinte:
(a) Atribua a RESULTADO_SUC
MiniMax(SUC,Profundidade + 1,OPOSTO(Jogador))3
Esta chamada recursiva na verdade executará a exploração de SUC.
(b) Atribua a NOVO_VALOR – VALOR (RESULTADO_SUC). Isto reflectirá os
méritos da posição do ponto de vista oposto ao do próximo nível mais
abaixo.
(c) Se NOVO_VALOR > MELHOR_CONTAGEM, então encontra-se um
sucessor melhor que qualquer outro que já tenha sido examinado até
ao momento.
i. Atribua a MELHOR_VALOR NOVO_VALOR
ii. O melhor caminho conhecido agora é de CORRENTE para SUC e
depois para o caminho apropriado abaixo de SUC, conforme
determinada pela chamada recursiva MiniMax. Portanto, atribua
a MELHOR_CAMINHO o resultado da inclusão de SUC à frente
de CAMINHO(RESULTADO_SUC).
5. Agora que todos os sucessores foram examinados, sabe-se o valor de Posição
e também do caminho que deve ser seguido para chegar a esse parâmetro.
Então retorne a estrutura
VALOR = MELHOR_CONTAGEM
CAMINHO = MELHOR_CAMINHO
Quando a chamada do procedimento retornar, o melhor movimento de Posição4 é o
primeiro elemento de CAMINHO (Lista com a sequência de jogadas).
3
Usamos a função ESTÀTICA do ponto de vista do jogador (maximização).
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
37
Instituto Superior de Engenharia do Porto
Capítulo 4 – O Minimax e alguns refinamentos
Este procedimento MiniMax que foi descrito é muito simples, mas o seu desempenho
pode
ser
significativamente
melhorado.
Alguns
desses
melhoramentos
serão
descritos a seguir.
4.2 -
Cortes ALFA-BETA
Sendo o MiniMax um procedimento de busca em profundidade normalmente usa-se
como critério de paragem da busca um tempo. Quando esse tempo for atingido são
retornados valores para cada nó da árvore. Apresenta a vantagem de ser possível
melhor a sua eficiência através de técnicas de “ramificar-e-limitar”. Como isso são
descartados ramos da árvore ou até mesmo sub-arvores que apresentam um valor
pior que a solução conhecida. Para isso se usa dois limites um para cada jogador.
Estes valores limites são alfa e beta, sendo alfa o limite inferior que um nó
maximizante poderá receber em último caso e o beta o limite superior que o nó
minimizante poderá ter.
Para ilustrar a operação de cortes alfa-beta considere a figura 5. Nos níveis de
maximização apenas o beta é utilizado e nos níveis de minimização o alfa será
usado.
Para se fazer a busca na árvore A começa-se pela sub-arvore B. O valor que B
tomará será o correspondente ao mínimo entre os valores de D e E (nível de
minimização). Portanto o valor para B é 3. Sendo que A se encontra no nível de
maximização, então A terá um valor >= 3. Se alfa é o limite inferior de um nó
maximizante, então alfa é 3 (figura 6). Analisando agora a sub-arvore C, vê-se que
ao se examinar o nó M o I (nó de minimização) tomará valores <= 0, assim sendo o
máximo que poderá ter é 0. Isto quer dizer que F terá valores >= 0, ou seja,
garantidamente tem um mínimo de 0. Sendo este este valor inferior ao alfa
encontrado anteriormente (3) então nenhum outro ramo de I precisa ser
considerado. Portanto, o jogador maximizante sabe que não deverá fazer a jogada C,
e depois I porque a contagem resultante não será melhor que 0, e então escolhe a
jogada B que garante um mínimo de 3.
4
De notar que sempre que tomamos a decisão de chamar o procedimento definido, a raiz da árvore é
sempre a posição que queremos analisar, e assim o procedimento vai gerando uma seqüência de posições
sucessoras.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
38
Instituto Superior de Engenharia do Porto
Capítulo 4 – O Minimax e alguns refinamentos
O valor beta é usado para o jogador minimizante. Continuando a exploração da
árvore, passamos então ao nó J já que não é preciso explorar o outro ramo do nó I.
O J tem um valor 5, então F terá o valor 5 que é o máximo entre 0 e 5. Sendo que o
nó C é de minimização então este terá valores <= 5, ou seja, terá um valor máximo
de 5. E assim, de acordo com a descrição de beta que é o máximo entre os mínimos
possíveis que o nó poderá tomar, temos que beta é 5 no nó C (figura 7).
Expandindo agora o no G, passamos a analisar o nó K que tem um valor 7. Isto
significa que sendo G (nó de maximização) terá um valor >= 7. Ora, uma vez que no
nó C o jogador tentará minimizar. Comparando o valor 7 com beta (5) vemos que é
superior. Então não interessa explorar o outro ramo de G. Passamos a avaliar o H, e
tem o valor 4 que é inferior ao beta. Se o nó C tivesse mais ramos então o beta
passaria a ter o valor 4 e continuávamos a percorrer a árvore.
Figura 5 – Cortes Alfa e Beta [1]
Figura 6 – Corte usando o valor de Alfa
Figura 7 – Corte usando o valor Beta
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
39
Instituto Superior de Engenharia do Porto
Capítulo 4 – O Minimax e alguns refinamentos
Em suma, nos níveis maximizantes podemos eliminar logo um movimento se ficar
claro que seu valor será menor que o alfa actual, enquanto que nos níveis
minimizantes a busca será terminada se forem descobertos valores maiores que o
beta actual. De notar também que ao descartarmos um nó no nível maximizante,
então se o mesmo nó tiver ramos que derivam dele, então no nível de minimização
essas derivações do nó não serão consideradas, o que provoca uma melhoria muito
significativa em termos de desempenho no nosso algoritmo MiniMax [1][17].
A referência [17] propõe alguns acréscimos ao algoritmo MiniMax definido
anteriormente, originando assim um novo procedimento. Este passa a ter em vez de
três, cinco parâmetros sendo que os dois últimos são alfa e beta. Este procedimento
é usado tanto nos níveis de maximização como também nos níveis de minimização.
Como o procedimento é recursivo, então no nível de maximização é usado o beta
para determinar onde a busca deve ser interrompida e o alfa é usado na chamada
recursiva do procedimento MiniMax que depois será usado no nível a seguir. E no
nível de minimização só é usado o alfa para ver onde a busca deve ser interrompida
e beta neste caso apenas será usado para a chamada recursiva do procedimento.
Portanto, ambos os níveis precisam dos dois valores, um para ser usado na busca e
o outro para ser usado na passagem recursiva para o nível seguinte.
Este procedimento trata os níveis de maximização e minimização da mesma
maneira, invertendo apenas o sinal das avaliações sempre que há uma mudança de
nível. Para simplificar a compreensão do algoritmo, foram usados em vez da notação
alfa e beta, foram usados USAR-LIMITE (valor a ser usado para a interrupção da
busca) e PASSAR-LIMITE (valor que apenas será usado para a chamada recursiva).
Na chamada recursiva, os valores USAR-LIMITE e PASSAR-LIMITE serão trocados
devido a mudança de nível.
O Algoritmo MiniMax com cortes alfa e beta
MiniMax-A-B(Posição, Profundidade, Jogador, Usar-Limite, Passar-Limite)
1. Se PROFUNDO_O_SUFICIENTE(Posição, Profundidade), então retorna a
estrutura
VALOR = ESTATICA(Posição, Jogador)
CAMINHO = nil
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
40
Instituto Superior de Engenharia do Porto
Capítulo 4 – O Minimax e alguns refinamentos
2. Caso contrário, gere mais uma camada da árvore chamando a função
GERMOV(Posição, Jogador) e atribuindo a SUCESSORES a lista que ela
retornar.
3. Se SUCESSORES estiver vazio, então não há nenhum movimento a fazer.
Retorne a mesma estrutura em 1.
4. Se SUCESSORES não estiver vazio, então examine cada elemento e
mantenha o registro do melhor.
Para cada SUC de SUCESSORES, faremos:
(a) Atribua a RESULTADO_SUC
MiniMax-A-B(SUC, Profundidade+1,OPOSTO(Jogador),
- Passar-Limite, - Usar-Limite)
(b) Atribua a NOVO-VALOR – VALOR (RESULTADO_SUC)
(c) Se NOVO_VALOR > Passar-Limite, então encontramos um sucessor
melhor do que qualquer outro examinado até ao momento. Registre o
facto fazendo o seguinte:
i.
Atribua Passar-Limite – NOVO_VALOR
ii.
O melhor caminho conhecido agora é de CORRENTE para
SUC e depois para o caminho apropriado, conforme
determinada
pela
chamada
recursiva
MiniMax-A-B.
Atribua a MELHOR_PERCURSO o resultado da inclusão
de SUC à frente de CAMINHO (RESULTADO_SUC).
(d) Se Passar-Limite (refletindo o melhor valor actual) não for melhor que
Usar-Limite, então deveremos parar de examinar essa ramificação.
Mas tanto os limites quanto os valores foram invertidos. Portanto, se
Passar-Limite = Usar-Limite, então retorne imediatamente com o valor
VALOR = Passar-Limite
CAMINHO = MELHOR-CAMINHO
5. Retorne a estrutura
VALOR = Passar-Limite
CAMINHO = MELHOR_PERCURSO
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
41
Instituto Superior de Engenharia do Porto
4.3 -
Capítulo 4 – O Minimax e alguns refinamentos
Desvantagens do MiniMax
A referência [17] propõe mais uma série de melhoramentos, que permite melhorar o
desempenho do procedimento MiniMax. Contudo, sabe-se que em jogos complicados
é praticamente inexeqüível olhar para o jogo como um todo e analisar a configuração
actual do jogo e conseguir extrair qual o movimento correcto. É impossível construir
um catalogo que consegue manter as informações necessárias para se tomar as
decisões de que jogada fazer em determinado momento. Para estes tipos de jogos a
referencia aconselha usar “movimentos de livros” que é uma lista com os
movimentos que poderão ser feitos na abertura e no encerramento do jogo. A meio
do jogo aconselha-se o uso do procedimento MiniMax. Esta combinação produzirá
melhores resultados do que aplicar cada uma das técnicas isoladamente.
Apesar de serem possíveis estes melhoramentos já referidos, ainda assim pelo facto
do MiniMax ser um algoritmo de profundidade, portanto apresenta as mesmas
desvantagens que qualquer procedimento de busca em profundidade como referido
no capitulo anterior.
E ainda mais do que isso é o facto do procedimento se basear fortemente na
suposição de que o adversário escolhe sempre o movimento ideal, ou seja, que
escolhe a jogada que minimiza os nossos ganhos. Tal suposição só é aceitável em
caso de vitória em que o jogador pode encontrar uma jogada que realmente é boa
para ele. Em caso de derrota poderá ser melhor arriscar que o adversário cometerá
um erro. Para ilustrar isso podemos considerar um caso em que temos duas jogadas
possíveis ambas ruins para nós, sendo uma delas mais desfavorável que a outra.
Podemos supor que o movimento menos promissor poderá ser bom para nós se o
jogador cometer um erro. Contudo, o MiniMax nunca o escolheria, mas sim o outro
que apresenta um valor melhor. Mas nós se calhar arriscaríamos a escolher o pior
movimento contando que o jogador poderá errar e assim tirarmos ganho. Existem
várias situações que fazem com que o MiniMax tenha uma base teórica bastante
fraca. Além do mais alguns entendidos da matéria demonstraram que em certas
árvores de jogos, quanto mais profunda for a busca piores serão os resultados
obtidos pelo MiniMax.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
42
Instituto Superior de Engenharia do Porto
4.4 -
Capítulo 4 – O Minimax e alguns refinamentos
Jogos implementados usando o MiniMax
A maioria dos jogos de tabuleiro como é o caso do Xadrez e as Damas
implementados em computador usam o algoritmo MiniMax. Nestes tipos de jogos há
um balanceamento entre o conhecimento e a busca, ou seja, não há um equilíbrio
entre o conhecimento e a busca. Quanto maior for o nível de conhecimento que um
programa tiver menor será a busca exigida. E o mesmo acontece com a busca, se
tivermos um nível bastante elevado então praticamente não precisaremos de
conhecimento. A distinção que se faz entre os humanos e um programa de
computador é que enquanto os humanos têm limitações quanto a busca em
profundidade,
estes
apresentam
bastante
conhecimento.
Um
programa
de
computador ao contrario do homem tem a capacidade de efectuar uma busca mais
profunda e exaustiva na árvore de jogadas, não sendo necessário então ter muitos
conhecimentos.
O conhecimento que este tem se limita a uma função de avaliação estática. Essa
tendência para programas baseados essencialmente em busca com força bruta
permite maior rapidez nos movimentos. Para a obtenção de níveis bastante elevados
basta efectuar uma busca profunda e com cortes.
O HITECH e o DEEP THOUGTH são exemplos de máquinas que derrotaram grandes
mestres humanos e ambos usam hardware paralelo feito sob medida para acelerar a
geração de movimentos válidos e a avaliação heurística das jogadas. Nas Damas
também existem programas para jogar esse mesmo jogo, sendo que o primeiro
programa foi desenvolvido por Arthur L. Samuel (IBM) em 1963. O programa tinha
um componente de aprendizagem que permitia que o desempenho da máquina fosse
aumentando com a experiência. O próprio programa derrotou o próprio criador. [17]
A referencia [21] fala também de um programa desenvolvido recentemente o DEEP
BLUE. Este foi desenvolvido por uma equipa de 6 programadores. Esta maquina
conseguiu vencer o maior jogador de xadrez vivo, Gary Kasparov. Mais uma vez a
provar que a inteligência artificial é uma área muito importante na ciência.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
43
Instituto Superior de Engenharia do Porto
Capítulo 4 – O Minimax e alguns refinamentos
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
44
Capítulo 5
Implementação de um agente inteligente para o
Dvonn
Este capítulo se destina à implementação do agente proposto para este projecto.
Depois de estudar a pesquisa bibliográfica é hora de decidir como implementar o
agente e que caminho seguir. Se implementar o MiniMax ou escolher outro caminho.
Neste capítulo falaremos essencialmente das regras do jogo, de seguida faremos
uma breve descrição do problema a resolver, como foi estruturado a aplicação, como
foi implementado.
5.1 -
Regras do Dvonn
As regras do jogo que serão descritas nesta secção encontram-se no site do Dvonn
http://www.gipf.com/Dvonn/.
O Dvonn é um jogo entre dois jogadores, sendo que para este trabalho teremos
apenas um jogador que jogará contra o computador, que será um agente inteligente.
Esse jogo é composto pelos seguintes componentes: o tabuleiro, 3 peças Dvonn
vermelhas, 23 peças brancas e 23 peças pretas.
O objectivo do jogo consiste em controlar o maior número possível de peças
empilhando ou amontoando as peças umas em cima das outras, tentando sempre
manter contacto com as peças Dvonn vermelhas. Quando mais nenhuma jogada
poder ser efectuada, o jogador que controla o maior número de peças ganha o jogo.
Estas regras do jogos se encontram descritas na referência.
Para iniciar o jogo, escolhe-se à sorte qual o jogador que começará o jogo, neste
caso, se é o agente ou o adversário. O primeiro jogador é o jogador que terá a cor
branca e fica com duas peças Dvonn e o segundo jogador fica com uma peça Dvonn.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
45
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
Portanto, as peças brancas ficam para o primeiro jogador e as pretas para o
segundo.
O tabuleiro deve ser colocado entre os dois jogadores de maneira a que cada jogador
tenha a sua frente 9 lugares (A – I).
O jogo está dividido em duas fases, sendo que na primeira fase cada jogador
alternadamente vai colocando as peças (uma a uma) pelas posições livres no
tabuleiro, e a segunda fase o jogo em si.
Fase 1 – Colocação das peças no tabuleiro
™ O jogo começa com o tabuleiro vazio. Alternadamente, cada um dos
jogadores, coloca uma peça no tabuleiro até estarem todas as peças no
tabuleiro. As peças Dvonn são as primeiras a serem colocadas no tabuleiro e
só depois as peças da própria cor como mostra o exemplo a seguir.
Branco: primeira peça Dvonn
Preto: segunda peça Dvonn
Branco: terceira peça Dvonn
Preto: primeira peça preta
Branco: primeira peça branca
Preto: segunda peça preta ...
™ As peças Dvonn são neutras, enquanto estiverem no tabuleiro não pertencem
a qualquer dos jogadores.
™ Uma peça pode ser colocada em qualquer espaço livre, sem restrições.
™ Quando todas as peças estiverem colocadas no tabuleiro, não haverá espaços
livres no tabuleiro e assim termina a primeira fase.
Fase 2 – Empilhamento de peças
™ Nesta fase o jogador que terminou a fase anterior, é o primeiro a jogar ou seja
o jogador que tiver a peça branca é o primeiro a jogar. As jogadas dos
jogadores são efectuadas de forma alternada.
™ Os jogadores só podem jogar com peças da sua própria cor. Quando duas ou
mais peças estão empilhadas em cima umas das outras a cor da peça do topo
determina de quem é a pilha, ou seja, qual o jogador que a pode mover.
™ Em cada turno, o jogador tem de mover uma peça ou uma pilha (se a peça
que se encontra no topo da pilha é da cor que pertence ao jogador). Uma
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
46
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
única peça pode mover-se um espaço em qualquer direcção, mas apenas para
um espaço ocupado. Após o movimento a peça ficará em cima de uma outra
peça ou pilha qualquer cor.
™ Uma peça ou pilha que está cercada por todos os 6 lados não pode ser movida.
A cor das peças e/ou pilhas vizinhas não tem qualquer importância. Assim, no
início do jogo apenas as peças da orla do tabuleiro podem ser movimentadas.
As peças que não estão posicionadas na orla permanecem bloqueadas
enquanto estiverem totalmente cercadas. Na Figura 8 as peças e as pilhas
marcadas com um “x” estão cercadas por todos os 6 lados e não podem ser
movidas.
Figura 8 - Peças no tabuleiro que não podem ser movidas
™ Um movimento nunca pode terminar num espaço vazio (tem sempre que
terminar no topo de uma peça ou pilha, de qualquer cor e que pode ser um
Dvonn), mas é permitido o movimento através de um ou mais espaços
vazios. Ao efectuar um movimento, cada espaço deve ser contado,
independentemente de estar vazio ou ocupado (Figura 9).
™ Uma pilha tem sempre que ser movida como um todo e move-se tantos
espaços quantas as peças existentes na pilha (independentemente das suas
cores). Por exemplo, uma pilha de 3 peças tem que ser movida 3 espaços. Tal
como uma peça única, uma pilha pode ser movida em qualquer direcção, mas
sempre em linha recta e tem que terminar sempre num lugar que esteja
ocupado Figura 9.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
47
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
Figura 9 - Movimento das peças
™ Uma peça Dvonn não pode ser movida, mas uma peça ou pilha pode ser
movida para cima dela. Quando uma peça Dvonn é parte de uma pilha,
pode-se mover a pilha contendo a peça Dvonn, mas, como explicado acima,
apenas pelo jogador que controla a pilha.
™ Não se pode passar a vez de jogar ao adversário, a não ser que o jogador
não tenha hipótese de jogadas válidas.
Perda de Peças
™ Todas as peças e pilhas devem permanecer de algum modo em contacto com
pelo menos uma peça Dvonn. Em contacto significa que deve sempre existir
um elo (directamente ou através de outras peças) com pelo menos uma peça
Dvonn. Qualquer peça e/ou pilha que não tenha ligação a uma das peças
Dvonn, tem de ser imediatamente removida do tabuleiro. Assim, pode
acontecer que um grande número de peças e pilhas sejam subitamente
removidas, como resultado de um simples movimento. Considere o exemplo
na Figura 10. Se a peça branca fizer o movimento indicado, todas as peças à
esquerda perderão o contacto com uma peça Dvonn. Terão que ser todas
removidas do tabuleiro.
Figura 10 - Perda de peças
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
48
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
™ Não importa quem faz o movimento que origina a separação das peças e/ou
pilhas com as peças Dvonn. Todas as peças e/ou pilhas isoladas seja de um
ou do outro jogador são removidas do tabuleiro. Este é um facto a ter em
atenção, especialmente no fim do jogo, uma vez que não se pode passar a
vez para o adversário, pode acontecer que um jogador isole uma ou mais das
suas peças/pilhas devido a um movimento que é obrigado a fazer (Figura 11).
Figura 11 – Fim do jogo
™ As 3 peças Dvonn permanecem em jogo até ao fim do jogo. Embora as peças
Dvonn possam ser movidas quando incluídas numa pilha, elas continuam a
ter a propriedade de manter as peças em jogo. Como se pode ver na Figura
11 é a vez do jogador com a cor branca jogar mas, este tem apenas uma
hipótese de jogada válida (mover a pilha com a peça Dvonn para a posição
indicada). Portanto o jogador é obrigado a efectuar essa jogada por não ter
outra escolhao que provoca a eliminação das pilhas marcadas com um “x”.
Fim do Jogo
™ Os jogadores devem jogar enquanto lhes for possível fazê-lo. Se um jogador
não tiver hipóteses de jogadas válidas, o outro continuar a jogar até que
tenha efectuado a sua última jogada possível. No caso raro, de um jogador
que, sendo obrigado a passar a vez ao adversário, consegue mais tarde uma
oportunidade de se mover, ele é obrigado jogar.
™ O jogo termina assim que a última jogada for efectuada. Quando esta fase é
alcançada, o jogador que controla o maior número de peças ganha o jogo. Os
dois jogadores empilham as peças e pilhas que controlam no final do jogo, o
jogador com a maior pilha, tem mais peças e, portanto ganhou! Se ambos os
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
49
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
jogadores terminarem com uma pilha igual, então o jogo termina num
empate.
5.2 -
Descrição do Problema a resolver
Pretende-se um agente com certas capacidades de inteligência, e que seja capaz de
tomar decisões de jogada mediante a avaliação do estado do tabuleiro e das jogadas
do adversário.
Na Internet existem servidores de jogos onde qualquer pessoa pode conectar-se e
escolher o jogo que quer jogar. O jogador escolhe se quer jogar com um adversário
humano ou com o computador (neste caso activa-se o agente inteligente). Após isso,
o servidor prepara as coisas para se começar a jogar. Um dos passos que o servidor
supostamente terá que fazer é gerar um tabuleiro, e enviar a cada jogar um ficheiro
com a informação contida no tabuleiro.
Cada jogador (aplicação que funciona de jogador) internamente efectua as
actualizações necessárias no ficheiro correspondente ao tabuleiro. Estas alterações
só são efectuadas aquando há confirmação de uma jogada. O servidor após aceitar
uma jogada como válida, envia aos participantes a informação de confirmação com
os elementos necessários para se fazer a referida actualização.
Esta politica é boa porque, tendo em conta que o servidor se encontra na Internet
então poderá estar em qualquer ponto do globo e os participantes também. De modo
que facilita muito a operação uma vez que o servidor não tem que estar sempre a
enviar aos participantes o ficheiro com os alterações do tabuleiro o que se torna
bastante pesado para o proprio servidor. É mais facil haver uma confirmação de
aceitação de uma jogada por parte do servidor e a própria aplicação dos dois lados
dos participante efectuarem as respectivas actualizações aos seus ficheiros.
O servidor como é óbvio também tem que actualizar o seu ficheiro com a informação
sobre o tabuleiro. Este poderá ter que controlar vários jogos (o servidor tem vários
jogos disponíveis e várias pessoas a jogar o mesmo tipo de jogo) por isso cada jogo
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
50
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
tem uma identificação e cada tabuleiro5 também tem uma identificação que permite
ao servidor controlar os jogos.
Assim sendo, o agente que se comporta como um jogador normal, receberá no inicio
do jogo um ficheiro com a informação sobre o tabuleiro gerado pelo servidor.
Podemos supor que o ficheiro se encontra em formato texto. Após isso também o
agente terá que receber do servidor uma cor (white ou black). Esta cor é gerada pelo
servidor e é ela que indica qual dos jogadores terá que começar a jogar. As regras
do jogos e como funciona se encontram anexadas no fim deste documento.
O agente terá que avaliar um conjunto de jogadas possíveis, calcular os beneficios
das mesmas jogadas, e no final escolher uma jogada. Será necessário definir
estratégias para a escolha das jogadas. O agente recebe do servidor alguma
informação de confirmação ou rejeição de uma jogada. Quando o servidor confirma
uma jogada, seja a jogada do agente ou do outro jogador, o agente actualiza a
informação do tabuleiro com a informação fornecida pelo servidor.
O mais importante nisso tudo é que além de implementar as regras do jogo é preciso
desenvolver estratégias e tácticas de jogada. Podemos aproveitar o raciocínio
utilizado no MiniMax e criar as nossas próprias estratégias.
5.3 -
Análise de espaço do problema
No inicio do jogo Dvonn cada jogador possui 23 peças para movimentar, sendo que
em média cada jogador terá 10 peças em condições de serem movimentadas, cada
uma das peça terá 3 ou 4 movimentos válidos nesta fase.
Desta maneira existem mais ou menos 30 jogadas possíveis para cada jogador.
Considerando um cálculo aproximado, cada jogador fará durante o jogo uma média
de 15 jogadas, então para os dois jogadores teremos 30 jogadas. Assim a árvore
completa de pesquisa terá aproximadamente 3030 nós para analisar. Ao longo do
jogo as hipóteses de jogada vão diminuindo a medida que os jogadores vão
perdendo peças o que significa que as ramificações vão diminuindo mas essa
5
Para cada instância de um jogo qualquer que o servidor gere, este terá que gerar também uma
identificação para o tabuleiro. Associada a identificação do tabuleiro o servidor guarda informações como:
dados sobre o tabuleiro, quem são os participantes, que tipo de jogo é, a informação das regras do jogo,
etc.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
51
Instituto Superior de Engenharia do Porto
diminuição não é fixa. Assim sendo,
Capítulo 5 – Implementação agente Dvonn
a abordagem “maciça” não se demonstrou
aplicável ao problema em questão. Note-se que o algoritmo implementado pelo
método MiniMax considera uma abordagem maciça com um nível de profundidade
máximo, por exemplo 8 jogadas, tendo-se optado por implementar uma abordagem
que considera tácticas e heurísticas para o jogo.
5.4 -
Estruturação do problema proposto
Analisar o jogo em si, é um problema comum da tomada de decisão num jogo
qualquer de tabuleiro. O processo de tomada de decisão subdivide-se em 3 níveis:
Estratégico, Táctico e Operacional como representado na pirâmide na Figura 12.
Figura 12 - Diferentes níveis de abstração no jogo Dvonn
Em cada um destes níveis existem informações diferentes e estruturas de
conhecimento também diferentes.
O nivel mais baixo é o nível operacional. Neste nível define-se a estrutura básica da
informação sobre o tabuleiro, define-se a forma de implementação das regras do
jogo e validações necessárias. Neste nível os objectivos são a nível de ganho de
peças e como podemos ver na segunda pirâmide neste nível existem apenas dados,
ou seja, a informação que temos não permite tirar conclusões quanto a que
movimentos efectuar. Essa informação não é apropriada para a tormada de decisões.
No nível a seguir, o táctico, os objectivos já são mais elaborados, já se associa
conceitos como de áreas. Pode-se definir como objectivo criar áreas sem Dvonn para
poder diminuir as hipóteses de jogada do adversário. Os objectivos para este nível já
é a nível de pilhas. Isolamento das pilhas do adversário, ganhar pilhas do adversário,
etc.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
52
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
Neste nível a qualidade de informação é muito melhor que no nível anterior e por
isso na pirâmide é considerado o nível da informação. Neste nível são implementadas
tácticas de jogo como forma de recolher o maior número possível de informação do
tabuleiro. De notar que essa informação é uma informação tratada com objectivo de
poder ajudar na tomada de decisão no nível superior.
O nível estratégico é o nível mais elevado e por isso de conhecimento. Este é o nivel
mais dificil de implementar. Neste nível já existe o conhecimento em si do jogo. Por
exemplo, que estratégias aplicar em cada situação. Existe a capacidade de
aprendizagem. Consegue-se perceber a jogada que o adversário irá efectuar por
estudar os seus movimentos efectuados anteriormente. Existe a capacidade de
induzir o adversário a fazer uma jogada que o leve a perder. Neste nível o
conhecimento é muito mais difícil de representar uma vez que teremos bastante
informação adquirida e torna-se necessário aceder a tais informações de forma
rápida e tomar decisões também de forma rápida. Também terá que existir métodos
muito bem elaborados que consiga recolher essas informações e efectuar as
melhores escolhas de jogada.
Neste projecto, pretende-se estudar e implementar os 3 níveis de tomada de
decisão.
Para
cada
nível
teremos
um
módulo
associado
onde
teremos
os
procedimentos necessários para cumprir com os objectivos definidos em cada um
destes níveis. Desta forma definiu-se a seguinte estrutura para a aplicação (Figura
13):
™ Agente inteligente;
™ Área de processamento de tomada de decisões;
™ O tabuleiro em formato texto que posteriormente será transformado num
facto dinâmico que guardará em memória a informação sobre o tabuleiro;
™ Um ficheiro de regras do jogo;
™ Um ficheiro de tácticas para o jogo;
™ Um ficheiro de estratégias para o jogo.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
53
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
Tabuleiro em
formato de texto
Estratégias
Tácticas
Agente
Main
Inteligente
Processamento
Regras
Operacional
Tabuleiro
Figura 13 – Organização dos ficheiros
Descrição dos Módulos
Agente inteligente
Este agente será a nossa aplicação em si, uma vez que todas as comunicações serão
feitas através dela. Cria-se o agente e este fica a espera de um pedido de ligação por
parte do servidor. Esta ligação ou conexão envolve não só o pedido de ligação mas
também após isso o servidor terá que enviar ao nosso agente inteligente um
identificador (servidor) e também o porto onde se encontra para futuras trocas de
informações. De notar que na fase do estabelecimento da ligação o servidor terá que
saber a localização do agente e assim ser possível efectuar a referida conexão.
O agente encontra-se programado para receber certas mensagens em específico,
sendo elas as seguintes:
id(servidor,Porto) – o servidor envia ao agente esta mensagem com o
identificador id e o primeiro parâmetro é um túpulo “servidor” e o
Porto
é
uma
variável
que
terá
o
valor
correspondente
ao
porto
do
Servidor.
cor(servidor,Cor) – após ser gerado o tabuleiro pelo servidor, este
terá que enviar ao agente esta mensagem onde a variável Cor corresponde
a cor com a qual o agente irá jogar.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
54
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
sua_vez – enquanto não receber esta mensagem do servidor não consegue
efectuar qualquer jogada garantindo que o agente não tentará jogar
quando não é a sua vez de jogar.
confirma_jogada(ID,(Col1,Lin1),(Col2,Lin2),Resposta)
-
quando
o
servidor recebe um pedido de jogada, o servidor avalia o pedido e dá
uma
confirmação
ao
emissor.
O
emissor
é
identificado
através
da
variável ID que pode ser “pc” (se for o agente inteligente) e “jogador”
(se for o adversário). A confirmação é recebida através da variável
Resposta que pode ser “aceite” ou “invalida”. Caso aceite a jogada,
então envia também ao outro jogador a mesma mensagem para que o jogador
ou o agente possa alterar o estado do seu tabuleiro.
Qualquer mensagem que o agente receba que não esteja neste formatos
especificados anteriomente não serão tratados.
Depois de o agente ter todas as informações necessárias para haver trocas de
mensagens entre este e o servidor, então podemos assim dizer que começa o jogo.
As jogadas serão feitas por trocas de mensagens entre o agente e o servidor. Mais
adiante será descrito mais pormenorizadamente o funcionamento do agente.
Área de processamento
Esta área como o proprio nome indica é uma área que se destina ao processamento
de todo o tipo de informação. Teremos aqui todos os predicados mais importantes.
Mais adiante será explicado mais em pormenor o raciocinio utilizado para o
desenvolvimento do agente.
Tabuleiro
Depois de receber o ficheiro de texto correspondente ao tabuleiro gerado pelo
servidor, o agente precisa tratar essa informação. Esta terá que ser transformada em
informação de fácil processamento pelo Prolog. Tendo em conta o formato do nosso
tabuleiro (Figura 14) definimos uma estrutura que seja de fácil percepção e
principalmente que permita uma melhor manipulação da informação pelo programa.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
55
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
Figura 14 – Tabuleiro Dvonn [19]
O tabuleiro tem 5 linhas de 1 a 5, e 11 colunas de A a K. Para tornar mais rápido o
acesso a informação existente no tabuleiro as colunas serão definidas de 1 a 11.
Criou-se o facto dinâmico tabuleiro/26 com dois parâmetros. O primeiro parâmetro
é a coluna (1 - 11) e o segundo é uma lista onde teremos a informação sobre as
linhas.
De notar que existem colunas que não têm 5 linhas, portanto para algumas colunas
teremos uma lista mais pequena. A lista com a informação sobre as linhas contém a
seguinte informação no formato (Linha, Cor, N_Peças, Dvonn). A variável Linha
identifica qual a linha em questão (1 - 5), a Cor corresponde a cor (poderá ser w, b,
d) da peça que se encontra no topo da pilha nessa posição, a variável N_Peças é o
número de peças que compõe a pilha e Dvonn é uma flag que tem o valor 0 ou 1
consoante a pilha tiver uma peça Dvonn ou não. Considere o exemplo da
representação do tabuleiro da Figura 14. Neste exemplo temos 11 predicados, cada
um com o seu identificador (coluna) de 1 a 11 e uma lista com as informações sobre
as linhas de cada coluna.
tabuleiro(1,[(1,w,1,0),(2,b,1,0),(3,w,1,0)]).
tabuleiro(2,[(1,b,1,0),(2,b,1,0),(3,b,1,0),(4,b,1,0)]).
tabuleiro(3,[(1,b,1,0),(2,w,1,0),(3,w,1,0),(4,b,1,0),(5,w,1,0)]).
tabuleiro(4,[(1,w,1,0),(2,b,1,0),(3,b,1,0),(4,d,1,1),(5,w,1,0)]).
tabuleiro(5,[(1,b,1,0),(2,b,1,0),(3,w,1,0),(4,w,1,0),(5,w,1,0)]).
tabuleiro(6,[(1,b,1,0),(2,w,1,0),(3,w,1,0),(4,b,1,0),(5,w,1,0)]).
tabuleiro(7,[(1,w,1,0),(2,b,1,0),(3,b,1,0),(4,d,1,1),(5,b,1,0)]).
tabuleiro(8,[(1,w,1,0),(2,w,1,0),(3,w,1,0),(4,b,1,0),(5,b,1,0)]).
tabuleiro(9,[(1,b,1,0),(2,w,1,0),(3,w,1,0),(4,b,1,0),(5,w,1,0)]).
tabuleiro(10,[(2,w,1,0),(3,w,1,0),(4,w,1,0),(5,b,1,0)]).
tabuleiro(11,[(3,b,1,0),(4,d,1,1),(5,b,1,0)]).
6
Em Prolog utiliza-se a notação nome_predicado/N onde N é o número de argumentos que o método
tem.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
56
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
A aplicação disponibiliza um predicado tabuleiro que desenha no ecrã o tabuleiro
existente em memória. Na Figura 15 pode-se ver que para cada posição do tabuleiro
(Coluna, Linha) existem 3 identificadores (atributos decisivos). Nas posições onde
não existe Dvonn o primeiro identificador é um ponto (.) e quando existe é um
asterisco (*). O segundo identificador é a cor que domina a pilha e pode ser um w, b
ou d (neste caso a pilha ainda não pertence a nenhum dos jogadores). O terceiro
identificador que também é importante corresponde ao tamanho da pilha, e é a
partir deste valor que o jogador sabe quantas posições poderá mover.
5
4
3
2
1
-
.w1 .w1 .w1 .w1 .b1 .b1 .w1 .b1 .b1
.b1 .b1 *d1 .w1 .b1 *d1 .b1 .b1 .w1 *d1
.w1 .b1 .w1 .b1 .w1 .w1 .b1 .w1 .w1 .w1 .b1
.b1 .b1 .w1 .b1 .b1 .w1 .b1 .w1 .w1 .w1
.w1 .b1 .b1 .w1 .b1 .b1 .w1 .w1 .b1
\
\
\
\
\
\
\
\
\
\
A
B
C
D
E
F
G
H
I
J
\
K
Figura 15 – Formato de apresentação do tabuleiro
Como nota queremos referir que estes 3 identificadores utilizados para fazer o
desenho do tabuleiro foram escolhidos tendo em conta que são informações
importantes para um jogador conhecer o estado do tabuleiro, quais as suas jogadas
válidas e também qual ao situação do seu adversário. Para isso é preciso localizar as
peças Dvonn e também saber quais as pilhas que poderá mover e as posições para
onde poderão mover.
Regras do jogo (nível operacional)
Este nível fornece o suporte básico e imprescindível aos níveis superiores. Para isso
contém métodos que serão utilizados para validar os movimentos ou jogadas dos
jogadores mediante a informação do estado do tabuleiro. Por exemplo, um jogador
que joga com a cor w não poderá movimentar uma pilha de cor b ou d. Outro
exemplo, uma pilha de tamanho 2 não poderá efectuar um salto de 1 ou 3. Na fase 2
não é possível efectuar movimentos para posições vazias, um jogador não pode
jogar quando não é a sua vez. Existem várias situações que terão de ser validadas
como descrito da secção 5.1 e isso tudo se encontra neste módulo.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
57
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
Tácticas de jogo (nivel tático)
Este ficheiro é destinado a implementação de algumas táticas para o jogo. Estas
táticas utilizam predicados que se encontra no módulo processamento e faz uma
conjunção delas de modo a se conseguir implementar as táticas propostas. As
tácticas são objectivos que o agente pretende atingir a curto prazo. Considera-se por
exemplo como objectivo a curto prazo fazer jogadas que dão mais beneficios
imediato ao agente.
Estratégias de jogo (nivel estratégico)
Neste módulo serão implementadas estratégias ou objectivos do agente a longo
prazo. Sendo este o nível mais elevado, não existirão muitos pormenores a nivel de
como implementar as estratégias e por isso os níveis mais baixos terão que fornecer
o suporte para a implementação das estratégias definidas. Por outras palavras, o
nível estratégico terá predicados simples que recorrem a outros predicados criados
nos níveis de baixo.
5.5 5.5.1 -
Implementação das regras do jogo
Validação das jogadas
A partir das instruções fornecidas na secção 5.1 é preciso definir formas de validar as
jogadas, formas de identificar as jogadas válidas possíveis do agente, como poderão
ser efectas as jogadas, etc. Desta maneira, criou-se o conceito de vizinho (Figura
16a), que corresponde as posições a volta de uma determinada posição. De salientar
que uma das régras expressa no documento em anexo é de que as pilhas que se
encontram completamente cercadas não poderão ser movidas (Figura 8). Atendendo
a Figura 16 verifica-se que cada posição tem no máximo 6 direcções para onde
poderá mover. Essas direcções estão numeradas de 1 a 6.
Vamos de seguida analizar o resultado de um movimento para cada uma das
direcções (Figura 16b).
Se quisermos mover a pilha P na direcção 1 da posição 1 para a posição 2 então
para determinarmos as “coordenadas” da posição 2, apenas a coluna irá variar,
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
58
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
mantendo-se a linha. Como foi referido aquando da criação do predicado tabuleiro/2,
a coluna é numerada de 1 a 11 facilitando assim a conta. Assim o resultado será
Coluna2 = Coluna1 – N_Peças (tamanho da pilha P a mover).
Na direcção 4 segue-se o mesmo raciocinio mas com a diferença de que em vez de
diminuir a coluna aumenta.
Nas direcções 2 e 5 mantem-se a coluna e as linhas aumentam e diminuem N_Peças
respectivamente.
Na direcção 3 aumenta tanto a linha como a coluna N_Peças. E finalmente para a
direcção 6 diminui N_Peças tanto a linha como a coluna.
Figura 16 – Direcções para onde uma pilha pode movimentar
Definimos alguns predicados que são muito importantes para a continuidade do
raciocício descrito. O predicado mais básico e que suporta toda a implementação do
agente é o predicado vizinho(+Pos,+Size,-Vizinho)7.
Este predicado tem os seguintes parâmetros: o primeiro é a posição no formato
(Coluna,Linha) sobre o qual queremos procurar vizinhos. O segundo parâmetro toma
o valor 1 quando o predicado é usado para encontrar os vizinhos de uma
determinada posição e toma o valor N_Peças quando queremos saber quais as
posições para onde a pilha, que esteja na posição referida no parâmetro 1, pode
mover.
Para exemplificar a situação considere a Figura 17. Para sabermos os vizinhos da
posição na figura consideramos Size = 1 e temos dois vizinhos. Se considerar agora
o Size como N_Peças (tamanho da pilha), que neste caso é 3, então segundo a
figura teremos 3 jogadas possíveis considerando um salto de 3 posições (os saltos
estão representadas na figura com setas brancas). Considere ainda que o tamanho
7
A notação que será usada para a definição dos predicados será a mesma que é usada na linguagem
Prolog.
(+): campo de entrada – é preciso fornecer este valor ao método.
(–): campo de saída – valor de retorno do método.
(?): campo que poderá ser tanto de saída como de entrada – este pode ser fornecido ou não.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
59
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
da pilha era 1, então o salto seria 1 também. Por isso teriamos 2 jogadas possíveis
iguais aos vizinhos encontrados. O terceiro argumento corresponde a um vizinho
encontrado para a posição, ou um movimento possível da pilha.
O predicado vizinho/3 será utilizado por outros predicados, tais como:
calcular_vizinhos(+Pos,+Size,-Lista) – que devolve uma lista com todas
as posições vizinhas. Esta lista se encontra no formato [(Col,Lin),...]
encontrar_vizinhos_ocupados(+Pos,+Size,-Lista) - que devolve uma lista
das vizinhas que estão ocupadas com peças. Não podemos esquecer de que
na fase 2 só é possível efetuarmos um movimento para uma posição que
esteja
ocupada.
Portanto
este
predicado
é
conveniente
para
esta
situação.
contar_vizinhos_ocupados(+Pos,+Size,-Tam) – uma das régras do próprio
Dvonn é de que as peças que estiverem completamente cercadas não podem
ser
movimentadas.
Assim,
este
predicado
devolve
na
variável
Tam
o
número de vizinhos da posição (C,L) ocupados. Se o Tam = 6 então a
posição está completamente cercada e não se pode movimentar.
jogadas_possiveis_validas(+Cor,-Jogadas_Validas)
–
conjugando
os
predicados acima descritos, este devolve uma lista de jogadas válidas
para uma determinada cor. Se usar a cor w, o predicado devolve uma
lista de todas as jogadas válidas para o estado actual do tabuleiro,
para o jogador que joga com a cor w. Se fizer o mesmo para a b,
delvolverá a lista das jogadas válidas para o jogador com a cor b. Esta
lista se encontra no formato [(Col,Lin),...]
Figura 17 – Movimentar uma pilha
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
60
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
Estes predicados são muito importantes quer para a definição de jogadas válidas que
o agente poderá efectuar, como também para a criação das estratégias do jogo.
Outro aspecto que é importante considerar na validação das jogadas é que cada
jogador só pode mover peças da sua cor. Portanto, o agente inteligente terá que
conseguir saber quais as posições no tabuleiro que pode mover. Vimos anteriomente
que o facto tabuleiro/2 foi pensado de forma a tormar fácil a manipulação da
informação sobre o tabuleiro. Assim sendo, após identificarmos as posições onde se
encontram as peças da nossa cor, aí então poderemos avaliar quais as possibilidades
de jogada que cada posição nos oferece através do predicado vizinho. De notar que
uma posição tem no máximo 6 hipóteses de jogada, e também pode não ter
nenhuma hipótese de jogada (isto acontece muitas vezes quando a pilha é muito
grande).
5.5.2 -
Como calcular os benefícios de uma jogada?
Cálcular os benefícios de uma jogada é relativamente difícil uma vez que não se
pode, de uma forma directa identificar quais as peças que o jogador ganha e
também as perdas associadas a mesma jogada. Considere portanto a figura 14.
Nesta figura vemos que o jogador com a cor branca pretende efectuar uma jogada
onde o seu ganho é de uma peça e no entanto essa jogada provoca o isolamento de
várias peças do tabuleiro entre elas duas peças da sua cor. Assim, vemos que apesar
de ter um ganho de uma peça da cor preta, perde duas peças da cor branca.
Esta avaliação que estamos fazendo, é uma avaliação de imediato, ou seja, a curto
prazo. Se calhar interessa para o jogador efectuar essa jogada porque o adversário
perde 5 pilhas com tamanhos diferentes. Essa perda por parte do adversário é boa
para nosso jogador em questão.
Portanto, no cálculo dos benefícios é necessário incluirmos também não só o ganho e
a perda do jogador também a perda do adversário. Chegar a uma fórmula que seja
razoávelmente boa é difícil, dependendo do raciocínio que o programador tiver em
mente. Uma vez que o custo das jogadas influencia muito na escolha das jogadas
por parte do agente é preciso ter muito cuidado na sua definição. Apesar de a
tomada de decisão ser feita de acordo com as estratégias implementadas, a fórmula
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
61
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
terá uma peso também elevado que fará com que o agente consiga tomar decisões
boas ou más tendo em conta o critério usado para a pontuação dos custos das
jogadas.
Mas neste projecto não se preocupou muito com este aspecto. Contudo, foi definida
uma fórmula que é relativamente simples mas que leva em contas as parcelas
importantes no como as perdas do jogador e do adversário e também os ganhos.
A fórmula definida é a seguinte: Custo = PGJ - PPJ + PPA
PGJ – são as peças ganhas pelo jogador
PPJ – são as peças que o jogador perde
PPA – são as peças que o adversário perde.8
Depois de estar definido a fórmula e de calcularmos os pesos das jogadas, então
será preciso tirar conclusões sobre qual é a melhor jogada que poderá ser feito. Nem
sempre as conclusões serão boas. Como se pode ver após o cálculo do custo
perde-se a informação sobre os ganhos e perdas quer do jogador quer do adversário.
Desta maneira a fórmula terá que ser muito bem pensada de modo a que os custos
calculados para as jogadas sejam boas para a tomada de decisões. Se existir um
grau de confiança elavado em relação aos resultados que a fórmula nos dá então
existirá um equilíbrio entre este ganho e as perdas de informação referidas
anteriormente.
Para permitir a alteração da fórmula criou-se o seguinte predicado onde podemos
reestruturar ou redefinir uma nova fórmula para o cálculo do custo das jogadas:
determinar_custo(PGJ,PPJ,PPA,Custo)
8
Notar que os ganhos ou perdas são a soma do tamanho de todas as pilhas da referida cor, ou seja,
quando o jogador ganha uma pilha do adversário o seu ganho corresponde ao tamanho da pilha. E no
caso de perdas é a mesma coisa temos que somar todas as pilhas da cor.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
62
Instituto Superior de Engenharia do Porto
5.5.3 -
Capítulo 5 – Implementação agente Dvonn
Calcular o Isolamento de peças
O cálculo do ganho que se pode ter com uma jogada é fácil de fazer, basta saber a
cor da pilha que irá ser movimentada e para onde quer mover. Sabe-se que na
posição para onde se irá mover tem uma cor associada, assim basta verificar se as
cores são iguais para se saber se haverá ganho de peças ou não. Se as cores forem
iguais o PGJ = 0, e se forem diferentes o ganho que o jogador terá é o tamanho que
a pilha para onde quer mover tem. Neste caso PGJ = N_Peças da posição 2.
Se a pilha tiver um Dvonn pode-se acrescentar 1 ponto como bónus para fazer com
que os jogadores tenham por objectivo controlar as peças Dvonn.
O problema se põe em calcular as peças que ficam sem ligação a um Dvonn, ou seja,
encontrar as peças isoladas. Para avaliar esta situação considere a Figura 18.
Figura 18 – Isolamento de peças
Na figura pode-se ver que depois de se concretizar a jogada ou movimento, haverá
duas áreas distintas (formou-se como que dois grupos de peças um grupo de lado
esquerdo e outro do lado direito) no tabuleiro. Nestas duas áreas vê-se que as peças
pertencentes a área da esquerda terão que ser eliminadas por não ter ligação Dvonn,
ou seja, não existe nenhum Dvonn nessa área. Como implementar isso?
Figura 19 – Tabuleiro inicial gerado pelo servidor
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
63
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
Uma solução é pensar da seguinte forma: o tabuleiro tem 3 peças Dvonn o que faz
como que no máximo seja possível formar 3 áreas distintas. Quando dizemos 3
áreas referimos as áreas com ligação Dvonn porque como referido na secção 5.1 as
peças isoladas serão retiradas do tabuleiro.
A figura 19 é um exemplo de um tabuleiro no seu estado inicial, neste estado existe
apenas uma única área porque não existem separações entre as peças.
Considerando que existe uma lista com todas as posições ocupadas do tabuleiro no
formato (Coluna,Linha) e que a mesma lista se encontra ordenada. Para a Figura 20
teremos uma lista com 26 elementos. A lista das posições é a seguinte:
[(1,1),(1,2),(1,3),(2,2),(2,3),(3,1),(3,4),(3,5),(4,1),(4,2),(4,4),(5,1),(5,2),(5,3),
(5,5),(6,1),(7,1),(7,3),(7,4),(8,1),(9,3),(9,4),(10,2),(10,3),(11,3),(11,4)]
Figura 20 – Divisão do tabuleiro em áreas
Para cada elemento da lista, calcula-se as suas posições vizinhas e de entre estas
veremos se algum pertence a lista inicial. Antes de se começar a explorar uma
posição, guarda-se essa indicação numa lista auxiliar. Neste caso vê-se que a
posição (1,1) tem 3 posições vizinhas (1,2), (2,1) e (2,2). De entre estes vizinhos
(1,2), e (2,2) pertencem a lista portanto, serão os próximos a ser explorado.
Seguindo a ordem (1,2) será explorado primeiro, e vê-se que tem as posições (1,1),
(1,3), (2,2), e (2,3) como vizinhas e todas elas pertencem a lista contudo, a posição
(1,1) não será explorada porque já se encontra na lista auxiliar, e o processo se
repete até se obtermos (todas as posições da área já foram exploradas).
No final a lista auxiliar terá as posições ligadas por uma linha na figura. Estas
posições ([(1,1),(1,2),(1,3),(2,3),(2,2),(3,4),(3,5),(4,4),(5,5)]) são as posições que
formam a área 1. Depois de encontrar uma área verifica-se se existe alguma posição
da área que tenha um Dvonn. Se sim então estas posições têm ligação, senão serão
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
64
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
marcadas como peças para remover do tabuleiro. Sempre que encontra uma área
nova remove-se da lista inicial todas as posições que pertencem a referida área.
O processo se repete até que todas posições da lista tenham sido exploradas. Da
Figura 20 vemos que 8 posições serão marcadas para serem removidas. Estas são:
[(3,1),(4,1),(4,2),(5,1),(5,2),(5,3),(6,1),(7,1)]
A lista de posições a remover pode ter n elementos, e estes elementos podem ser da
cor branca (w) ou preta (b). Faz-se a contabilização das peças existentes nessas
posições para se saber o que cada jogador perde. De notar que por exemplo, para a
cor branca perde-se três pilhas, e o total é a soma do tamanho de cada pilha. Na
imagem as pilhas têm apenas uma peça por isso o total é 3.
Depois de saber que peças cada jogador perde, usa-se a fórmula definida na secção
5.4.2. para determinar o custo da jogada. Associado a cada jogada válida do agente
acrescenta-se este custo.
O predicado jogadas_beneficio(+Lista_jogadas,-ListaNova)
é um método
recursivo que é usado para fazer a actualização da lista de jogadas válidas do
agente, e para isso também utiliza o predicado calcular_beneficio_jogada/2.
O formato da lista de jogadas válidas é a seguinte: [[Pos1,Pos2], ... ] em que as
variáveis Pos1 e Pos2 se encontram no formato (Coluna, Linha). [Pos1,Pos2]
significa que é possível efectuar o movimento da pilha que se encontra na posição
Pos1 para a posição Pos2. A ListaNova resultante terá o seguinte formato:
[[Pos1,Pos2,Custo], ... ].
O
predicado
calcular_beneficio_jogada(+Jogada,-Jogada_custo)
é
muito
importante, porque é ele que cuida dos pormenores referentes a como calcular os
efeitos da referida jogada sobre o tabuleiro. Isso inclui simular a jogada, e após isso
verificar quais as peças que o agente ganha, quais as peças que perde e também
quais as peças que o adversário perde. Todas essas simulações são feitas sempre
através da criação de áreas no tabuleiro. A variável Jogada como já se referido no
predicado anterior tem o formato [Pos1,Pos2] e a variável Jogada_custo será
[Pos1,Pos2,Custo].
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
65
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
Na implementação deste predicado deparamos como muitas dificuldades, como é o
caso de quando queremos calcular os benefícios de uma lista relativamente grande
de jogadas possíveis. A aplicação Prolog apresentava sempre uma mensagem de
erro dizendo a hip está cheia. Este problema foi difícil de resolver por não
conseguirmos detectar a razão para os predicados funcionarem com listas pequenas
e para listas com mais alguns elementos já não funcionava. Depois chegou-se a
conclusão que realmente quando se usa listas relativamente grandes para se testar
os predicados a aplicação não conseguia terminar a execução e abortava. Por isso
teria que ser preciso arranjar uma forma de solucionar o problema.
Após muitos dias sem conseguir resolver o problema chegou-se a uma situação
interessante: para explicar o raciocínio considere a figura 21. Na figura existem 3
áreas, e as jogadas ou movimentos podem ser feitos dentro da mesma área ou para
fora da área. Para começar vamos analisar os movimentos da pilha de cor branca da
primeira área. Esta pilha tem tamanho 2 e portanto tem 3 hipóteses de jogada, uma
para a área 2 e duas dentro da mesma área. Como a pilha não contém nenhum
Dvonn então os efeitos resultantes do seu movimento é o mesmo (a nível de peças
perdidas) quer seja dentro da área ou para fora. Portanto, para essa posição só
preciso calcular as perdas uma só vez. Como podemos constatar na figura, as peças
perdidas são as mesmas quer movemos para dentro da área ou para fora. Com a
excepção do caso do movimento ser para uma posição que ficará sem ligação, neste
caso também perde-se a pilha (não existe ganho) e portanto será acrescentado ao
total de perdas o tamanho da pilha.
E se a pilha tiver um Dvonn?
Vamos considerar a pilha de cor preta da área 1. Esta pilha tem tamanho 3 e contém
uma peça Dvonn. Os movimentos possíveis para esta pilha são dois. Um na direcção
1 e o outro na direcção 4. O movimento na direcção 1 é dentro da mesma área, e o
outro é para a área 2. Se o movimento for para fora da área as peças que ficam sem
ligação são as mesmas seja qual for a posição para onde se move. Neste caso só
temos uma hipótese de jogada mas, se tivéssemos mais bastaria calcular as perdas
para uma dessas jogadas e guardar essa informação. Neste caso, o movimento
provocaria muitas perdas porque todas as posições da área 1 dependem dessa pilha.
Quando o movimento for dentro da área aí temos que ter um pouco mais de cuidado
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
66
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
porque nem sempre as perdas são as mesmas portanto temos que fazer os cálculos
sempre.
Figura 21 – Movimentar pilhas entre áreas
Portanto, como vimos esta ideia melhora muito a performance do agente, porque
consegue ter as informações mais rápida e não é preciso estar sempre a efectuar
cálculos de perdas para todas as jogadas. Isto não quer dizer que desconsideramos
as outras jogadas possíveis mas sim, que já não precisamos efectuar cálculos
desnecessários porque pordemos obter estes valores a partir de outros cálculos já
efectuados anteriormente. Antes fazia-se a avaliação para as 6 jogadas possíveis e
agora considera-se apenas duas situações (dentro e fora da área). Desta maneira a
aplicação prolog não aborta a execução a meio e consegue-se um melhor
desempenho.
Os predicados criados para o cálculo das perdas formam os seguintes:
calcular_areas(+ListaPosicoesOcupadas) – este predicado é muito útil
porque é através dele que podemos calcular as perdas dos jogadores. As
perdas são calculadas em função das áreas existentes no tabuleiro. O
predicado recebe no argumento a lista de posições ocupadas do tabuleiro
e depois cria um facto auxiliar areas/1 que será usado para qualquer
cálculo necessário.
Este facto areas tem o formato [[(Col,Lin,Cor,Tam,DV), ... ], ... ] e
pode ter no máximo 3 elementos (3 listas). Cada lista pode ter o número
qualquer de elementos sendo que as listas representam áreas existentes
no tabuleiro e os elementos das listas são as posições do tabuleiro
correspondentes a área.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
67
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
Considere um como exemplo o seguinte tabuleiro:
5
4
3
2
1
-
.0. .b1 .b1 .0. .0. .b3 .0. .w2 .0.
.b2 .0. .b1 .0. .0. .b1 .w2 .0. .b1 .0.
.w1 .b1 .w2 .0. .w2 .b3 .0. .0. *d1 .0. .0.
.0. *b2 .0. .w1 .0. .w1 .0. .0. .0. .0.
.w2 .0. *d1 .w1 .w1 .w1 .0. .0. .0.
\
\
\
\
\
\
\
\
\
\
A
B
C
D
E
F
G
H
I
J
\
K
Para este tabuleiro as lista de áreas é a seguinte:
[
[(1,1,w,2,0),(1,3,w,1,0),(2,2,b,2,1),(2,3,b,1,0),(2,4,b,2,0),(3,3,w,2,0
),(4,4,b,1,0),(4,5,b,1,0),(5,5,b,1,0)]
,
[(3,1,d,1,1),(4,1,w,1,0),(4,2,w,1,0),(5,1,w,1,0),(5,3,w,2,0),(6,1,w,1,0
),(6,2,w,1,0),(6,3,b,3,0),(7,4,b,1,0),(8,4,w,2,0),(8,5,b,3,0)]
,
[(9,3,d,1,1),(10,4,b,1,0),(10,5,w,2,0)]
]
Nesta lista temos 3 listas de áreas e em cada área temos a informação
sobre as posições que pertecem a área.
calcular_efeitos_jogada_tabuleiro(+Pos1,+Pos2,-Tipo)
–
este
predicado
com 3 argumentos serve para sabermos qual o efeito de um movimento
sobre o tabuleiro. O primeiro argumento é a posição a mover e o segundo
é a posição para onde queremos deslocar a pilha. O terceiro argumento é
o tipo que poderá ter três valores, dentro, fora ou qualquer. Estes
valores indicam se o movimento é para dentro ou fora da área se a pilha
tiver um Dvonn e no caso de ser uma pilha normal o valor da variável é
qualquer porque tanto faz se o movimento for para fora ou para dentro
as posições perdidas serão as mesmas. Depois disso o predicado cria um
facto dinâmico auxiliar pecas_perdidas_jogada/3 que guarda a informação
sobre o movimento e a lista das posições que ficam sem ligação depois
do movimento.Este facto terá o seguinte formato:
pecas_perdidas_jogada(Posicao,TipoMov,PecasPerdidas).
pecas_ganhoJ_perdidasA(+Cor1,+Cor2,+Tam2,+DV2,+P_S_Lig_Adv,-PGJ,-PPA)–
calcula os parâmetros correspondentes ao ganho do jogador e as perdas
tanto do jogador como do adversário. Os valores para as variáveis Cor
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
68
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
da posição, Cor da posição 2, tamanho da pilha da posição 2 e se
existem Dvonn na posição 2 e também o nímero de peças do adversário sem
ligação são fornecidos como a própria notação indica e os dois últimos
parâmetros serão calculados pelo método e serão retornados a aplicação.
parametros_calculo_custo_jogada(+[Pos1,Pos2],-PGJ,-PPJ,-PPA)–
predicado
auxiliar que usa alguns destes predicados já definidos, como o caso do
predicado definido anteriormente para encontrar os parâmetros que serão
usados no cálculo do beneficio da jogada [Pos1,Pos2].
determinar_custo(+PGJ,+PPJ,+PPA,-Custo)
–
predicado
responsável
por
calcular o custo da jogada mediante a fórmula definida para esse fim.
5.5.4 -
Fim do Jogo
No jogo os jogadores vamos perdendo peças, as pilhas vão aumentando, e o número
de jogadas possíveis varia. Contudo, durante o desenrolar do jogo, pode haver
situações em que um dos jogadores não tenha jogadas válidas. Neste caso o outro
jogador continua a jogar até que o outro tenha hipótese de jogar. Quando nenhum
dos jogadores tiver jogadas possíveis então o jogo acaba. Nesta altura faz-se a
contagem das peças na posse de cada jogador. O jogador que tiver o maior número
de peças ganha o jogo. Para a contagem das peças faz-se o somatório do tamanho
de cada pilha.
5.6 -
Tácticas propostas para o jogo
A página http://www.gipf.com/Dvonn/ dá-nos algumas sugestões de táticas e
estratégias que podemos definir para o jogo. O jogo tem duas fases mas a primeira
fase não foi referida ao longo do relatório porque tem a ver com a arrumação das
peças no tabuleiro. Nesta fase as jogadas não constituem movimentos por isso é fácil
de ser efectuada, só precisamos efectuar a alteração do tabuleiro. Uma vez que os
servidores na Internet permitem a opção de gerar um tabuleiro, então não nos
preocupamos muito com esta fase.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
69
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
Para a fase 2 é que temos que ter mais cuidados em termos de que tácticas
escolher. As condições dos jogadores variam e assim sendo os jogadores têm a
necessidade de mudar as suas tácticas de jogo consoante o estado do tabuleiro e as
jogadas do adversário. Desta maneira, propõe-se uma série de tácticas cada uma
para situações distintas. De salientar que este projecto também tem como objectivo
estudar e propor tácticas e estratégias de acordo com informação que se tem do
tabuleiro.
Tácticas propostas:
1. Uma vez que no início do jogo as hipóteses de jogada são poucas (só as
peças a volta do tabuleiro podem ser movidas porque as outras estão
completamente cercadas), podemos optar por fazer as jogadas que libertam
as peças da nossa cor. Assim passamos a ter mais jogadas possíveis. Esta
táctica é aconselhada no início do jogo, nas primeiras jogadas.
2. Podemos optar por fazer os movimentos sempre para posições com peças de
cor do adversário.
3. Capturar as peças ou pilhas do adversário com possibilidades de capturar
uma pilha nossa que contenha um Dvonn.
4. Efectuar movimentos para posições do adversário com possibilidades de
capturar um Dvonn. Assim podemos diminuir a probabilidade do adversário
capturar o Dvonn. Esta táctica já inclui implicitamente a captura de peças do
adversário vizinhas de algum Dvonn.
5. Efectuar jogadas de modo a capturar pilhas com Dvonn por fazer o
movimento para a posição onde se encontra o Dvonn.
6. Evitar o crescimento demasiado das nossas pilhas porque depois será difícil o
seu movimento. Para isso devemos evitar jogadas em que a posição destino
passará a ter um tamanho elevado após o acréscimo das peças da outra
pilha.
7. Ter o cuidado quando o adversário controla uma pilha com Dvonn, e avaliar
que perdas poderá ter a nível de peças se o adversário mover a pilha para
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
70
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
uma outra posição. Avaliar os movimentos da pilha e diminuir as hipóteses de
movimento da pilha.
8. Efectuar jogadas que proporcionam o menos número de perdas possíveis.
Como o custo benefício de uma jogada é dados pela conjunção de vários
atributos usando uma fórmula então torna-se difícil através desse custo tomar
decisões quanto ao número de posições que ficam movíveis no tabuleiro após
a jogada. Talvez essas perdas sejam muito significativas a ponto de o jogador
ficar sem jogadas válidas.
9. Escolher a jogada que nos dá uma melhor pontuação em relação ao nosso
adversário a nível de:
•
Mais jogadas validas
•
Mais peças em nosso poder
•
Mais posições livres para jogada
•
Menos perdas a nível de posições que o adversário
5.6.1 -
Implementação das tácticas propostas
Para este capítulo vamos descrever de uma forma sucinta como foi implementada as
tácticas propostas. Não vamos considerar muitos pormenores com respeito a
métodos implementados por serem relativamente complexos de descrever. Cada
táctica é identificada por um número, tactica(+Número,+CorJog,-Jogada). As
tácticas consideram sempre o parâmetro CorJog recebido em argumento que permite
uma resposta sobre qual a melhor jogada, tanto para o jogador como para o
adversário mediante a táctica. Por isso se quisermos podemos usar essas tácticas do
lado do adversário para ele obter sugestões de jogada.
Táctica 1
Para a táctica 1 é preciso como sempre saber quais as jogadas possíveis para a
nossa cor. Para cada uma das jogadas calcula-se o número de posições vizinhas da
nossa cor e associamos essa informação a jogada. Depois no final a jogada que tiver
um valor maior será a melhor jogada mediante esta táctica. Se tivermos mais do que
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
71
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
uma jogada com o mesmo valor, escolhe-se a jogada que tenha maior custo
beneficio. Para isso foram usados os seguintes métodos:
jogadas_possiveis_validas(+Cor,-Jogadas_Validas) – este predicado como
o próprio nome mostrar se destina a encontrar as jogadas válidas para
uma determinada cor.
A lista de retorno tem o formato: [[Pos1,Pos2], ... ] e Pos1 e Pos2 têm
o formato (Coluna,Linha).
vizinhos_a_libertar(+Jogadas_Validas,-LF) – este predicado usa a lista
de jogadas válidas para determinar quantos vizinhos da nossa cor cada
jogada liberta. Para isso terá que usar outros predicados como por
exemplo
contar_vizinhos_mesma_cor_cercados/3.
A
lista
LF
resultante
terá um parâmetro a mais que a lista Jogadas_validas que é o número de
vizinhos da nossa cor que cada jogada liberta. Portanto o formato da
lista será [[Pos1,pos2,NVizinhos], ... ].
Depois de termos a lista com a informação sobre o número de vizinhos
que cada jogada liberta usa-se o predicado
jogadas_liberta_mais_vizinhos/4
para
encontrar
a
jogada
que
liberta
mais vizinhos. Se existirem mais do que uma escolha então usa-se os
predicados
jogadas_beneficio/2
anteriormente
e
jogada_maior_custo/4
já
definidos
para escolher a jogada que tiver maior benefício em
termos de custo.
Táctica 2
A implementação desta táctica é muito simples tendo em conta alguns predicados já
definidos anteriormente. Queremos capturar as peças do adversário, para isso temos
a lista de jogadas válidas. Escolhemos avaliar apenas as jogadas (Pos1, Pos2) cuja
Pos2 pertence ao adversário. Após isso calcula-se os benefícios das mesmas jogadas
e a que tiver melhor custo é a escolhida. Métodos usados:
jogadas_para_posicoes_diferentes(+Cor,-Jogadas) – este predicado recebe
uma
determinada
cor
e
procura
as
jogadas
possíveis
apenas
para
as
posições do adversário. A lista Jogadas que é retornada tem o mesmo
formato que a lista de jogadas válidas.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
72
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
jogadas_beneficio/2 e jogada_maior_custo/4 já descritos anteriormente.
Táctica 3
Encontrar as nossas jogadas válidas para posições pertencentes ao adversário,
depois disso temos também que conhecer as jogadas possíveis do adversário para
posições onde se encontram as nossas pilhas com algum Dvonn. Depois disso temos
que ver se existe alguma jogada que possamos fazer antes, para que o adversário
não tenha mais jogadas válidas para a posição onde se encontra a pilha que
queremos proteger. Se encontrarmos alguma jogada possível então calculamos o
custo beneficio da mesma jogada. Se existirem mais do que uma jogada possível
escolhemos a que tiver maior ganho. Para essa implementação foram usados os
seguintes métodos:
jogadas_para_posicoes_diferentes/2,
jogadas_beneficio/2
e
jogada_maior_custo/4 já descritos anteriormente e ainda os predicados
que serão descritos a seguir.
jogadas_para_posicoes_com_Dvonn(+Cor,-Jogadas)
–
este
procedimento
é
parecido com o jogadas_para_posicoes_diferentes/2 com a diferença de
que aqui pretende-se encontrar os movimentos para as posições que do
adversário que do agente que controle uma peça Dvonn. A lista Jogadas
retornada terá o mesmo formato que a lista das jogadas válidas.
Dvonn_controlado_cor(+Cor,-ListaDvonn)
–
devolve
uma
lista
com
as
posições onde existe um Dvonn controlado pelo jogador com a Cor. Caso
não exista nenhuma pilha com a Cor requerida que controle algum Dvonn
retorna-se lista vazia.
Táctica 4
Esta táctica é relativamente parecida com a táctica descrita anteriormente, com um
pormenor de não avaliar apenas os movimentos do adversário para posições da
nossa cor que tenha um Dvonn mas também no caso de um Dvonn ainda não
pertencer a nenhum dos jogadores. De notar que esta táctica também faz a captura
de peças ou pilhas do adversário que são vizinhas de um Dvonn.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
73
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
Táctica 5
A implementação desta táctica é igual a táctica 2 com a diferença de que queremos
capturar não as peças do adversário mas sim os Dvonns.
Táctica 6
Para esta táctica calculou-se para cada jogada possível o tamanho da pilha
resultante. Estabelecemos uma variável N, que poderá ser alterado consoante a
interpretação que quisermos, para o tamanho máximo das pilhas. Para esta
implementação foi escolhido o valor 4 para a variável N uma vez que como temos
apenas 5 linhas no tabuleiro, se uma pilha tiver tamanho maior que 4, então a pilha
terá no máximo 2 movimentos possíveis (nas direcções 1 e 4). Depois disso, como
nas outras tácticas, calculamos os benefícios para a lista encontrada e no fim
escolhe-se a jogada com maior benefício. Nesta táctica foram usadas os seguintes
predicados:
jogadas_possiveis_validas/2, jogadas_beneficio/2 e jogada_maior_custo/4
descritos acima e ainda os seguintes predicados:
calcular_tamanho_pilha_resultante(+Jogadas_Validas,-LRes) – este método
devolve uma lista resultante com o formato [[Pos1,Pos2,Tam], ... ] onde
o Tam é o tamanho que a pilha na posição 2 terá após o movimento da
pilha da posição 1 para a posição 2. Este valor será importante para
depois ser possível saber qual ou quais as jogadas que originam um
crescimento demasiado excessivo das nossas pilhas e poder descartar
essas jogadas se possível.
Para isso recorre-se ao predicado jogada_pilha_resultante_menor_N/4 que
devolve a lista com as jogadas que originam uma pilha menor que N. Este
valor fica ao critério do programador, mas neste projecto foi usado o
valor 4.
Táctica 7
Esta táctica é relativamente complexa. Para isso teremos que procurar se existe
alguma pilha que tenha um Dvonn e seja controlado pelo adversário. Depois disso
precisamos analisar as jogadas possíveis a partir da posição onde se encontra a
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
74
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
pilha. Para cada jogada possível calculamos os benefícios mas os valores serão
inversos, ou seja, como o cálculo do benefício nos dá valores para o adversário então
para nós o ganho do adversário é perda para nós. Por isso se o benefício do
adversário for 6, o benefício para nós é –6. Depois de ter esses valores podemos
optar por analisar as jogadas (Pos1,Pos2) com piores valores. O que nos interessa
neste caso são os Pos2. Para estas posições calculamos as jogadas possíveis e após
isso calcula-se os benefícios de se efectuar tais jogadas e escolhemos a jogada que
tiver maior beneficio. Resumindo, o que se pretende desta táctica é antecipar em
efectuar uma jogada que contraria um ganho que o adversário poderia ter. Ao
efectuarmos essa jogada minimizamos de alguma forma o ganho do adversário. Os
predicados usados para a implementação da táctica são:
Dvonn_controlado_cor/2, jogadas_posicao/2, jogadas_beneficio/2,
jogada_maior_custo/4 definidas anteriomente e os métodos
posicao_destino_minha_cor(+Lista,+Cor,-LRes)
uma
lista
das
jogadas
possíveis
e
a
–
Cor
este
e
predicado
procura
na
recebe
lista
os
movimentos cuja posição destino é uma posição dominada pela Cor, e
devolve na lista Lres esses movimentos. A lista terá o mesmo formato
que a lista de jogadas válidas [[Pos1,Pos2], ... ].
analisar_perdas(+Jogadas_Validas,+L,-LRes)
jogadas
válidas
adversário
sobre
do
adversário
e
o
tabuleiro.
Este
–
calcula
recebe
o
efeito
beneficio
é
uma
das
lista
de
jogadas
do
calculado
usando
o
predicado calcular_beneficio_jogada_adversario(+Jogada,-Custo). Como já
foi referido este custo é o inverso do beneficio que o adversário tem
se efectuar essa jogada.
Táctica 8
Esta táctica é muito simples de implementar considerando alguns predicados já
definidos
como
jogadas_possiveis_validas/2,
jogada_menor_custo/4,
jogada_maior_custo/4
jogadas_beneficio/2,
e
e foi preciso criar o método
jogada_perda_posicoes/3 para ser possível sabermos as perdas, em termos de
posições para cada jogada possível. Depois de efectuarmos os cálculos, de entre as
jogadas com menos perdas escolhemos a jogada com maior benefício.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
75
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
jogada_perda_posicoes(+Lista_Jogadas,+Cor,-LRes) – recebe uma lista com
as jogadas válidas e contabiliza o número de perdas da Cor em termos de
posições livres. Isto é importante porque as vezes podemos ter uma em
termos
de
peças
grande
mas
continuamos
a
ter
jogadas
válidas.
Mas
quando as perdas provocam a diminuição de muitas jogadas válidas isso
provoca quase de certeza a perda do jogo por parte do jogador.
Táctica 9
Esta táctica apresenta um grau de dificuldade maior uma vez que é preciso fazer a
recolha de muita informação tanto sobre as nossas jogadas como as do adversário.
A recolha é feita através dos métodos a seguir apresentados, onde podemos fazer
variar os argumentos de acordo com o ponto de vista a analisar. De acordo com o
identificador do jogador (cor) podemos por exemplo calcular as jogadas possíveis
validas do jogador com a cor w ou b.
jogadas_possiveis_validas/2, contar_n_pecas_pertencente_a_cor/2,
contar_posicoes_cor/2, jogada_perda_posicoes/3, jogadas_beneficio/2 e
jogada_maior_custo/4
Além destes predicados temos também o predicado calcular_ganhos/6 que irá
calcular um peso para cada jogada de acordo com a informação recolhida nos
predicados anteriores. Após isso, as jogadas com maior peso serão avaliadas
segundo os benefícios e escolhe-se a que tiver maior benefício imediato.
Para o cálculo do peso foi definida a seguinte fórmula:
DifPecas = NPecasJog - NPecasAdv,
DifPos_livres = NPosCorJog - NPosCorAdv,
Dif_Jogadas_validas = NJogadasJog - NJogadasAdv,
Peso = PerdAdv - PerdJog + DifPecas + DifPos_livres +
Dif_Jogadas_validas
Após a implementação destas tácticas surge então a necessidade de saber em que
situação aplicar cada táctica. Esta situação é respondida no nível superior, o
estratégico. Nesse nível seria necessário implementar mecanismos de escolha das
tácticas definidas e ainda a criação de algumas estratégias de jogo a longo prazo.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
76
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
Algumas possibilidades para a escolha da jogada adequada seriam:
™ Processar todas as tácticas e obter para cada táctica uma jogada e ver qual é
a melhor em termos de beneficio;
™ Escolher entre as hipóteses fornecidas pelas tácticas, a jogada escolhida por
um maior número de tácticas. Se existirem mais do que uma jogada
escolhida através de várias tácticas então opta-se como sempre por aquela
com maior benefício.
Este nível não será implementado neste projecto devido a falta de tempo disponível
para o fazer.
5.7 - Comunicação do agente com o servidor de jogos na
Internet
Como referido anteriormente pretende-se que o agente tenha uma ligação com um
servidor de jogos na Internet.
No site http://www.gamerz.net/pbmserv/commands.html, encontra-se um conjunto
de comandos para se efectuar a comunicação entre o nosso agente e o referido
servidor.
Comandos de administração como por exemplo:
signup userid password [ e-mail address(es) ]
change password userid current-password new-password
signoff userid password
Comandos de Informação
game help
game games userid* [ all | active | inactive | next ]
game show board[#moveno]+ [ -t ]
Comandos de jogar
game challenge userid1 userid2 [-options]
game move board userid password move[#moveno]
game move board userid password pass[#moveno]
etc…
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
77
Instituto Superior de Engenharia do Porto
Capítulo 5 – Implementação agente Dvonn
De entre os vários comandos descritos no site que nos poderá servir ao longo de um
jogo, o que nos interessa mais para a implementação do agente é o comando de
movimentar as pilhas de um lado para o outro (game move board userid password
move[#moveno]).
Como vemos o servidor aceita uma string neste formato onde o os parâmetros com
o estilo de letra bold serão valores que variam conforme a informação que temos do
jogo. Board é o código que identifica o tabuleiro na lista de tabuleiros do servidor
porque este poder ter vários jogos com vários jogadores a jogar ao mesmo tempo
em vários pontos da Internet. Userid é o identificador do jogador e também precisa
também de uma password para que o servidor possa aceitar o pedido de jogada.
Estes valores board, userid e password são gerados pelo servidor e disponibilizados
ao jogador antes de inicio um jogo. Assim o servidor fornece também o tabuleiro e a
cada jogador uma cor com a qual irá jogar. Finalmente o agente terá que gerar o
movimento tendo em conta as suas capacidades de avaliar qual a melhor jogada e
envia a string construída ao servidor. O servidor deverá confirmar ou não a jogada e
quando o adversário efectuar uma jogada o servidor deverá também enviar ao
agente a jogada efectuada pelo adversário.
O nosso agente inteligente não foi testado na Internet devido a falta de tempo
disponível para o fazer. Para fazer o teste teríamos que ter um conjunto de
informações exactas, como por exemplo qual o formato do tabuleiro que o servidor
de jogos envia aos participantes, saber a localização do mesmo servidor e as
possibilidades de poder existir esta mesma comunicação. A figura 22 mostra-nos de
uma forma simplificada a ligação que existirá entre o agente, o servidor e o jogador.
O servidor se encontra no meio e é ele que controla o jogo, os participantes não se
comunicam entre si directamente.
Figura 22 – Comunicação entre os participantes do jogo
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
78
Capítulo 6
Conclusão
Durante o desenvolvimento do projecto e a elaboração do relatório foram
encontrados diversos problemas, relatados ao longo do relatório. Realmente os
princípios da teoria de jogos podem ser aplicados a muitas situações da vida real. No
entanto, encontrar informação específica sobre como os princípios são aplicados nos
jogos em si é difícil.
Sabemos que se usa muito a Inteligência Artificial como forma de dotar os
programas de alguma capacidade de tomar decisões em determinado momento,
tendo em conta sempre os factores externos e internos do jogo. Nesta ordem de
ideias para foi relativamente muito difícil elaborar este documento e principalmente o
desenvolvimento da parte prática deste projecto que não ficou concluída. Quanto a
como a inteligência artificial é usada nos jogos encontramos apenas informação
teórica e também alguma informação breve sobre os requisitos de memória e
processamento que tais programas de jogos exigem.
Apesar destes problemas este trabalho foi muito desafiador e interessante. Devido a
falta de tempo o projecto não fica concluído, como se pode perceber existe uma
quantidade enorme de coisas por detrás duma aplicação de jogos deste tipo.
Alguns melhoramentos que futuramente poderiam ser acrescentadas são os
seguintes:
™ Estudar as estratégias de modo a saber em cada instante quais as melhores
tácticas aplicar;
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
79
Instituto Superior de Engenharia do Porto
Capítulo 6 – Conclusão
™ Encontrar um servidor na Internet e tentar estudar uma forma de se poder
efectuar uma ligação entre o agente e o servidor. Que parâmetros seriam
precisos, como por exemplo localização do servidor, porto, etc. Também seria
preciso conhecer o ficheiro com a informação do tabuleiro que o servidor
envia ao agente para ser analisado e para que o agente possa tratar essa
informação;
™ Criar estratégias com grau de visibilidade boa (estratégias que consigam
efectuar uma analise 2, 3, ..., n jogadas a frente).
Se o tempo permitisse ainda poderiam ser exploradas outras hipóteses para
melhorar a tomada de decisão do agente. Assim como um humano vai aumentando
o seu grau de inteligência a medida em que se familiariza com um jogo, poderiamos
também com o tempo descobrir outras tácticas que poderiam ajudar a melhorar a
inteligêcia do agente. Enfim existe muita coisa que poderia ser acrescentado mas,
considera-se bom ter chegado até aqui.
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
80
Instituto Superior de Engenharia do Porto
Bibliografia e Referências
[1]
Inteligência Artificial, Elaine Rich - McGraw-Hill
[4]
Carlos Duarte Costa e Kely C. Paintner Hauser - documento sobre
Teoria dos Jogos
http://oeconomista.com/wm/wmview.php?ArtID=689
Data acesso: 12 Março 2004
[6]
Centro Universitário Ibero-Americano
Teoria dos Jogos
http://www.unibero.edu.br/nucleosuni_neriteo05.asp
Data acesso: 12 Março 2004
[9]
Nogueira,
Fernando
–
Apontamentos
de
DISCIPLINA:
MODELAGEM
E
SIMULAÇÃO.
Universidade Federal de Juiz de Fora, Brasil.
[11]
Alunos
de
Pós-Graduação
do
Departamento
de
matemática,
Pontifícia
Universidade Católica do Rio de Janeiro, Brasil
http://www.mat.puc-rio.br/~inicient/3_jogos/index_jogos.htm
Data acesso: 15 Março 2004
[13]
Alunos
de
Pós-Graduação
do
Departamento
de
matemática,
Pontifícia
Universidade Católica do Rio de Janeiro, Brasil
http://www.mat.puc-rio.br/~inicient/3_jogos/somazero.htm
Data acesso: 15 Março 2004
[15]
Alunos
de
Pós-Graduação
do
Departamento
de
matemática,
Pontifícia
Universidade Católica do Rio de Janeiro, Brasil
http://www.mat.puc-rio.br/~inicient/3_jogos/somanaozero.htm
Data acesso: 15 Março 2004
[16]
Tatai,
Victor
Kazuo
-
Técnicas
de
Sistemas
Inteligentes
Aplicadas
Desenvolvimento de Jogos de Computador Agosto 2003.
Universidade Estadual de Campinas
Faculdade de Engenharia Eléctrica e de Computação
Departamento de Engenharia de Computação e Automação Industrial
[17]
Inteligência Artificial, Elaine Rich e Kevin Knight
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
81
ao
Instituto Superior de Engenharia do Porto
[18]
http://www.gipf.com/Dvonn/
Data acesso: 10 Março 2004
[19]
http://www.gamerz.net/pbmserv/Dvonn.html
Data acesso: 10 Março 2004
[21]
Pedro Luis Kantek Garcia Navarro
http://www.pr.gov.br/batebyte/edicoes/1997/bb65/deepblue.htm
Data acesso: 5 de Agosto de 2004
[23]
Polyane Alves Santos
Universidade Estadual de Danta Cruz - Brazil
Departamento de Ciências exatas e tecnológias
Introdução a teoria dos jogos
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
82
Instituto Superior de Engenharia do Porto
Acrônimos
IA – Inteligência Artificial
SI – Sistemas Inteligentes
IDA* – Iterative Deepening A*
SMA* – Simplified memory-bounded A*
MiniMax – Algoritmo de busca em profundidade numa árvore
Marlene da Graça Santos nº 980975 Ramo de Computadores e Sistemas
83
Download

Agente jogar DVONN - Departamento de Engenharia Informática