Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
ufabc
J2 Velha
Uma Implementacao Java do Jogo da Velha
Utilizando o Algoritmo MiniMax
Andr
e Filipe de Moraes Batista
andre.batista@ufabc.edu.br
Disciplina de Intelig
encia Artificial
o
Prof Jeronimo Pellegrini
Santo Andre, Junho de 2008
Sum
ario
1 Jogos em IA
1.1 Minimax - Algoritmo de Busca Competitiva . . . . . . . . . . . . . . . . .
1
1
4
4
8
Anexos
16
A J2 Velha: C
odigos
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
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
ii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
Captulo 1
Jogos em IA
Para a maioria das pessoas o termo jogo e considerado como um passatempo do dia-a-dia.
Para as criancas 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 estrategias que lhes deem vantagens sobre os adversarios. Ou
seja, o resultado do jogo e determinado pelas estrategias utilizadas pelos jogadores. O
ramo da Matematica que pensa de semelhante maneira e 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 sao uma das areas mais antigas desenvolvidas em Inteligencia
Artificial (IA). Em 1950, desde que os computadores se tornaram programaveis, o primeiro
jogo de xadrez foi criado por Claude Shannon e por Alan Turing. Desde entao diversos
progressos ocorreram nesta area, de tal forma que os sistemas atuais sao capazes de
rivalizar e ganhar de um dos melhores jogadores de xadrez da historia, 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
codigo de programacao e em linguagem C e e executado no sistema operacional AIX. O
resultado e uma maquina escalavel capaz de calcular entre 100 e 200 bilhoes de jogadas
em aproximadamente 3 minutos. No primeiro confronto entre os dois, a vitoria foi de
Kasparov. Ate que em 1997 a IBM desdobrou-se em constantes desenvolvimentos e atualizacoes de modo a melhorar o desempenho do Deep Blue. O resultado de tanto esforco
foi que Garry Kasparov foi vencido em 1997 pelo Deep Blue. A Figura 1.1 mostra uma
cena desta disputa.
1.1
Em um ambiente multiagente os agentes convivem com situacoes de cooperacao e competicao. Um ambiente competitivo e aquele em que as metas dos agentes estao em constante
1
conflito. Para tais situacoes e preciso desenvolver tecnicas de busca competitiva entre os
neste ponto que a teoria dos jogos pode auxiliar na construcao de um agente
agentes. E
racional.
Em IA os jogos normalmente sao de um tipo bastante especializados - algumas vezes
denominados determinsticos de revezamento de dois jogadores de soma zero com informacoes perfeitas. Isto representa ambiente determinsticos completamente observaveis em
que existem dois agentes cujas acoes devem se alternar e em que os valores de utilidade no
fim do jogo sao sempre iguais e opostos. Por exemplo, se um jogador ganha um jogo de
xadrez (+1), o outro jogador necessariamente perde (-1). Essa oposicao entre as funcoes
de utilidades dos agentes que gera a situacao de competicao.
O MiniMax e um algoritmo de busca competitiva que seleciona a melhor acao a ser
feita em uma situacao ou em um jogo, onde dois jogadores se empenham em alcancar
objetivos mutuamente exclusivos. Ele se aplica especialmente na busca em arvores de
jogo para determinar qual a melhor jogada para o jogador atual. O algoritmo se baseia
no princpio de que em cada jogada, o jogador ira escolher o melhor movimento possvel.
A arvore de jogo consiste de todas as jogadas possveis para o jogador atual como nos
filhos da raiz, e todas as jogadas disponveis para o proximo jogador como filhas destes nos
e assim por diante, ate o nvel que se desejar. Cada ramificacao da arvore representa um
movimento que o jogador pode fazer em tal momento do jogo. Uma busca mais profunda
na arvore fornece mais informacoes sobre as possveis vantagens ou armadilhas e portanto
resulta em uma jogada melhor.
O MiniMax faz uma busca que determina todas as possveis continuacoes do jogo ate
o nvel desejado, avaliando e atribuindo um valor a cada movimento possvel. A busca
entao retorna na arvore de jogo alternando entre escolher o valor mais alto e o valor mais
baixo entre os valores da jogadas em um nvel. O metodo de busca consiste na ideia de
maximizar a utilidade supondo que o adversario vai tentar minimiza-la. Em termos de
busca, e realiza uma busca cega em profundidade, o agente e o MAX e seu adversario e o
MIN.
Algoritmo 1 MINIMAX
func
ao DECISAO-MINIMAX(estado)
retorna uma acao
entradas: estado, estado corrente no jogo
v VALOR-MAX(estado)
retornar a acao em SUCESSORES(estado) com valor v
func
ao VALOR-MAX(estado) retorna um valor de utilidade
se TESTE-TERMINAL(estado) ent
ao retornar UTILIDADE(estado)
v
para a, s em SUCESSORES(estado) faca
v MAX(v, VALOR-MIN(s))
retornar v
func
ao VALOR-MIN(estado) retorna um valor de utilidade
se TESTE-TERMINAL(estado) ent
ao retornar UTILIDADE(estado)
v
para a, s em SUCESSORES(estado) faca
v MAX(v, VALOR-MAX(s))
retornar v
Se fosse o caso de se tratar de uma busca normal, bastava percorrer-se a arvore ate
aos nos terminais e escolher o caminho que levasse ao no com maior valor de utilidade.
Mas nao e assim, visto existir outro jogador. Assim, e necessario, escolher a partir de
cada no filho, o menor valor de utilidade, e copia-lo para o no pai, recursivamente ate ao
no inicial. Este e o algoritmo MiniMax. Isto deve-se ao fato, do jogador MIN tentar
minimizar o ganho do jogador MAX, pois ele tentara escolher uma jogada, dentro das
possveis, que de menos pontos ao jogador adversario. Na Caixa de Algoritmo 1 tem-se o
algoritmo MiniMax.
No Captulo que segue tem-se uma implementacao do Jogo da Velha utilizando a
linguagem Java e o algoritmo MiniMax.
Captulo 2
J2 Velha: Uma Abordagem Java ao
Jogo da Velha
Conhecido tambem como Jogo do Galo, ou Tic Tac Toe, o jogo da velha e um jogo
extremamente simples, que nao 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 nao terem mais condicoes de bordar em razao
da fraqueza de suas vistas, jogavam este jogo simples.
O jogo da velha e um dos exemplos mais classicos de utilizacao do algoritmo Minimax.
O estado inicial e os movimentos validos para cada lado definem a arvore do jogo correspondente ao jogo. A Figura 2.1 mostra parte da arvore de jogo para o jogo da velha. A
partir do estado inicial, MAX tem nove movimentos possveis. O jogo se alterna entre
a colocacao de um X por MAX e a colocacao de um O por MIN ate que se alcance nos
de folhas correspondentes a estados terminais, tais que um jogador tem tres smbolos em
uma linha, coluna ou ainda diagonal; ou ate que todos os quadrados estejam preenchidos.
O n
umero em cada no de folha indica o valor de utilidade do estado terminal, do ponto
de vista de MAX; valores altos sao considerados bons para MAX e ruins para MIN. Cabe
a MAX usar a arvore de busca para determinar o melhor movimento.
2.1
J2 Velha
J2 Velha (Java 2 Velha) e uma implementacao do Jogo da Velha desenvolvida na Linguagem Java utilizando o algoritmo MiniMax. Consiste de 4 classes, quais sejam:
1. Velha.java - Classe principal da Aplicacao;
2. Minimax.java - Classe responsavel em aplicar o algoritmo MiniMax;
3. Tabuleiro.java - Classe responsavel pela manipulacao do tabuleiro do jogo;
4
2.1. J2 Velha
MiniMax
2.1. J2 Velha
/
sucessores . clear () ;
/
Recebe a u t i l i d a d e m
axima
/
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 maxima
/
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 maxima 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
a 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
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 maxima 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
/
Percorre os n
o 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
Exemplos
A seguir tem-se a execucao de algumas jogadas. Primeiramente vamos utilizar um tabuleiro de tamanho 3x3. Para tal nao se faz necessaria a definicao de uma profundidade
maxima, pois a resposta do algoritmo e rapida. Executando o classe Velha.java tem-se
a seguinte sada 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 entao 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
Sua jogada:
Linha [0 - 2]:
Para decidir onde jogar, o computador efetuou todo o algoritmo minimax e escolheu
uma posicao que lhe favoreca, ao mesmo tempo que prejudique (nao agora, pode ser nas
proximas jogadas) o adversario. 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 posicao que evita que o adversario
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 ganhara a partida. O jogador decide
jogar na linha 2, coluna 2. Tem-se a vitoria 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!
Voce pode verificar o funcionamento do jogo com um tabuleiro 4x4. Basta mudar as
variaveis TAM e PROF na classe Velha. Devido `a complexidade do algoritmo recomenda-se
utilizar uma profundidade 5 para que o tempo de execucao do mesmo seja razoavel. 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!
15
Anexo A
J2 Velha: C
odigos
A seguir tem-se a codificacao completa da aplicacao. Esta foi desenvolvida utilizando a
IDE NetBeans e JDK 1.6.
A.1
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 e n c i a A r t i f i c i a l
P r o f e s s o r Jer
o nimo P e l l e g r i n i
Alunos :
Andre F i l i p e de Moraes B a t i s t a
L us Fernando de O l i v e i r a J a c i n t h o
/
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
ario
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
axima da b u s c a no MiniMax . Se PROF = 1 o
algoritmo
minimax i r
a b u s c a r a te um e s t a d o t e r m i n a l .
/
21
24
16
17
30
33
36
39
42
45
48
51
54
57
60
63
}
A.2
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 e n c i a A r t i f i c i a l
P r o f e s s o r Jer
o nimo P e l l e g r i n i
Alunos :
Andre F i l i p e de Moraes B a t i s t a
L us Fernando de O l i v e i r a J a c i n t h o
/
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
a o para i m p r e s s
a 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 me 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 () ;
}
/
19
48
51
54
/
Metodo para a i m p r e s s
a 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 == (
tam1) ? : | ) ;
}
i f ( i != ( tam1) )
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
81
84
d += " ---" ;
87
return d ;
}
90
}
A.3
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 e n c i a A r t i f i c i a l
P r o f e s s o r Jer
o nimo P e l l e g r i n i
Alunos :
Andre F i l i p e de Moraes B a t i s t a
L us 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
30
}
33
}
A.4
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 e n c i a A r t i f i c i a l
P r o f e s s o r Jer
o nimo P e l l e g r i n i
Alunos :
Andre F i l i p e de Moraes B a t i s t a
L us 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
{
/
armazenada u t i l i z a n d o
L i s t a de S u c e s s o r e s . Esta l i s t a Ac
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 mAxima
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 )
{
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 mAxima
/
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 mAxima
/
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
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
o 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 )
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
axima 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
o 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 ;
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 ?
/
186
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 [ ( tam1) 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
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 codificacao 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). Alem disto, existe a possibilidade de jogar com elementos de acaso,
isto e, as pecas podem deslizar em determinada jogada. Todo o codigo esta comentado
para que estas funcionalidades sejam entendidas mais facilmente.
B.1
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 e n c i a A r t i f i c i a l
P r o f e s s o r Jer
o nimo P e l l e g r i n i
Alunos :
Andre F i l i p e de Moraes B a t i s t a
L us Fernando de O l i v e i r a J a c i n t h o
/
import j a v a . u t i l . Scanner ;
12
15
public c l a s s Velha
{
/
Pec as e s c o r r e g a d i a s ?
/
s t a t i c boolean ESCORREGA;
18
21
27
24
27
30
33
28
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 ..." ) ;
29
69
}
72
}
B.2
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 e n c i a A r t i f i c i a l
P r o f e s s o r Jer
o nimo P e l l e g r i n i
Alunos :
Andre F i l i p e de Moraes B a t i s t a
L us Fernando de O l i v e i r a J a c i n t h o
/ /
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
a o para i m p r e s s
a 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 Aas
Escorregadias ?
/
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
/
Metodo 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
31
/
if ( escorrega )
{
/
Ao
V e r i f i c a os v i z i n h o s l i v r e da posi A
..
/
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 pec 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
c a escorregou e caiu na posi
c~
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
c~
a o j
a ocupada , perdeu a vez!" ) ;
75
}
78
81
84
87
90
/
Metodo que v e r i f i c a s e h
a 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)
{
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
}
/
32
33
138
141
144
147
}
150
}
B.3
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 e n c i a A r t i f i c i a l
P r o f e s s o r Jer
o nimo P e l l e g r i n i
Alunos :
Andre F i l i p e de Moraes B a t i s t a
L us 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
27
}
}
B.4
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 e n c i a A r t i f i c i a l
P r o f e s s o r Jer
o nimo P e l l e g r i n i
Alunos :
Andre F i l i p e de Moraes B a t i s t a
L us Fernando de O l i v e i r a J a c i n t h o
/
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
os 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 c 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
/
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 )
{
/
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
axima
/
int v = valor max ( tab , I n t e g e r . MIN VALUE, I n t e g e r .MAX VALUE, true ) ;
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
axima
/
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
axima 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
o 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 . . .
37
/
a l f a = Math . max( a l f a , v ) ;
93
}
return v ;
96
}
99
102
105
108
111
/
P e r c o r r e os n
o 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
/
141
144
147
150
153
156
pe Aa
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 ] ;
}
159
162
165
168
171
174
177
tab [ i ] [ j ] = v ;
s u c . add (new S u c e s s o r ( tab ) ) ;
tab [ i ] [ j ] = 0 ;
}
}
180
}
183
38
return s u c ;
39
}
186
189
/
Metodo que v e r i f i c a s e h
a 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}) ;
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
o termina s e n
a o h o u v er mais e s p a c 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 e a d i f e r e n c 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
a o d e s e j a apenas vencer , mas tambem 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
return ( pcu 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 ) ;
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 ?
Metodo de contagem b i n
a r i a . . um b y t e e d e s n e c e s s a
rio , precisaria
apenas
de 4 b i t s . . Basicamente , para cada p o s i c
a o a t r i b u i s e o v a l o r 1 na
mesma
p o s i c a
o do b y t e , i n d i c a n d o que a l i e 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 c
o 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 combinac
a o t e r i a menos do que
3 p o s i c
o e s v i z i n h a s e n
a 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
300
i f ( soma == 1 5 ) // 1111
return 3 ;
e l s e i f ( ( soma == 7 ) | |
return 1 ;
else
return 0 ;
303
306
}
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 )
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
339
/
Nas duas d i a g o n a i s a s e g u i r s
o e p o s s v e l formar s e q u e n c i a s de 3 ,
podendos 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
43
366
369
/
Nas duas d i a g o n a i s a s e g u i r s
o e p o s s v e l formar s e q u e n c i a s de 3 ,
podendos 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
ao 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 ;
}