Vous êtes sur la page 1sur 13

Capa

Relatório de Avaliação Intercalar do 1º Trabalho Prático da Disciplina


de Programação em Lógica

Jogo Escolhido:

Elementos do Grupo:

Daniel Augusto Gama Castro Silva: ei01083@fe.up.pt


Vasco Hugo Vinhas Gonçalves Moreira: vasco.vinhas@fe.up.pt

Página 1 de 13
Resumo & Introdução

Resumo

O trabalho consistirá no desenvolvimento do jogo de tabuleiro Quarto!® recorrendo ao


Prolog como linguagem de implementação. O projecto terá ainda um módulo de
visualização gráfica 3D a ser implementado em linguagem C++.
A aplicação final deverá permitir dois humanos jogarem entre si, assim como um jogo
entre um humano e o computador, podendo o jogador escolher o nível de dificuldade
que achar mais adequado, escolhendo, para tal, quais as regras a usar.

Nota: Para mais informações quanto a este método de regulação do nível de


dificuldade por favor consulte o capítulo: Descrição do Problema

Introdução

Pretende-se que com este trabalho se ganhe sensibilidade para o paradigma da


programação em lógica, usando para tal, estratégias de resolução de problemas até agora
pouco exploradas. Toma-se também como objectivo a aquisição de conhecimento no
domínio da teoria dos jogos.
A concretização destas motivações gerais na escolha do jogo em questão traduz-se no
facto de este ser já do conhecimento de um dos elementos do grupo e de se ter a
convicção que, muito embora o jogo se revista de uma aparente simplicidade, devido
em parte ao reduzido número de regras, é na realidade um jogo muito interessante e
desafiador das capacidades dos jogadores, tornado-se especialmente complexo quando
se põem em campo todas as combinações de término permitidas.
Outro aspecto que cativou a atenção dos elementos do grupo foram as diversas
particularidades deste jogo que tornam a sua implementação muito diferente da dos
jogos mais tradicionais. São de notar as seguintes características:

• As peças em jogo são comuns aos dois jogadores.


• É o jogador adversário que escolhe a peça a ser jogada.
• A avaliação do tabuleiro é particularmente difícil, na medida em que as peças
são comuns e existe sempre uma dependência das peças ainda por jogar.
• É possível regular o grau de dificuldade do jogo, bastando escolher quais as
regras a usar, podendo assim ser jogado por todo o tipo de jogadores.

Será difícil encontrar maior motivação do que implementar o jogo mais premiado de
todos os tempos!

Página 2 de 13
Descrição, Representação & Visualização

Descrição do Problema

O jogo Quarto!® foi criado por Blaise Muller, sendo comercializado em 1991 pela
Gigamic S.A.. Pode-se dizer que o seu inventor foi ‘beber’ inspiração a jogos mais
tradicionais como o ‘Jogo do Galo’ ou
o ‘Quatro em Linha’, tendo-lhes
adicionado um pequeno grupo de
regras que fizeram deste jogo, num
espaço de tempo pouco maior de que
uma década, o jogo mais premiado de
sempre [3,4].

Regras do Jogo

Apresentação e Preparação
• Um tabuleiro de 16 casas.
• 16 peças diferentes tendo cada uma quatro características: cor clara ou escura,
forma redonda ou quadrada, alta ou baixa, maciça ou oca.
No começo da partida, as peças são dispostas ao lado do tabuleiro.

Objectivo do Jogo

Formar no tabuleiro um alinhamento de 4 peças que tenham no mínimo uma


característica em comum.
Esse alinhamento poderá ser horizontal, vertical ou diagonal.

Desenvolvimento de uma Partida


• O primeiro jogador é tirado à sorte.
• De seguida escolhe uma das 16 peças e entrega-a ao seu adversário.
• Este deverá colocá-la numa das casas do tabuleiro e, em seguida, escolher uma
das 15 peças restantes para entregar ao seu adversário.
• Por sua vez, este coloca a peça numa das casas disponíveis do tabuleiro e assim
sucessivamente...

Vencedor da Partida

A partida é ganha pelo primeiro jogador que disser “Quarto!”.


1. Um jogador faz “Quarto!” e ganha a partida quando coloca a peça que lhe é
dada:
• Forma um alinhamento de 4 peças de cor clara ou escura, ou 4 peças
redondas ou quadradas, ou 4 peças altas ou baixas, ou 4 peças maciças
ou ocas.
• Não é obrigatório que esse mesmo jogador tenha colocado as outras 3
peças.
• Ele deverá proclamar a sua vitória dizendo “Quarto!”.

Página 3 de 13
Descrição, Representação & Visualização
2. Se esse jogador não vir o alinhamento e entregar uma peça ao adversário, este
último pode nesse momento dizer “Quarto!”, e, mostrando tal alinhamento,
ganhar a partida.
3. Se nenhum dos jogadores vir o alinhamento durante a vez em que jogam e
quando ele se forma, ninguém poderá ganhar a partida e o jogo continuará.

Fim da Partida
• Vitória: Um jogador diz e indica um “Quarto!”
• Igualdade: Todas as peças foram colocadas sem haver um vencedor.

Tempo de Duração de uma Partida


• De 10 a 20 minutos, em média
• Em torneio, é possível dar a cada jogador um tempo limite de um minuto por
jogada.

Variante para Jogadores Iniciados (crianças...)

Para se iniciar progressivamente pode-se jogar unicamente com 1, 2 ou 3 características


como critérios de alinhamento.
Exemplo: Formar no tabuleiro um alinhamento de 4 peças com a mesma cor (uma única
característica).

Variante para Jogadores Experimentados

O objectivo do jogo é o de formar um alinhamento ou um quadrado de 4 peças que


tenham no mínimo uma característica em comum.
Existem assim 9 possibilidades suplementares de fazer “Quarto!”.
Adicionalmente, pode ainda considerar-se como alinhamento quatro peças em ‘L’ com
uma característica em comum, no mínimo.

Representação do Estado do Jogo

Tratando-se de um jogo que se desenrola num tabuleiro com 4 linhas e outras tantas
colunas, estando as casas organizadas de uma forma perfeitamente ortogonal e sendo as
listas a estrutura de dados por excelência em Prolog, a forma escolhida para a
representação do estado do tabuleiro foi a de uma lista de listas, em que cada um dos
elementos representa uma peça ou um espaço disponível. Deste modo é fácil identificar
a posição de cada uma das peças, usando para tal efeito, um sistema referencial
bidimensional cartesiano.

Tabuleiro vazio:
tabuleiro( [ [22,22,22,22], [22,22,22,22], [22,22,22,22], [22,22,22,22] ] ).

Na medida em que as peças são comuns aos 2 jogadores, torna-se também necessária
manter a informação referente às peças ainda disponíveis. Para tal também foi usada
uma lista de listas em tudo idêntica à usada para representar o tabuleiro de jogo.

Página 4 de 13
Descrição, Representação & Visualização
Peças disponíveis no inicio:
reserva( [ [15,14,13,12], [11,10,9,8], [7,6,5,4], [3,2,1,0] ] ).

Tendo o jogo 16 peças, todas elas diferentes mas tendo cada uma a possibilidade de
assumir 2 estados diferentes e complementares de cada uma das 4 características, optou-
-se por uma representação numérica das peças. Tal representação conterá em si mesma
toda a informação necessária para caracterizar cada peça. Explorando a referida
dualidade que cada uma das características pode assumir, atribuiu-se a cada peça um
número de 0 a 15 em que cada digito na base 2 identifica univocamente cada
característica da peça.
A título de exemplo, a peça identificada pelo número 12, 1100 na base 2, é uma peça
grande, de forma quadrada, de cor clara e oca, por outro lado a peça com o número 3,
0011 em binário será uma peça pequena, redonda, de cor escura e maciça. Foi reservado
o número 22 para assinalar uma casa vazia.

Representação de uma Jogada

Atendendo, mais uma vez, à particularidade do jogo, também a definição de jogada não
é a mais usual, na medida em que as jogadas se processam de uma forma peculiar e em
duas fases. A primeira, em que um jogador coloca a peça previamente escolhida pelo
seu adversário numa casa vazia no tabuleiro, e uma segunda em que escolhe uma
qualquer peça disponível para entregar ao adversário.
É de salientar que, quer a primeira jogada, quer a última, são ‘meias-jogadas’, na
medida em que o jogador só tem de escolher a peça para entregar ao adversário, ou
somente colocar a peça em jogo.
Uma jogada pode assim ser definida como um tuplo variável consoante a altura de jogo:
Mov = J-(X,Y)-P1-P2 % Jogador J coloca peça P1 em (X,Y) e escolhe peça P2
Mov = J-(X,Y)-P % Jogada final - Jogador J coloca peça P em (X,Y)
Mov = J-P % Jogada inicial - Jogador J escolhe peça P para o adversário

A Figura 1representa esquematicamente uma jogada.

Ilustração
Figura 1 1- Diagrama
- Diagramadedeuma
umaJogada
Jogada

Assim, quer para colocar uma peça no tabuleiro como para especificar uma peça para
dar ao adversário usou-se a seguinte relação:

Página 5 de 13
Descrição, Representação & Visualização
insert_peca(Peca,PecaNova,X,Y,Tabuleiro,TabuleiroNovo):-
insert_peca_aux(1,Peca,PecaNova,X,Y,Tabuleiro,TabuleiroNovo),!.

O algoritmo usado é o de copiar linha a linha o conteúdo de Tabuleiro para


TabuleiroNovo até chegar à linha onde se pretende inserir a peça; uma vez aí, passa-se a
copiar elemento a elemento até se chegar à peça a substituir. Depois de trocar, copia-se
elemento a elemento até acabar a linha em questão e, depois, novamente, linhas inteiras.

Visualização do Tabuleiro

Devido, novamente, às particularidades do jogo, e especialmente ao facto de todas as 16


peças serem diferentes, a sua representação em modo texto foi alvo de especial atenção.
Ao contrário da maioria dos jogos tradicionais, em que uma peça poderia ser
identificada por um único carácter, teve de se optar por uma representação numa matriz
de caracteres de dimensão 16x8. Teve-se, ainda, de mostrar quais as peças ainda
disponíveis para escolha, sendo no entanto tal representação em tudo semelhante à do
tabuleiro de jogo.
Assim, a relação que permite visualizar o tabuleiro mostra a linha que é a cabeça da
lista, até ao fim da recursividade:

mostra([],[],_).
mostra( [L|Resto], [H|T], N):- draw(middle, N), N2 is N+1,
mostra_linha_linha(L,H,1), draw(middle, N),
draw(base), mostra(Resto, T, N2).
mostra_tabuleiro([L|Resto], [H|T]):- draw(top),
mostra([L|Resto], [H|T], 1), nl.

Por sua vez, por cada linha é mostrado linha a linha cada elemento até ao fim da lista:

mostra_linha_linha(L, T, 8).
mostra_linha_linha(L, T, N):- mostra_linha(L,N),write('| '),
mostra_linha(T,N),write('|'), N1 is N+1,
mostra_linha_linha(L, T, N1).

Como cada elemento é desenhado linha a linha, também tem de ser desenhado
recursivamente:

mostra_linha([],_).
mostra_linha( [Elem|Resto], N):- draw(Elem, N),mostra_linha(Resto, N).

A Figura 2 representa esquematicamente o funcionamento destes predicados:

Figura 2 - Diagrama de Desenho do Tabuleiro de Jogo


Página 6 de 13
Conclusões & Bibliografia

Conclusões e Perspectivas de Desenvolvimento


Analisando o trabalho desenvolvido, chega-se à conclusão que foram atingidos todos os
objectivos propostos, entendendo como satisfatórios os recursos à nossa disposição,
documentos e equipamentos.
Sempre realçando que se apresenta uma primeira versão extremamente primária quando
comparada com o produto final, conclui-se que os módulos já desenvolvidos, sendo de
destacar a representação do tabuleiro e a visualização do mesmo e das peças, aparentam
já ter a forma que terão na versão final.
Antecipando objectivos, é já possível a realização de um jogo entre dois humanos. No
entanto, este último módulo, muito embora esteja já operacional e funcional, carece de
validação de jogadas e de adicional informação para os jogadores.
Feito o balanço entre os objectivos alcançados, tenham sido exigidos ou antecipados,
estima-se que já se tenha atingido o marco dos 35% de trabalho cumprido.

Bibliografia

Para a realização do trabalho:

[1] Eugénio Oliveira e Luís Paulo Reis, Materiais da Disciplina de Programação em


Lógica, disponível online a partir de http://www.fe.up.pt/~eol/LP/0304 (Consultado em
Outubro de 2003).
[2] Vários Autores, SICStus Prolog User’s Manual, Release 3.10.1, Abril de 2003.

Para a realização do relatório:

[3] Vários Autores, Educational Learning Games - Quarto, disponível online


em http://www.educationallearninggames.com/quarto-game.asp (Consultado em
Outubro de 2003).
[4] Vários Autores, Manual do jogo Quarto!®.

Página 7 de 13
Anexo A – Exemplo de Modo de Utilização

Representação do tabuleiro de jogo


inicialmente vazio e todas as peças
disponíveis para serem escolhidas.

Indicação da posição da peça


escolhida, neste caso a coordenada
(1,1).

Mudança de jogador, retirada da


peça escolhida pelo adversário da
tabela de peças disponíveis.

i
Anexo A – Exemplo de Modo de Utilização

Indicação da posição no tabuleiro


para colocação da peça escolhida
pelo adversário.

Colocação efectiva da peça no


tabuleiro de jogo e espera por
indicação da posição da peça para
entregar ao adversário.

Todas as outras jogadas processam-se de forma idêntica. Apresenta-se, de seguida, uma


possível jogada final.

Especificação da posição no
tabuleiro para a colocação da peça
assinalada.

ii
Anexo A – Exemplo de Modo de Utilização

Colocação da peça no tabuleiro.

Assinalamento do alinhamento das 4 peças com característica em comum. Neste caso é


de notar que se está a considerar a modalidade mais complexa, em que um alinhamento
em ‘L’ é também considerado válido. A característica em comum seria o facto de as
peças serem ocas.

iii
Anexo B– Código
draw(12,3):- write('| | __ | ').
draw(14,3):- write('| | - -__ - | ').
draw(9,3):- write('| / \\ ').
draw(8,3):- write('| / __ \\ ').
draw(11,3):- write('| /- - - - \\ ').
draw(11,4):- write('| |- - - - - | ').
draw(11,5):- write('| | - - - - -| ').
draw(10,3):- write('| /- -__ - \\ ').
draw(4,3):- write('| | __ | ').
draw(6,3):- write('| |- __ -| ').
draw(3,3):- write('| /- - \\ ').
draw(3,4):- write('| |- - - | ').
draw(2,3):- write('| /-__-\\ ').
draw(0,3):- write('| / __ \\ ').
draw(1,3):- write('| / \\ ').
draw(middle,N):- write('| | | | | '),
write(N),
write('| | | | |').

draw(X,1):- 3=:=X>>2, write('| __________ '). %todos os grandes quadrados


draw(X,7):- 3=:=X>>2, write('| |__________| ').%todos os grandes quadrados
draw(X,1):- 2=:=X>>2, write('| ______ '). %todos os grandes redondos
draw(X,7):- 2=:=X>>2, write('| \\______/ '). %todos os grandes redondos
draw(X,2):- 4=:=X>>1, write('| / \\ '). %todos os grandes redondos claros
draw(X,6):- 4=:=X>>1, write('| \\ / '). %todos os grandes redondos claros
draw(X,2):- 5=:=X>>1, write('| /- - - \\ '). %todos os grandes redondos escuros
draw(X,6):- 5=:=X>>1, write('| \\ - - - -/ '). %todos os grandes redondos escuros
draw(X,N):- (X==15,0=:=N mod 2;X==14,(N==2;N==6)), write('| |- - - - - | ').%todos os grandes
quadrados escuros

draw(13,N):- N>1, N<7, write('| | | '). % dos grandes quadrados claros maciços
draw(15,N):- (N==3;N==5), write('| | - - - - -| ').% dos grandes quadrados escuros maciços
draw(12,N):- (N==2;N==6), write('| | | '). % dos grandes quadrados claros ocos
draw(9,N):- (N==4;N==5), write('| | | '). % dos grandes redondos claros maciços
draw(X,4):- (X==8;X==12), write('| | | | | '). %todos os grandes e claros e ocos
draw(X,5):- (X==8;X==12), write('| | |__| | '). %todos os grandes e claros e ocos
draw(X,4):- (X==10;X==14), write('| |- -| | - | '). %todos os grandes e escuros e ocos
draw(X,5):- (X==10;X==14), write('| | - |__|- -| '). %todos os grandes e escuros e ocos

draw(X,N):- (N==1;N==7),0=:=X>>3, write('| '). %todos os pequenos


draw(X,2):- 1=:=X>>2, write('| ______ '). %todos os pequenos e quadrados
draw(X,6):- 1=:=X>>2, write('| |______| '). %todos os pequenos e quadrados
draw(X,6):- 0=:=X>>2, write('| \\____/ '). %todos os pequenos e redondos
draw(X,2):- 0=:=X>>2, write('| ____ '). %todos os pequenos e redondos
draw(X,N):- (N==4,X==7;N==5,X==3), write('| | - - -| ').%todos os pequenos e escuros e
maciços
draw(X,4):- (X==2;X==6), write('| |-| |-| '). %todos os pequenos e escuros e ocos
draw(X,5):- (X==2;X==6), write('| |-|__|-| '). %todos os pequenos e escuros e ocos
draw(X,4):- (X==0;X==4), write('| | | | | '). %todos os pequenos e claros e ocos
draw(X,5):- (X==0;X==4), write('| | |__| | '). %todos os pequenos e claros e ocos

draw(1,N):- (N==4;N==5), write('| | | '). % dos pequenos redondos claros maciços


draw(7,N):- (N==3;N==5), write('| |- - - | '). % dos pequenos quadrados escuros maciços
draw(5,N):- (N==3;N==4;N==5), write('| | | ').% dos pequenos quadrados claros maciços

draw(top) :- write(' 1 2 3 4 1 2 3
4 ' ),

i
Anexo B– Código
write(' ______________ ______________ ______________ ______________
______________ ______________ ______________ ______________ ' ).

draw(base) :- write('|______________|______________|______________|______________|
|______________|______________|______________|______________|').
draw(22, N) :- write('| ').

tabuleiro( [ [22,22,22,22], [22,22,22,22], [22,22,22,22], [22,22,22,22] ] ).


reserva( [ [15,14,13,12], [11,10,9,8], [7,6,5,4], [3,2,1,0] ] ).

mostra([],[],_).
mostra( [L|Resto], [H|T], N):-
draw(middle, N), N2 is N+1,
mostra_linha_linha(L,H,1),
draw(middle, N), draw(base),
mostra(Resto, T, N2).

mostra_tabuleiro([L|Resto], [H|T]):-
draw(top),
mostra([L|Resto], [H|T], 1), nl.

mostra_linha([],_).
mostra_linha( [Elem|Resto], N):-
draw(Elem, N),
mostra_linha(Resto, N).

mostra_linha_linha(L, T, 8).
mostra_linha_linha(L, T, N):-
mostra_linha(L,N),write('| '),
mostra_linha(T,N),write('|'),
N1 is N+1,
mostra_linha_linha(L, T, N1).

% Copyright LPR 1999


insert_peca(Peca,PecaNova,X,Y,Tabuleiro,TabuleiroNovo):-
insert_peca_aux(1,Peca,PecaNova,X,Y,Tabuleiro,TabuleiroNovo),!.
insert_peca_aux(_,_,_,_,_,[],[]).
insert_peca_aux(Y,Peca,PecaNova,X,Y,[Lin|Resto],[NovLin|Resto2]):- %linha com a peça a
substituir
insert_peca_linha(1,Peca,PecaNova,X,Lin,NovLin),
N2 is Y+1,
insert_peca_aux(N2,Peca,PecaNova,X,Y,Resto,Resto2).
insert_peca_aux(N,Peca,PecaNova,X,Y,[Lin|Resto],[Lin|Resto2]):- %linha a copiar
por inteiro
N\=Y, N2 is N+1,
insert_peca_aux(N2,Peca,PecaNova,X,Y,Resto,Resto2).
insert_peca_linha(_,_,_,_,[],[]).
insert_peca_linha(X,Peca,PecaNova,X,[Peca|Resto],[PecaNova|Resto2]):- %posição da
peça
N2 is X+1,
insert_peca_linha(N2,Peca,PecaNova,X,Resto,Resto2).
insert_peca_linha(N,Peca,PecaNova,X,[El|Resto],[El|Resto2]):-
N\=X, N2 is N+1,
insert_peca_linha(N2,Peca,PecaNova,X,Resto,Resto2).
% End of Copyright LPR 1999

jogo :- tabuleiro(X), reserva(Y), nl,nl, joga(X,Y,1).

ii
Anexo B– Código
joga(Tabuleiro, Reserva, Jogador):- mostra_tabuleiro(Tabuleiro,Reserva),
nl,nl,nl,nl,nl,nl,nl,nl,
read(Xorigem), read(Yorigem),nl, busca_peca(Peca,
Xorigem, Yorigem),
insert_peca(Peca, 22, Xorigem, Yorigem, Reserva, Z),
mostra_tabuleiro(Tabuleiro,Z), nl,
mostra_peca(Peca, 1), nl,
muda_jogador(Jogador, NovoJogador),
read(Xdes), read(Ydes),nl,nl,
insert_peca(22, Peca, Xdes, Ydes, Tabuleiro,
NovoTabuleiro),
joga(NovoTabuleiro, Z, NovoJogador),nl,nl.

muda_jogador(1,2).
muda_jogador(2,1).

mostra_peca(Peca, 8):- write('|').


mostra_peca(Peca, N):-draw(Peca,N), nl,
N2 is N+1,
mostra_peca(Peca,N2).

busca_peca(Peca, X, Y):- Peca is (((4-Y)<<2) + (4-X)).

iii