J2Velha

Transcrição

J2Velha
Universidade Federal do ABC
ufabc
J2 Velha
Uma Implementação Java do Jogo da Velha
Utilizando o Algoritmo MiniMax
André Filipe de Moraes Batista
[email protected]
Luis Fernando de Oliveira Jacintho
[email protected]
Disciplina de Inteligência Artificial
Profo Jerônimo Pellegrini
Santo André, Junho de 2008
Sumário
1 Jogos em IA
1.1 Minimax - Algoritmo de Busca Competitiva . . . . . . . . . . . . . . . . .
1
1
2 J2 Velha: Uma Abordagem Java ao Jogo da Velha
2.1 J2 Velha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
4
8
Anexos
16
A J2 Velha: Códigos
A.1 Classe Velha.java . . .
A.2 Classe Tabuleiro.java
A.3 Classe Sucessor.java .
A.4 Classe Minimax.java . .
.
.
.
.
16
16
18
20
21
.
.
.
.
27
27
30
34
35
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
B J2 Velha: Novas Funcionalidades
B.1 Classe Velha.java . . . . . . .
B.2 Classe Tabuleiro.java . . . .
B.3 Classe Sucessor.java . . . . .
B.4 Classe Minimax.java . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
ii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Capı́tulo 1
Jogos em IA
Para a maioria das pessoas o termo jogo é considerado como um passatempo do dia-a-dia.
Para as crianças serve como um modo de fugir aos trabalhos de casa e entrar em um mundo
virtual de infinitas possibilidades. Para os adultos o termo jogo pode invocar imagens de
jogadores que procuram estratégias que lhes dêem vantagens sobre os adversários. Ou
seja, o resultado do jogo é determinado pelas estratégias utilizadas pelos jogadores. O
ramo da Matemática que pensa de semelhante maneira é denominado Teoria dos Jogos.
A Teoria dos Jogos tem por objetivo visualizar qualquer ambiente multiagente como
um jogo, desde que o impacto de cada agente sobre os outros seja, de algum modo,
significativo. Os jogos são uma das áreas mais antigas desenvolvidas em Inteligência
Artificial (IA). Em 1950, desde que os computadores se tornaram programáveis, o primeiro
jogo de xadrez foi criado por Claude Shannon e por Alan Turing. Desde então diversos
progressos ocorreram nesta área, de tal forma que os sistemas atuais são capazes de
rivalizar e ganhar de um dos melhores jogadores de xadrez da história, Garry Kasparov.
Em meados de 1996 ocorreu o primeiro confronto entre Garry Kasparov e o Deep
Blue. Trata-se de um super computador de alta performance desenvolvido pela IBM, seu
código de programação é em linguagem C e é executado no sistema operacional AIX. O
resultado é uma máquina escalável capaz de calcular entre 100 e 200 bilhões de jogadas
em aproximadamente 3 minutos. No primeiro confronto entre os dois, a vitória foi de
Kasparov. Até que em 1997 a IBM desdobrou-se em constantes desenvolvimentos e atualizações de modo a melhorar o desempenho do Deep Blue. O resultado de tanto esforço
foi que Garry Kasparov foi vencido em 1997 pelo Deep Blue. A Figura 1.1 mostra uma
cena desta disputa.
1.1
Minimax - Algoritmo de Busca Competitiva
Em um ambiente multiagente os agentes convivem com situações de cooperação e competição. Um ambiente competitivo é aquele em que as metas dos agentes estão em constante
1
1.1. Minimax - Algoritmo de Busca Competitiva
2
Figura 1.1: Cena de um Disputa de Kasparov versus DeepBlue
.
conflito. Para tais situações é preciso desenvolver técnicas de busca competitiva entre os
agentes. É neste ponto que a teoria dos jogos pode auxiliar na construção de um agente
racional.
Em IA os jogos normalmente são de um tipo bastante especializados - algumas vezes
denominados determinı́sticos de revezamento de dois jogadores de soma zero com informações perfeitas. Isto representa ambiente determinı́sticos completamente observáveis em
que existem dois agentes cujas ações devem se alternar e em que os valores de utilidade no
fim do jogo são sempre iguais e opostos. Por exemplo, se um jogador ganha um jogo de
xadrez (+1), o outro jogador necessariamente perde (-1). Essa oposição entre as funções
de utilidades dos agentes que gera a situação de competição.
O MiniMax é um algoritmo de busca competitiva que seleciona a melhor ação a ser
feita em uma situação ou em um jogo, onde dois jogadores se empenham em alcançar
objetivos mutuamente exclusivos. Ele se aplica especialmente na busca em árvores de
jogo para determinar qual a melhor jogada para o jogador atual. O algoritmo se baseia
no princı́pio de que em cada jogada, o jogador irá escolher o melhor movimento possı́vel.
A árvore de jogo consiste de todas as jogadas possı́veis para o jogador atual como nós
filhos da raiz, e todas as jogadas disponı́veis para o próximo jogador como filhas destes nós
e assim por diante, até o nı́vel que se desejar. Cada ramificação da árvore representa um
movimento que o jogador pode fazer em tal momento do jogo. Uma busca mais profunda
na árvore fornece mais informações sobre as possı́veis vantagens ou armadilhas e portanto
resulta em uma jogada melhor.
O MiniMax faz uma busca que determina todas as possı́veis continuações do jogo até
o nı́vel desejado, avaliando e atribuindo um valor a cada movimento possı́vel. A busca
1.1. Minimax - Algoritmo de Busca Competitiva
3
então retorna na árvore de jogo alternando entre escolher o valor mais alto e o valor mais
baixo entre os valores da jogadas em um nı́vel. O método de busca consiste na idéia de
maximizar a utilidade supondo que o adversário vai tentar minimizá-la. Em termos de
busca, é realiza uma busca cega em profundidade, o agente é o MAX e seu adversário é o
MIN.
Algoritmo 1 MINIMAX
função DECISÃO-MINIMAX(estado) retorna uma ação
entradas: estado, estado corrente no jogo
v ← VALOR-MAX(estado)
retornar a ação em SUCESSORES(estado) com valor v
função VALOR-MAX(estado) retorna um valor de utilidade
se TESTE-TERMINAL(estado) então retornar UTILIDADE(estado)
v ← −∞
para a, s em SUCESSORES(estado) faça
v ← MAX(v, VALOR-MIN(s))
retornar v
função VALOR-MIN(estado) retorna um valor de utilidade
se TESTE-TERMINAL(estado) então retornar UTILIDADE(estado)
v←∞
para a, s em SUCESSORES(estado) faça
v ← MAX(v, VALOR-MAX(s))
retornar v
Se fosse o caso de se tratar de uma busca normal, bastava percorrer-se a árvore até
aos nós terminais e escolher o caminho que levasse ao nó com maior valor de utilidade.
Mas não é assim, visto existir outro jogador. Assim, é necessário, escolher a partir de
cada nó filho, o menor valor de utilidade, e copia-lo para o nó pai, recursivamente até ao
nó inicial. Este é o algoritmo MiniMax. Isto deve-se ao fato, do jogador MIN tentar
minimizar o ganho do jogador MAX, pois ele tentará escolher uma jogada, dentro das
possı́veis, que dê menos pontos ao jogador adversário. Na Caixa de Algoritmo 1 tem-se o
algoritmo MiniMax.
No Capı́tulo que segue tem-se uma implementação do Jogo da Velha utilizando a
linguagem Java e o algoritmo MiniMax.
Capı́tulo 2
J2 Velha: Uma Abordagem Java ao
Jogo da Velha
Conhecido também como “Jogo do Galo”, ou “Tic Tac Toe”, o jogo da velha é um jogo
extremamente simples, que não possui grandes dificuldades para seus jogadores. Seu nome
teria se originado na Inglaterra, quando nos finais de tarde, mulheres se reuniriam para
conversar e bordar. A mulheres idosas, por não terem mais condições de bordar em razão
da fraqueza de suas vistas, jogavam este jogo simples.
O jogo da velha é um dos exemplos mais clássicos de utilização do algoritmo Minimax.
O estado inicial e os movimentos válidos para cada lado definem a árvore do jogo correspondente ao jogo. A Figura 2.1 mostra parte da árvore de jogo para o jogo da velha. A
partir do estado inicial, MAX tem nove movimentos possı́veis. O jogo se alterna entre
a colocação de um X por MAX e a colocação de um O por MIN até que se alcance nós
de folhas correspondentes a estados terminais, tais que um jogador tem três sı́mbolos em
uma linha, coluna ou ainda diagonal; ou até que todos os quadrados estejam preenchidos.
O número em cada nó de folha indica o valor de utilidade do estado terminal, do ponto
de vista de MAX; valores altos são considerados bons para MAX e ruins para MIN. Cabe
a MAX usar a árvore de busca para determinar o melhor movimento.
2.1
J2 Velha
J2 Velha (Java 2 Velha) é uma implementação do Jogo da Velha desenvolvida na Linguagem Java utilizando o algoritmo MiniMax. Consiste de 4 classes, quais sejam:
1. Velha.java - Classe principal da Aplicação;
2. Minimax.java - Classe responsável em aplicar o algoritmo MiniMax;
3. Tabuleiro.java - Classe responsável pela manipulação do tabuleiro do jogo;
4
2.1. J2 Velha
5
Figura 2.1: Árvore de busca parcial para o jogo da velha
.
4. Sucessor.java - Classe responsável em gerar os sucessores, utilizados no algoritmo
MiniMax.
O algoritmo Minimax desenvolvido no J2 Velha pode buscar por profundidade infinita
(até que se encontre um estado terminal) ou por alguma profundidade determinada. A
implementação da escolha de profundidade deu-se em função da complexidade do algoritmo MiniMax. Se a profundidade máxima da árvore é m e existem b movimento válidos
em cada ponto, a complexidade de tempo do algoritmo MiniMax é O(bm ).
Na Caixa de Código XX tem-se um trecho do algoritmo MiniMax contido na classe
Minimax.java. É possı́vel comparar esta implementação com o algoritmo apresentado no
Capı́tulo anterior.
3
6
Código 2.1: Implementação do Algoritmo
/∗
∗ Método de d e c i s ã o do MiniMax
∗/
p u b l i c i n t [ ] [ ] d e c i s a o m i n i m a x ( i n t [ ] [ ] tab )
{
/∗
∗ Limpa o s s u c e s s o r e s
MiniMax
2.1. J2 Velha
6
∗/
sucessores . clear () ;
9
/∗
∗ Recebe a u t i l i d a d e máxima
∗/
i n t v = valor max ( tab , t r u e , 1 ) ;
12
15
/∗
∗ P e r c o r r e a l i s t a em busca do p r i m e i r o s u c e s s o r com u t i l i d a d e máxima
∗/
for ( Sucessor s : sucessores )
i f ( s . u t i l i d a d e == v )
return s . tabuleiro ;
18
21
r e t u r n tab ;
24
27
30
33
36
}
p u b l i c i n t valor max ( i n t [ ] [ ] tab , b o o l e a n prim , i n t p r o f )
{
/∗
∗ Se a p r o f u n d i d a d e f o r maior que a máxima ou o j o g o acabou , r e t o r n a a
∗ utilidade
∗/
i f ( p r o f++ > maxProf | | t e s t e t e r m i n a l ( tab ) )
r e t u r n u t i l i d a d e ( tab ) ;
/∗
∗ A t r i b u i o menor v a l o r de um i n t e i r o para v ( − i n f i n i t o )
∗/
i n t v = I n t e g e r . MIN VALUE ;
39
42
45
48
51
/∗
∗ P e r c o r r e o s não s u c e s s o r e s de MAX
∗/
f o r ( S u c e s s o r s : g e r a r s u c e s s o r e s ( tab , 1 ) )
{
v = Math . max( v , v a l o r m i n ( s . t a b u l e i r o , p r o f ) ) ;
s . utilidade = v;
/∗
∗ Se forem o s p r i m e i r o s s u c e s s o r e s , a d i c i o n a na l i s t a de s u c e s s o r e s
...
∗/
i f ( prim )
s u c e s s o r e s . add ( s ) ;
}
2.1. J2 Velha
7
return v ;
54
}
p u b l i c i n t v a l o r m i n ( i n t [ ] [ ] tab , i n t p r o f )
{
/∗
∗ Se a p r o f u n d i d a d e f o r maior que a máxima ou o j o g o acabou , r e t o r n a a
∗ utilidade
∗/
i f ( p r o f++ > maxProf | | t e s t e t e r m i n a l ( tab ) )
r e t u r n u t i l i d a d e ( tab ) ;
57
60
63
/∗
∗ A t r i b u i +I n f i n i t o
∗/
i n t v = I n t e g e r .MAX VALUE;
66
69
/∗
∗ P e r c o r r e o s n ó s s s u c e s s o r e s de MIN
∗/
f o r ( S u c e s s o r s : g e r a r s u c e s s o r e s ( tab , −1) )
{
v = Math . min ( v , valor max ( s . t a b u l e i r o , f a l s e , p r o f ) ) ;
s . utilidade = v;
}
72
75
78
return v ;
81
}
2.2. Exemplos
2.2
8
Exemplos
A seguir tem-se a execução de algumas jogadas. Primeiramente vamos utilizar um tabuleiro de tamanho 3x3. Para tal não se faz necessária a definição de uma profundidade
máxima, pois a resposta do algoritmo é rápida. Executando o classe Velha.java tem-se
a seguinte saı́da no prompt de comando:
UFABC - J2VELHA
Bem vindo ao Jogo!
Boa Sorte!
|
|
---+---+--|
|
---+---+--|
|
Sua jogada:
Linha [0 - 2]:
O jogador decide jogar na linha 0, coluna 1. Tem-se então o resultado da jogada do
computador:
...
Sua jogada:
Linha [0 - 2]: 0
Coluna [0 - 2]: 1
| o |
---+---+--|
|
---+---+--|
|
Jogada do Computador:
x | o |
---+---+--|
|
---+---+--|
|
2.2. Exemplos
9
Sua jogada:
Linha [0 - 2]:
Para decidir onde jogar, o computador efetuou todo o algoritmo minimax e escolheu
uma posição que lhe favoreça, ao mesmo tempo que prejudique (não agora, pode ser nas
próximas jogadas) o adversário. O jogador agora decide jogar na linha 1, coluna 1. Tem-se
a seguinte jogada do computador:
...
Linha [0 - 2]: 1
Coluna [0 - 2]: 1
x | o |
---+---+--| o |
---+---+--|
|
Jogada do Computador:
x | o |
---+---+--| o |
---+---+--| x |
Sua jogada:
Linha [0 - 2]:
Observe que o computador decidiu jogar em uma posição que evita que o adversário
ganhe. O jogador decide jogar na linha 0, coluna 2. Tem-se a jogada do computador:
...
Linha [0 - 2]: 0
Coluna [0 - 2]: 2
x | o | o
---+---+--| o |
---+---+--| x |
2.2. Exemplos
10
Jogada do Computador:
x | o | o
---+---+--| o |
---+---+--x | x |
Sua jogada:
Linha [0 - 2]:
Observe que de qualquer forma o computador ganhará a partida. O jogador decide
jogar na linha 2, coluna 2. Tem-se a vitória do computador:
...
Linha [0 - 2]: 2
Coluna [0 - 2]: 2
x | o | o
---+---+--| o |
---+---+--x | x | o
Jogada do Computador:
x | o | o
---+---+--x | o |
---+---+--x | x | o
O computador ganhou!
Você pode verificar o funcionamento do jogo com um tabuleiro 4x4. Basta mudar as
variáveis TAM e PROF na classe Velha. Devido à complexidade do algoritmo recomenda-se
utilizar uma profundidade 5 para que o tempo de execução do mesmo seja razoável. A
seguir tem-se uma partida completa utilizando um tabuleiro 4x4:
2.2. Exemplos
UFABC - J2VELHA
Bem vindo ao Jogo!
Boa Sorte!
|
|
|
---+---+---+--|
|
|
---+---+---+--|
|
|
---+---+---+--|
|
|
Sua jogada:
Linha [0 - 3]: 0
Coluna [0 - 3]: 0
o |
|
|
---+---+---+--|
|
|
---+---+---+--|
|
|
---+---+---+--|
|
|
Jogada do Computador:
o | x |
|
---+---+---+--|
|
|
---+---+---+--|
|
|
---+---+---+--|
|
|
Sua jogada:
Linha [0 - 3]: 1
Coluna [0 - 3]: 0
11
2.2. Exemplos
o | x |
|
---+---+---+--o |
|
|
---+---+---+--|
|
|
---+---+---+--|
|
|
Jogada do Computador:
o | x | x |
---+---+---+--o |
|
|
---+---+---+--|
|
|
---+---+---+--|
|
|
Sua jogada:
Linha [0 - 3]: 2
Coluna [0 - 3]: 0
o | x | x |
---+---+---+--o |
|
|
---+---+---+--o |
|
|
---+---+---+--|
|
|
Jogada do Computador:
o | x | x |
---+---+---+--o |
|
|
---+---+---+--o |
|
|
---+---+---+--x |
|
|
12
2.2. Exemplos
Sua jogada:
Linha [0 - 3]: 1
Coluna [0 - 3]: 1
o | x | x |
---+---+---+--o | o |
|
---+---+---+--o |
|
|
---+---+---+--x |
|
|
Jogada do Computador:
o | x | x | x
---+---+---+--o | o |
|
---+---+---+--o |
|
|
---+---+---+--x |
|
|
Sua jogada:
Linha [0 - 3]: 2
Coluna [0 - 3]: 2
o | x | x | x
---+---+---+--o | o |
|
---+---+---+--o |
| o |
---+---+---+--x |
|
|
Jogada do Computador:
o | x | x | x
---+---+---+--o | o |
|
---+---+---+--o |
| o |
---+---+---+--x |
|
| x
13
2.2. Exemplos
Sua jogada:
Linha [0 - 3]: 1
Coluna [0 - 3]: 2
o | x | x | x
---+---+---+--o | o | o |
---+---+---+--o |
| o |
---+---+---+--x |
|
| x
Jogada do Computador:
o | x | x | x
---+---+---+--o | o | o | x
---+---+---+--o |
| o |
---+---+---+--x |
|
| x
Sua jogada:
Linha [0 - 3]: 2
Coluna [0 - 3]: 3
o | x | x | x
---+---+---+--o | o | o | x
---+---+---+--o |
| o | o
---+---+---+--x |
|
| x
Jogada do Computador:
o | x | x | x
---+---+---+--o | o | o | x
---+---+---+--o | x | o | o
---+---+---+--x |
|
| x
14
2.2. Exemplos
Sua jogada:
Linha [0 - 3]: 3
Coluna [0 - 3]: 2
o | x | x | x
---+---+---+--o | o | o | x
---+---+---+--o | x | o | o
---+---+---+--x |
| o | x
Jogada do Computador:
o | x | x | x
---+---+---+--o | o | o | x
---+---+---+--o | x | o | o
---+---+---+--x | x | o | x
Empate!
O código completo da implementação encontra-se no Anexo I.
15
Anexo A
J2 Velha: Códigos
A seguir tem-se a codificação completa da aplicação. Esta foi desenvolvida utilizando a
IDE NetBeans e JDK 1.6.
A.1
3
6
Classe Velha.java
/∗
∗ UFABC − U n v e r s i d a d e F e d e r a l do ABC
∗ MC 3303 − I n t e l i g ê n c i a A r t i f i c i a l
∗ P r o f e s s o r Jerônimo P e l l e g r i n i
∗ Alunos :
∗
André F i l i p e de Moraes B a t i s t a
∗
L uı́ s Fernando de O l i v e i r a J a c i n t h o
∗/
9
12
/∗
∗ CLASSE VELHA − CLASSE PRINCIPAL DA APLICACAO
∗/
15
// B i b l i o t e c a Scanner para c a p t u r a da j o g a d a do u s u á r i o
import j a v a . u t i l . Scanner ;
18
public c l a s s Velha
{
/∗
∗ CONSTANTES UTILIDAZAS
∗ TAM −> Tamanho do T a b u l e i r o
∗ PROF −> P r o f u n d i d a d e máxima da b u s c a no MiniMax . Se PROF = −1 o
algoritmo
∗ minimax i r á b u s c a r a té um e s t a d o t e r m i n a l .
∗/
21
24
16
A.1. Classe Velha.java
17
s t a t i c int TAM = 3 , PROF = −1;
27
public s t a t i c void main ( S t r i n g [ ] a r g s )
{
Scanner e n t = new Scanner ( System . i n ) ;
// O b j e t o da C l a s s e T a b u l e i r o
T a b u l e i r o t = new T a b u l e i r o (TAM) ;
// O b j e t o da C l a s s e Minimax
MiniMax mm = new MiniMax (TAM, PROF) ;
System . out . p r i n t l n ( " UFABC - J2VELHA \nBem vindo ao Jogo !\ nBoa Sorte !\n\n
") ;
// Imprime o t a b u l e i r o na Tela
t . imprimir ( ) ;
do
{ // Captura j o g a d a do u s u á r i o
int l , c ;
System . out . p r i n t f ( "Sua jogada :\r\ nLinha [0 - %d]: " , (TAM−1) ) ;
l = ent . nextInt ( ) ;
System . out . p r i n t f ( " Coluna [0 - %d]: " , (TAM−1) ) ;
c = ent . nextInt ( ) ;
// R e a l i z a j o g a d a do u s u á r i o
t . fazerJogada ( l , c ) ;
t . imprimir ( ) ;
// V e r i f i c a s e não é um e s t a d o t e r m i n a l
i f ( !mm. t e s t e t e r m i n a l ( t . t a b u l e i r o ) )
{
// A p l i c a o a l g o r i t m o minimax ao t a b u l e i r o
t . t a b u l e i r o = mm. d e c i s a o m i n i m a x ( t . t a b u l e i r o ) ;
System . out . p r i n t l n ( " Jogada do Computador :" ) ;
t . imprimir ( ) ;
}
} while ( !mm. t e s t e t e r m i n a l ( t . t a b u l e i r o ) ) ;
// V e r i f i c a o ganhador , ou um empate
i f (mm. ganhou ( t . t a b u l e i r o , 1 ) )
System . out . p r i n t l n ( "O computador ganhou !" ) ;
e l s e i f (mm. ganhou ( t . t a b u l e i r o , −1) )
System . out . p r i n t l n ( "Voc^
e ganhou !" ) ;
else
System . out . p r i n t l n ( " Empate !" ) ;
}
30
33
36
39
42
45
48
51
54
57
60
63
}
A.2. Classe Tabuleiro.java
A.2
3
6
18
Classe Tabuleiro.java
/∗
∗ UFABC − U n v e r s i d a d e F e d e r a l do ABC
∗ MC 3303 − I n t e l i g ê n c i a A r t i f i c i a l
∗ P r o f e s s o r Jerônimo P e l l e g r i n i
∗ Alunos :
∗
André F i l i p e de Moraes B a t i s t a
∗
L uı́ s Fernando de O l i v e i r a J a c i n t h o
∗/
9
12
/∗
∗ CLASSE TABULEIRO − REPRESENTA O TABULEIRO NO JOGO DA VELHA
∗/
15
18
21
24
27
30
33
36
39
42
45
public c l a s s T a b u l e i r o
{
/∗
∗ Vetor de c o n v e r s ã o para i m p r e s s ã o na t e l a
∗/
s t a t i c char [ ] c o n v e r s a o = { ’o’ , ’ ’ , ’x’ } ;
/∗
∗ M a t r i z do t a b u l e i r o
∗/
s t a t i c int [ ] [ ] t a b u l e i r o ;
/∗
∗ Tamanho do t a b u l e i r o
∗/
int tam ;
/∗
∗ D i v i s o r das l i n h a s na t e l a
∗/
String divisor ;
/∗
∗ O método c o n s t r u t o r r e c e b e como parametro o tamanho do t a b u l e i r o
∗/
public T a b u l e i r o ( int tam )
{
t h i s . tam = tam ;
t a b u l e i r o = new int [ tam ] [ tam ] ;
divisor = gerarDivisor () ;
}
/∗
A.2. Classe Tabuleiro.java
19
∗ Método i n v o c a d o para a j o g a d a do Jogador
∗/
public void f a z e r J o g a d a ( int l , int c )
{
i f ( t a b u l e i r o [ l ] [ c ] == 0 )
t a b u l e i r o [ l ] [ c ] = −1;
else
System . out . p r i n t l n ( " Posicao ja ocupada , perdeu a vez!" ) ;
}
48
51
54
/∗
∗ Metodo para a i m p r e s s ã o do t a b u l e i r o na t e l a
∗/
public void i m p r i m i r ( )
{
f o r ( int i = 0 ; i < tam ; i ++)
{
f o r ( int j = 0 ; j < tam ; j ++)
{
System . out . p r i n t f ( " %c %c" , c o n v e r s a o [ t a b u l e i r o [ i ] [ j ] + 1 ] , j == (
tam−1) ? ’ ’ : ’|’ ) ;
}
i f ( i != ( tam−1) )
System . out . p r i n t l n ( d i v i s o r ) ;
}
System . out . p r i n t l n ( "\r\n" ) ;
}
57
60
63
66
69
72
/∗
∗ Metodo para Gerar o D i v i s o r de Linhas . S e r v e para a u x i l i o da
visualizacao
∗ g r a f i c a do t a b u l e i r o
∗/
public S t r i n g g e r a r D i v i s o r ( )
{
S t r i n g d = new S t r i n g ( "\r\n" ) ;
75
78
f o r ( int i = 0 ; i < ( tam − 1 ) ; i ++)
{
d += " ---+" ;
}
81
84
d += " ---" ;
87
return d ;
}
90
}
A.3. Classe Sucessor.java
A.3
3
6
9
20
Classe Sucessor.java
/∗
∗ UFABC − U n v e r s i d a d e F e d e r a l do ABC
∗ MC 3303 − I n t e l i g ê n c i a A r t i f i c i a l
∗ P r o f e s s o r Jerônimo P e l l e g r i n i
∗ Alunos :
∗
André F i l i p e de Moraes B a t i s t a
∗
L uı́ s Fernando de O l i v e i r a J a c i n t h o
∗/
/∗
∗ CLASSE SUCESSOR − GERA OS ESTADOS DO JOGO DA VELHA
∗/
12
15
public c l a s s S u c e s s o r
{
int [ ] [ ] t a b u l e i r o ;
int u t i l i d a d e ;
/∗
∗ Metodo C o n s t r u t o r
∗/
public S u c e s s o r ( int [ ] [ ] tab )
{
/∗
∗ Cria um novo t a b u l e i r o , b a s e a d o no que f o i p a s s a d o
∗/
int tam = tab . l e n g t h ;
t a b u l e i r o = new int [ tam ] [ tam ] ;
18
21
24
27
f o r ( int i = 0 ; i < tam ; i ++)
f o r ( int j = 0 ; j < tam ; j ++)
t a b u l e i r o [ i ] [ j ] = tab [ i ] [ j ] ;
30
}
33
}
A.4. Classe Minimax.java
A.4
3
6
9
21
Classe Minimax.java
/∗
∗ UFABC − U n v e r s i d a d e F e d e r a l do ABC
∗ MC 3303 − I n t e l i g ê n c i a A r t i f i c i a l
∗ P r o f e s s o r Jerônimo P e l l e g r i n i
∗ Alunos :
∗
André F i l i p e de Moraes B a t i s t a
∗
L uı́ s Fernando de O l i v e i r a J a c i n t h o
∗/
/∗
∗ CLASSE MINIMAX − ALGORITMO DE BUSCA COMPETITIVA
∗/
12
15
import j a v a . u t i l . A r r a y L i s t ;
import j a v a . u t i l . C o l l e c t i o n s ;
18
public c l a s s MiniMax
{
/∗
∗ L i s t a de S u c e s s o r e s . Esta l i s t a Ãc
armazenada u t i l i z a n d o
∗ um A r r a y L i s t
∗/
s t a t i c A r r a y L i s t <S u c e s s o r > s u c e s s o r e s = new A r r a y L i s t <S u c e s s o r > ( ) ;
int tam , maxProf ;
21
24
27
30
33
36
39
42
/∗
∗ C o n s t r u t o r r e c e b e o tamanho do t a b u l e i r o e a p r o f u n d i d a d e máxima da
busca
∗/
public MiniMax ( int tam , int maxProf )
{
t h i s . tam = tam ;
i f ( maxProf > 0 )
t h i s . maxProf = maxProf ;
else
t h i s . maxProf = I n t e g e r .MAX VALUE; // Recebe o maior v a l o r de um
inteiro .
}
/∗
∗ Metodo de d e c i s a o do MiniMax
∗/
public int [ ] [ ] d e c i s a o m i n i m a x ( int [ ] [ ] tab )
{
A.4. Classe Minimax.java
22
/∗
∗ Limpa os s u c e s s o r e s
∗/
sucessores . clear () ;
45
48
/∗
∗ Recebe a u t i l i d a d e máxima
∗/
int v = valor max ( tab , true , 1 ) ;
51
/∗
∗ P e r c o r r e a l i s t a em b u s c a do p r i m e i r o s u c e s s o r com u t i l i d a d e máxima
∗/
for ( Sucessor s : s u c e s s o r e s )
i f ( s . u t i l i d a d e == v )
return s . t a b u l e i r o ;
54
57
60
return tab ;
}
63
66
69
public int valor max ( int [ ] [ ] tab , boolean prim , int p r o f )
{
/∗
∗ Se a p r o f u n d i d a d e f o r maior que a máxima ou o j o g o acabou , r e t o r n a
a
∗ utilidade
∗/
i f ( p r o f++ > maxProf | | t e s t e t e r m i n a l ( tab ) )
return u t i l i d a d e ( tab ) ;
72
75
78
81
84
87
/∗
∗ A t r i b u i o menor v a l o r de um i n t e i r o para v ( − i n f i n i t o )
∗/
int v = I n t e g e r . MIN VALUE ;
/∗
∗ P e r c o r r e os nós s u c e s s o r e s de MAX
∗/
f o r ( S u c e s s o r s : g e r a r s u c e s s o r e s ( tab , 1 ) )
{
v = Math . max( v , v a l o r m i n ( s . t a b u l e i r o , p r o f ) ) ;
s . utilidade = v;
/∗
∗ Se forem os p r i m e i r o s s u c e s s o r e s , a d i c i o n a na l i s t a de s u c e s s o r e s
...
∗/
i f ( prim )
A.4. Classe Minimax.java
23
s u c e s s o r e s . add ( s ) ;
}
90
return v ;
93
96
99
102
}
public int v a l o r m i n ( int [ ] [ ] tab , int p r o f )
{
/∗
∗ Se a p r o f u n d i d a d e f o r maior que a máxima ou o j o g o acabou , r e t o r n a a
∗ utilidade
∗/
i f ( p r o f++ > maxProf | | t e s t e t e r m i n a l ( tab ) )
return u t i l i d a d e ( tab ) ;
/∗
∗ A t r i b u i +I n f i n i t o
∗/
int v = I n t e g e r .MAX VALUE;
105
108
/∗
∗ P e r c o r r e os nós s u c e s s o r e s de MIN
∗/
f o r ( S u c e s s o r s : g e r a r s u c e s s o r e s ( tab , −1) )
{
v = Math . min ( v , valor max ( s . t a b u l e i r o , f a l s e , p r o f ) ) ;
s . utilidade = v;
}
111
114
117
return v ;
}
120
123
126
129
132
135
/∗
∗ Gera os s u c e s s o r e s de um j o g a d o r , a p a r t i r do e s t a d o a t u a l
∗/
public A r r a y L i s t <S u c e s s o r > g e r a r s u c e s s o r e s ( int [ ] [ ] tab , int v )
{
A r r a y L i s t <S u c e s s o r > s u c = new A r r a y L i s t <S u c e s s o r > ( ) ;
f o r ( int i = 0 ; i < tam ; i ++)
{
f o r ( int j = 0 ; j < tam ; j ++)
{
i f ( tab [ i ] [ j ] == 0 )
{
tab [ i ] [ j ] = v ;
s u c . add (new S u c e s s o r ( tab ) ) ;
tab [ i ] [ j ] = 0 ;
A.4. Classe Minimax.java
24
}
}
}
138
return s u c ;
141
144
147
}
/∗
∗ V e r i f i c a s e chegou em algum e s t a d o t e r m i n a l e c a s o a f i r m a t i v o f i n a l i z a
o jogo
∗/
public boolean t e s t e t e r m i n a l ( int [ ] [ ] tab )
{
return ( ganhou ( tab , 1 ) | | ganhou ( tab , −1) | | semEspaco ( tab ) ) ;
}
150
153
156
159
162
165
168
171
/∗
∗ Retorna a u t i l i d a d e
∗/
public int u t i l i d a d e ( int [ ] [ ] tab )
{
i f ( ganhou ( tab , 1 ) )
return 1 ;
e l s e i f ( ganhou ( tab , −1) )
return −1;
else
return 0 ;
}
/∗
∗ V e r i f i c a s e j o g a d o r ganhou
∗/
public boolean ganhou ( int [ ] [ ] tab , int v )
{
f o r ( int i = 0 ; i < tam ; i ++)
i f ( ganhouLinha ( tab , i , v ) | | ganhouColuna ( tab , i , v ) )
return true ;
i f ( ganhouDiag1 ( tab , v ) | | ganhouDiag2 ( tab , v ) )
return true ;
174
return f a l s e ;
177
}
180
/∗
∗ Ganhou na s e q u e n c i a de l i n h a s ?
∗/
A.4. Classe Minimax.java
186
private boolean ganhouLinha ( int [ ] [ ] tab , int l , int v )
{
f o r ( int i = 0 ; i < tam ; i ++)
i f ( tab [ l ] [ i ] != v )
return f a l s e ;
189
}
183
return true ;
198
/∗
∗ Ganhou na s e q u e n c i a de c o l u n a s ?
∗/
private boolean ganhouColuna ( int [ ] [ ] tab , int c , int v )
{
f o r ( int i = 0 ; i < tam ; i ++)
i f ( tab [ i ] [ c ] != v )
return f a l s e ;
201
}
192
195
return true ;
210
/∗
∗ Ganhou na s e q u e n c i a d i a g o n a l p r i n c i p a l ?
∗/
private boolean ganhouDiag1 ( int [ ] [ ] tab , int v )
{
f o r ( int i = 0 ; i < tam ; i ++)
i f ( tab [ i ] [ i ] != v )
return f a l s e ;
213
}
204
207
return true ;
216
219
222
/∗
∗ Ganhou na s e q u e n c i a d i a g o n a l s e c u n d a r i a ?
∗/
private boolean ganhouDiag2 ( int [ ] [ ] tab , int v )
{
f o r ( int i = 0 ; i < tam ; i ++)
i f ( tab [ ( tam−1)− i ] [ i ] != v )
return f a l s e ;
return true ;
225
}
228
/∗
∗ Nao tem mais e s p a c o s r e s t a n t e s no t a b u l e i r o . .
25
A.4. Classe Minimax.java
26
∗/
public boolean semEspaco ( int [ ] [ ] tab )
{
f o r ( int l = 0 ; l < tam ; l ++)
f o r ( int c = 0 ; c < tam ; c++)
i f ( tab [ l ] [ c ] == 0 )
return f a l s e ;
231
234
return true ;
237
}
}
Anexo B
J2 Velha: Novas Funcionalidades
A seguir tem-se a codificação completa de novas funcionalidades do J2 Velha. O programa agora realiza o algoritmo minimax juntamente com o mecanismo de Poda Alfa-Beta
(Alpha-beta pruning). Além disto, existe a possibilidade de jogar com elementos de acaso,
isto é, as peças podem deslizar em determinada jogada. Todo o código está comentado
para que estas funcionalidades sejam entendidas mais facilmente.
B.1
3
6
Classe Velha.java
/∗
∗ UFABC − U n v e r s i d a d e F e d e r a l do ABC
∗ MC 3303 − I n t e l i g ê n c i a A r t i f i c i a l
∗ P r o f e s s o r Jerônimo P e l l e g r i n i
∗ Alunos :
∗
André F i l i p e de Moraes B a t i s t a
∗
L uı́ s Fernando de O l i v e i r a J a c i n t h o
∗/
9
import j a v a . u t i l . Scanner ;
12
15
public c l a s s Velha
{
/∗
∗ Peças e s c o r r e g a d i a s ?
∗/
s t a t i c boolean ESCORREGA;
18
21
public s t a t i c void main ( S t r i n g [ ] a r g s )
{
Scanner e n t = new Scanner ( System . i n ) ;
27
B.1. Classe Velha.java
24
27
30
33
28
System . out . p r i n t ( "Voc^
e deseja jogar com peças escorregadias ? [s/n]: " )
;
String esc = ent . nextLine ( ) ;
i f ( e s c . charAt ( 0 ) == ’s’ | | e s c . charAt ( 0 ) == ’S’ )
{
ESCORREGA = true ;
System . out . p r i n t l n ( " Peças escorregadias ativadas ." ) ;
}
else
{
ESCORREGA = f a l s e ;
System . out . p r i n t l n ( " Peças escorregadias desativadas ." ) ;
}
36
39
42
45
48
51
54
57
T a b u l e i r o t = new T a b u l e i r o (ESCORREGA) ;
MiniMax mm = new MiniMax (ESCORREGA) ;
t . imprimir ( ) ;
do
{
int l , c ;
System . out . p r i n t f ( "Sua jogada :\r\ nLinha [0 - 3]: " ) ;
l = ent . nextInt ( ) ;
System . out . p r i n t f ( " Coluna [0 - 3]: " ) ;
c = ent . nextInt ( ) ;
t . fazerJogada ( l , c ) ;
t . imprimir ( ) ;
i f ( !mm. t e s t e t e r m i n a l ( t . t a b u l e i r o ) )
{
long time = System . c u r r e n t T i m e M i l l i s ( ) ;
t . t a b u l e i r o = mm. d e c i s a o m i n i m a x ( t . t a b u l e i r o ) ;
time = System . c u r r e n t T i m e M i l l i s ( ) − time ;
System . out . p r i n t l n ( " Jogada do Computador (" + time + " ms):" ) ;
t . imprimir ( ) ;
}
} while ( !mm. t e s t e t e r m i n a l ( t . t a b u l e i r o ) ) ;
60
63
66
int u = mm. u t i l i d a d e ( t .
i f (u < 0)
System . out . p r i n t l n
e l s e i f ( u == 0 )
System . out . p r i n t l n
else
System . out . p r i n t l n
tabuleiro ) ;
( " Parabens ! Voce ganhou ..." ) ;
( " Empatou !" ) ;
( "Voce realmente e pior que um computador ..." ) ;
B.1. Classe Velha.java
29
System . out . p r i n t l n ( "Voc^
e marcou " + mm. co ntaP onto s ( t . t a b u l e i r o , −1) + "
pontos ." ) ;
System . out . p r i n t l n ( "O computador marcou " + mm. co nta Ponto s ( t . t a b u l e i r o ,
1 ) + " pontos ." ) ;
69
}
72
}
B.2. Classe Tabuleiro.java
B.2
3
6
Classe Tabuleiro.java
/∗
∗ UFABC − U n v e r s i d a d e F e d e r a l do ABC
∗ MC 3303 − I n t e l i g ê n c i a A r t i f i c i a l
∗ P r o f e s s o r Jerônimo P e l l e g r i n i
∗ Alunos :
∗
André F i l i p e de Moraes B a t i s t a
∗
L uı́ s Fernando de O l i v e i r a J a c i n t h o
∗/ ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗/
9
import j a v a . u t i l . A r r a y L i s t ;
12
15
18
21
24
27
30
33
public c l a s s T a b u l e i r o
{
/∗
∗ Vetor de c o n v e r s ã o para i m p r e s s ã o na t e l a
∗/
s t a t i c char [ ] c o n v e r s a o = { ’o’ , ’ ’ , ’x’ } ;
/∗
∗ M a t r i z do t a b u l e i r o
∗/
s t a t i c int [ ] [ ] t a b u l e i r o ;
/∗
∗ Pe ças E s c o r r e g a d i a s ?
∗/
boolean e s c o r r e g a ;
/∗
∗ Construtor
∗
e n t r a d a : tamanho do t a b u l e i r o
∗/
public T a b u l e i r o ( boolean e s c o r r e g a )
{
this . escorrega = escorrega ;
t a b u l e i r o = new int [ 4 ] [ 4 ] ;
}
36
39
42
45
/∗
∗ Método i n v o c a d o para a j o g a d a do Jogador !
∗/
public void f a z e r J o g a d a ( int l , int c )
{
i f ( t a b u l e i r o [ l ] [ c ] == 0 )
{
/∗
∗ Se e s t i v e r j o g a n d o com p e c a s e s c o r r e g a d i a s . . .
30
B.2. Classe Tabuleiro.java
31
∗/
if ( escorrega )
{
/∗
∗ V e r i f i c a os v i z i n h o s l i v r e da posi ç ão . .
∗/
A r r a y L i s t <int [] > v i z i n h o s = v i z i n h o s L i v r e s ( l , c ) ;
48
51
/∗
∗ Se h o u ve r ao menos um v i z i n h o l i v r e , tem 20% de chance da peça
∗ escorregar . .
∗/
i f ( v i z i n h o s . s i z e ( ) > 0 && Math . random ( ) <= 0 . 2 )
{
/∗
∗ E s c o l h e um dos v i z i n h o s a l e a t o r i a m e n t e . .
∗/
int x = ( int ) ( Math . random ( ) ∗ v i z i n h o s . s i z e ( ) ) ;
/∗
∗ Transforma as c o o r d e n a d a s a t u a i s nas c o o r d e n a d a s do v i z i n h o
∗ escolhido . .
∗/
l = vizinhos . get (x) [ 0 ] ;
c = vizinhos . get (x) [ 1 ] ;
System . out . p r i n t l n ( "A peça escorregou e caiu na posiç~
ao : " + l +
", " + c ) ;
}
54
57
60
63
66
69
}
t a b u l e i r o [ l ] [ c ] = −1;
72
}
else
System . out . p r i n t l n ( " Posiç~
a o já ocupada , perdeu a vez!" ) ;
75
}
78
81
84
87
90
/∗
∗ Método que v e r i f i c a s e há v i z i n h o s l i v r e s , c o n s i d e r a n d o as d i a g o n a i s
...
∗/
public A r r a y L i s t <int [] > v i z i n h o s L i v r e s ( int l , int c )
{
A r r a y L i s t <int [] > v i z i n h o s = new A r r a y L i s t <int [] > ( ) ;
/∗
∗ V i z i n h o s da l i n h a a n t e r i o r , s e h o u ve r . . .
∗/
i f ( l > 0)
{
B.2. Classe Tabuleiro.java
93
i f ( c > 0)
i f ( t a b u l e i r o [ l − 1 ] [ c −1] == 0 )
v i z i n h o s . add (new int [ ] { l −1, c −1}) ;
96
i f ( t a b u l e i r o [ l − 1 ] [ c ] == 0 )
v i z i n h o s . add (new int [ ] { l −1, c } ) ;
i f ( c < 3)
i f ( t a b u l e i r o [ l − 1 ] [ c +1] == 0 )
v i z i n h o s . add (new int [ ] { l −1, c +1}) ;
99
}
102
/∗
∗ V i z i n h o s da mesma l i n h a . . .
∗/
i f ( c > 0)
i f ( t a b u l e i r o [ l ] [ c −1] == 0 )
v i z i n h o s . add (new int [ ] { l , c −1}) ;
105
108
i f ( c < 3)
i f ( t a b u l e i r o [ l ] [ c +1] == 0 )
v i z i n h o s . add (new int [ ] { l , c +1}) ;
111
/∗
∗ V i z i n h o s da l i n h a p o s t e r i o r , s e h o u ve r . . .
∗/
i f ( l < 3)
{
i f ( c > 0)
i f ( t a b u l e i r o [ l + 1 ] [ c −1] == 0 )
v i z i n h o s . add (new int [ ] { l +1, c −1}) ;
114
117
120
123
i f ( t a b u l e i r o [ l + 1 ] [ c ] == 0 )
v i z i n h o s . add (new int [ ] { l +1, c } ) ;
126
i f ( c < 3)
i f ( t a b u l e i r o [ l + 1 ] [ c +1] == 0 )
v i z i n h o s . add (new int [ ] { l +1, c +1}) ;
}
129
return v i z i n h o s ;
132
135
}
/∗
∗ Método para a impress ão do t a b u l e i r o na t e l a
∗/
public void i m p r i m i r ( )
32
B.2. Classe Tabuleiro.java
33
{
138
f o r ( int i = 0 ; i < 4 ; i ++)
{
f o r ( int j = 0 ; j < 4 ; j ++)
{
System . out . p r i n t f ( " %c %c" , c o n v e r s a o [ t a b u l e i r o [ i ] [ j ] + 1 ] , j == 3
? ’ ’ : ’|’ ) ;
}
i f ( i != ( 3 ) )
System . out . p r i n t l n ( "\r\n---+---+---+---" ) ;
}
System . out . p r i n t l n ( "\r\n" ) ;
141
144
147
}
150
}
B.3. Classe Sucessor.java
B.3
3
6
9
12
34
Classe Sucessor.java
/∗
∗ UFABC − U n v e r s i d a d e F e d e r a l do ABC
∗ MC 3303 − I n t e l i g ê n c i a A r t i f i c i a l
∗ P r o f e s s o r Jerônimo P e l l e g r i n i
∗ Alunos :
∗
André F i l i p e de Moraes B a t i s t a
∗
L uı́ s Fernando de O l i v e i r a J a c i n t h o
∗/
public c l a s s S u c e s s o r
{
int [ ] [ ] t a b u l e i r o ;
int u t i l i d a d e ;
/∗
∗ Construtor
∗/
public S u c e s s o r ( int [ ] [ ] tab )
{
/∗
∗ Cria um novo t a b u l e i r o , b a s e a d o no que f o i p a s s a d o
∗/
int tam = tab . l e n g t h ;
t a b u l e i r o = new int [ tam ] [ tam ] ;
15
18
21
24
f o r ( int i = 0 ; i < tam ; i ++)
f o r ( int j = 0 ; j < tam ; j ++)
t a b u l e i r o [ i ] [ j ] = tab [ i ] [ j ] ;
27
}
}
B.4. Classe Minimax.java
B.4
3
6
35
Classe Minimax.java
/∗
∗ UFABC − U n v e r s i d a d e F e d e r a l do ABC
∗ MC 3303 − I n t e l i g ê n c i a A r t i f i c i a l
∗ P r o f e s s o r Jerônimo P e l l e g r i n i
∗ Alunos :
∗
André F i l i p e de Moraes B a t i s t a
∗
L uı́ s Fernando de O l i v e i r a J a c i n t h o
∗/
9
import j a v a . u t i l . A r r a y L i s t ;
12
15
18
21
24
27
public c l a s s MiniMax
{
/∗
∗ L i s t a dos nós s u c e s s o r e s
∗/
s t a t i c A r r a y L i s t <S u c e s s o r > s u c e s s o r e s = new A r r a y L i s t <S u c e s s o r > ( ) ;
/∗
∗ Jogar com p e ç a s e s c o r r e g a d i a s ?
∗/
boolean e s c o r r e g a ;
/∗
∗ Construtor
∗/
public MiniMax ( boolean e s c o r r e g a )
{
this . escorrega = escorrega ;
}
30
33
36
39
42
45
/∗
∗ Método de d e c i s ã o do MiniMax
∗/
public int [ ] [ ] d e c i s a o m i n i m a x ( int [ ] [ ] tab )
{
/∗
∗ Limpa os s u c e s s o r e s
∗/
sucessores . clear () ;
/∗
∗ Recebe a u t i l i d a d e máxima
∗/
int v = valor max ( tab , I n t e g e r . MIN VALUE, I n t e g e r .MAX VALUE, true ) ;
B.4. Classe Minimax.java
36
/∗
∗ P e r c o r r e a l i s t a em b u s c a do p r i m e i r o s u c e s s o r com u t i l i d a d e máxima
∗/
for ( Sucessor s : s u c e s s o r e s )
i f ( s . u t i l i d a d e == v )
return s . t a b u l e i r o ;
48
51
return tab ;
54
57
60
63
66
}
public int valor max ( int [ ] [ ] tab , int a l f a , int beta , boolean prim )
{
/∗
∗ Se a p r o f u n d i d a d e f o r maior que a máxima ou o j o g o acabou , r e t o r n a a
∗ utilidade
∗/
i f ( t e s t e t e r m i n a l ( tab ) )
return u t i l i d a d e ( tab ) ;
/∗
∗ Atribui −I n f i n i t o
∗/
int v = I n t e g e r . MIN VALUE ;
69
72
75
78
81
84
87
90
/∗
∗ P e r c o r r e os nós s u c e s s o r e s de MAX
∗/
f o r ( S u c e s s o r s : g e r a r s u c e s s o r e s ( tab , 1 ) )
{
v = Math . max( v , v a l o r m i n ( s . t a b u l e i r o , a l f a , b e t a ) ) ;
s . utilidade = v;
/∗
∗ Se forem os p r i m e i r o s s u c e s s o r e s , a d i c i o n a na l i s t a de s u c e s s o r e s
...
∗/
i f ( prim )
s u c e s s o r e s . add ( s ) ;
/∗
∗ Poda Beta − Se o v a l o r f o r maior que b e t a , r e t o r n a o v a l o r . .
∗/
i f ( v >= b e t a )
return v ;
/∗
∗ Se o v a l o r f o r maior que Alfa , A l f a r e c e b e o v a l o r . . .
B.4. Classe Minimax.java
37
∗/
a l f a = Math . max( a l f a , v ) ;
93
}
return v ;
96
}
99
102
105
public int v a l o r m i n ( int [ ] [ ] tab , int a l f a , int b e t a )
{
/∗
∗ Se a p r o f u n d i d a d e f o r maior que a máxima ou o j o g o acabou , r e t o r n a a
∗ utilidade
∗/
i f ( t e s t e t e r m i n a l ( tab ) )
return u t i l i d a d e ( tab ) ;
/∗
∗ A t r i b u i +I n f i n i t o
∗/
int v = I n t e g e r .MAX VALUE;
108
111
/∗
∗ P e r c o r r e os nós s u c e s s o r e s de MIN
∗/
f o r ( S u c e s s o r s : g e r a r s u c e s s o r e s ( tab , −1) )
{
v = Math . min ( v , valor max ( s . t a b u l e i r o , a l f a , beta , f a l s e ) ) ;
s . utilidade = v;
114
117
120
/∗
∗ Poda A l f a − Se o v a l o r f o r menor que a l f a , r e t o r n a o v a l o r . . .
∗/
i f ( v <= a l f a )
return v ;
123
126
/∗
∗ Se v a l o r menor que Beta , Beta o r e c e b e . . .
∗/
b e t a = Math . min ( beta , v ) ;
129
}
132
return v ;
}
135
138
/∗
∗ Gera os s u c e s s o r e s de um j o g a d o r , a p a r t i r do e s t a d o a t u a l
∗/
B.4. Classe Minimax.java
141
144
147
150
153
156
159
162
165
168
171
174
public A r r a y L i s t <S u c e s s o r > g e r a r s u c e s s o r e s ( int [ ] [ ] tab , int v )
{
A r r a y L i s t <S u c e s s o r > s u c = new A r r a y L i s t <S u c e s s o r > ( ) ;
f o r ( int i = 0 ; i < 4 ; i ++)
{
f o r ( int j = 0 ; j < 4 ; j ++)
{
i f ( tab [ i ] [ j ] == 0 )
{
/∗
∗ Se e s t i v e r j o g a n d o com p e c a s e s c o r r e g a d i a s . . .
∗/
if ( escorrega )
{
/∗
∗ V e r i f i c a os v i z i n h o s l i v r e da p o s i ç ã o . .
∗/
A r r a y L i s t <int [] > v i z i n h o s = v i z i n h o s L i v r e s ( tab , i , j ) ;
/∗
∗ Se h o u ve r ao menos um v i z i n h o l i v r e , tem 20% de chance da
pe ça
∗ escorregar . .
∗/
i f ( v i z i n h o s . s i z e ( ) > 0 && Math . random ( ) <= 0 . 2 )
{
/∗
∗ E s c o l h e um dos v i z i n h o s a l e a t o r i a m e n t e . .
∗/
int x = ( int ) ( Math . random ( ) ∗ v i z i n h o s . s i z e ( ) ) ;
/∗
∗ Transforma as c o o r d e n a d a s a t u a i s nas c o o r d e n a d a s do
vizinho
∗ escolhido . .
∗/
i = vizinhos . get (x) [ 0 ] ;
j = vizinhos . get (x) [ 1 ] ;
}
}
tab [ i ] [ j ] = v ;
s u c . add (new S u c e s s o r ( tab ) ) ;
tab [ i ] [ j ] = 0 ;
177
}
}
180
}
183
38
return s u c ;
B.4. Classe Minimax.java
39
}
186
189
/∗
∗ Método que v e r i f i c a s e há v i z i n h o s l i v r e s , c o n s i d e r a n d o as d i a g o n a i s
...
∗/
public A r r a y L i s t <int [] > v i z i n h o s L i v r e s ( int [ ] [ ] t a b u l e i r o , int l , int c )
{
A r r a y L i s t <int [] > v i z i n h o s = new A r r a y L i s t <int [] > ( ) ;
192
195
198
/∗
∗ V i z i n h o s da l i n h a a n t e r i o r , s e h o u ve r . . .
∗/
i f ( l > 0)
{
i f ( c > 0)
i f ( t a b u l e i r o [ l − 1 ] [ c −1] == 0 )
v i z i n h o s . add (new int [ ] { l −1, c −1}) ;
201
i f ( t a b u l e i r o [ l − 1 ] [ c ] == 0 )
v i z i n h o s . add (new int [ ] { l −1, c } ) ;
204
i f ( c < 3)
i f ( t a b u l e i r o [ l − 1 ] [ c +1] == 0 )
v i z i n h o s . add (new int [ ] { l −1, c +1}) ;
207
}
210
213
/∗
∗ V i z i n h o s da mesma l i n h a . . .
∗/
i f ( c > 0)
i f ( t a b u l e i r o [ l ] [ c −1] == 0 )
v i z i n h o s . add (new int [ ] { l , c −1}) ;
216
219
222
225
228
i f ( c < 3)
i f ( t a b u l e i r o [ l ] [ c +1] == 0 )
v i z i n h o s . add (new int [ ] { l , c +1}) ;
/∗
∗ V i z i n h o s da l i n h a p o s t e r i o r , s e h o u ve r . . .
∗/
i f ( l < 3)
{
i f ( c > 0)
i f ( t a b u l e i r o [ l + 1 ] [ c −1] == 0 )
v i z i n h o s . add (new int [ ] { l +1, c −1}) ;
B.4. Classe Minimax.java
40
i f ( t a b u l e i r o [ l + 1 ] [ c ] == 0 )
v i z i n h o s . add (new int [ ] { l +1, c } ) ;
231
i f ( c < 3)
i f ( t a b u l e i r o [ l + 1 ] [ c +1] == 0 )
v i z i n h o s . add (new int [ ] { l +1, c +1}) ;
234
}
237
return v i z i n h o s ;
}
240
243
246
/∗
∗ Fim de j o g o ?
∗ O j o g o só termina s e não h o u v er mais e s p a ç o para j o g a d a s . . .
∗/
public boolean t e s t e t e r m i n a l ( int [ ] [ ] tab )
{
return ( semEspaco ( tab ) ) ;
}
249
252
255
/∗
∗ Retorna a u t i l i d a d e . . .
∗ Aqui a u t i l i d a d e c o n s i d e r a d a é a d i f e r e n ç a de p o n t o s e n t r e o
computador e
∗ o j o g a d o r , o computador não d e s e j a apenas vencer , mas também h u m i l h a r
=P
∗/
public int u t i l i d a d e ( int [ ] [ ] tab )
{
int pc , u s r ;
258
pc = co ntaPo nto s ( tab , 1 ) ;
u s r = co nta Ponto s ( tab , −1) ;
261
return ( pc−u s r ) ;
}
264
267
270
273
/∗
∗ V e r i f i c a s e j o g a d o r ganhou
∗/
public int co ntaP onto s ( int [ ] [ ] tab , int v )
{
int p o n t o s = 0 ;
f o r ( int i = 0 ; i < 4 ; i ++)
{
p o n t o s += c o nta L inh a ( tab , i , v ) ;
B.4. Classe Minimax.java
41
p o n t o s += contaColuna ( tab , i , v ) ;
276
}
279
p o n t o s += contaDiag1 ( tab , v ) ;
p o n t o s += contaDiag2 ( tab , v ) ;
return p o n t o s ;
282
285
288
291
294
}
/∗
∗ Pontos na s e q u e n c i a de l i n h a s ?
∗
∗ Método de contagem b i n á r i a . . um b y t e é d e s n e c e s s á r i o , p r e c i s a r i a
apenas
∗ de 4 b i t s . . Basicamente , para cada p o s i ç ã o a t r i b u i −s e o v a l o r 1 na
mesma
∗ p o s i ç ã o do b y t e , i n d i c a n d o que a l i é d e l e . No f i n a l checamos as 3
∗ p o s s i b i l i d a d e s de marcar pontos , 4 p o s i ç õ e s v i z i n h a s ( 1 1 1 1 ) ou 3
posicoes
∗ v i z i n h a s (0111 ou 1110) . Qualquer o u t r a combinação t e r i a menos do que
∗ 3 p o s i ç õ e s v i z i n h a s e não marcariam p o n t o s .
∗/
private int c o nt a L in ha ( int [ ] [ ] tab , int l , int v )
{
byte soma = 0 ;
297
f o r ( int i = 0 ; i < 4 ; i ++)
i f ( tab [ l ] [ i ] == v )
soma += ( 1 << i ) ;
300
i f ( soma == 1 5 ) // 1111
return 3 ;
e l s e i f ( ( soma == 7 ) | |
return 1 ;
else
return 0 ;
303
306
( soma == 1 4 ) ) // 0111 v 1110
}
309
312
315
318
/∗
∗ Pontos na s e q u e n c i a de c o l u n a s ?
∗/
private int contaColuna ( int [ ] [ ] tab , int c , int v )
{
int soma = 0 ;
f o r ( int i = 0 ; i < 4 ; i ++)
i f ( tab [ i ] [ c ] == v )
B.4. Classe Minimax.java
42
soma += ( 1 << i ) ;
i f ( soma == 1 5 ) // 1111
return 3 ;
e l s e i f ( ( soma == 7 ) | | ( soma == 1 4 ) ) // 0111 v 1110
return 1 ;
else
return 0 ;
321
324
327
330
333
}
/∗
∗ Ganhou na s e q u e n c i a d i a g o n a l ?
∗/
private int contaDiag1 ( int [ ] [ ] tab , int v )
{
int soma = 0 ;
int p e x t r a = 0 ;
336
f o r ( int i = 0 ; i < 4 ; i ++)
i f ( tab [ i ] [ i ] == v )
soma += ( 1 << i ) ;
339
/∗
∗ Nas duas d i a g o n a i s a s e g u i r só é p o s sı́ v e l formar s e q u e n c i a s de 3 ,
∗ podendo−s e a d i c i o n a r e n t a o apenas 1 ponto . . . .
∗/
i f ( tab [ 1 ] [ 0 ] == v && tab [ 2 ] [ 1 ] == v && tab [ 3 ] [ 2 ] == v )
p e x t r a ++;
i f ( tab [ 0 ] [ 1 ] == v && tab [ 1 ] [ 2 ] == v && tab [ 2 ] [ 3 ] == v )
p e x t r a ++;
342
345
348
i f ( soma == 1 5 )
return 3 + p e x t r a ;
e l s e i f ( ( soma == 7 ) | | ( soma == 1 4 ) )
return 1 + p e x t r a ;
else
return 0 + p e x t r a ;
351
354
}
357
360
/∗
∗ Ganhou na s e q u e n c i a d i a g o n a l ?
∗/
363
{
private int contaDiag2 ( int [ ] [ ] tab , int v )
int soma = 0 ;
int p e x t r a = 0 ;
B.4. Classe Minimax.java
43
366
f o r ( int i = 0 ; i < 4 ; i ++)
i f ( tab [3− i ] [ i ] == v )
soma += ( 1 << i ) ;
369
/∗
∗ Nas duas d i a g o n a i s a s e g u i r só é p o s sı́ v e l formar s e q u e n c i a s de 3 ,
∗ podendo−s e a d i c i o n a r e n t a o apenas 1 ponto . . . .
∗/
i f ( tab [ 0 ] [ 2 ] == v && tab [ 1 ] [ 1 ] == v && tab [ 2 ] [ 0 ] == v )
p e x t r a ++;
i f ( tab [ 1 ] [ 3 ] == v && tab [ 2 ] [ 2 ] == v && tab [ 3 ] [ 1 ] == v )
p e x t r a ++;
372
375
378
i f ( soma == 1 5 )
return 3 + p e x t r a ;
e l s e i f ( ( soma == 7 ) | | ( soma == 1 4 ) )
return 1 + p e x t r a ;
else
return 0 + p e x t r a ;
381
384
}
387
396
/∗
∗ Não tem mais e s p a c o s r e s t a n t e s no t a b u l e i r o . .
∗/
public boolean semEspaco ( int [ ] [ ] tab )
{
f o r ( int l = 0 ; l < 4 ; l ++)
f o r ( int c = 0 ; c < 4 ; c++)
i f ( tab [ l ] [ c ] == 0 )
return f a l s e ;
399
}
390
393
return true ;
}

Documentos relacionados