Vous êtes sur la page 1sur 52

Relatório Intercalar do 1º Trabalho Prático da

Disciplina de Programação em Lógica

Congo

Autores:
Carlos Alberto Loureiro Nunes
Pedro Nuno Verde Cerqueira
Grupo 54, Turma 5

Faculdade de Engenharia da Universidade do Porto


Mestrado Integrado em Engenharia Informática e Computação

Outubro de 2008
Relatório Intercalar do 1º Trabalho Prático da
Disciplina de Programação em Lógica

Trabalho realizado no âmbito da disciplina de Programação em Lógica, do 1º semestre, do


3º ano, da Licenciatura em Eng. Informática e de Computação da Faculdade de
Engenharia da Universidade do Porto, leccionada por
Eugénio de Oliveira e Luís Paulo Reis.

Faculdade de Engenharia da Universidade do Porto


Mestrado Integrado em Engenharia Informática e Computação

Outubro de 2008
III

Resumo

Este trabalho consiste no desenvolvimento do jogo de tabuleiro Congo, variante do


xadrez, através do uso da linguagem Prolog. Incluirá também uma interface de
visualização gráfica 3D, a ser implementado em OpenGL, e C++ na cadeira de LASO. A
aplicação final permitirá três modos de jogo: Humano/Humano, Computador/Computador
e Humano/Computador e ainda a possibilidade de escolher entre vários níveis de
dificuldade.
O que se encontra realizado é a imlementação de todas as regras relacionadas com
movimentos, a representação do estado do jogo e ainda um método de visualizar o estado
do jogo.
IV

Índice

Resumo iii

Índice iv

Lista de Figuras vi

Lista de Tabelas vii

Glossário viii

1. Introdução ix
1.1 Enquadramento...................................................................................................................ix
1.2 Motivação............................................................................................................................ix
1.3 Objectivos...........................................................................................................................ix
1.4 Estrutura do Relatório...........................................................................................................x

2. Descrição do jogo xi
2.1 Introdução...........................................................................................................................xi
2.2 História................................................................................................................................xi
2.3 Regras do Jogo...................................................................................................................xii
2.3.1 Tabuleiro, Regras Básicas e Notação..........................................................................xii
2.3.2 Objectivo....................................................................................................................xiii
2.3.3 Peças e Movimentos...................................................................................................xiii
2.3.3.1 Leão.....................................................................................................................xiii
2.3.3.2 Elefante...............................................................................................................xiii
2.3.3.3 Macaco................................................................................................................xiv
2.3.3.4 Crocodilo.............................................................................................................xiv
2.3.3.5 Girafa....................................................................................................................xv
2.3.3.6 Zebra.....................................................................................................................xv
2.3.3.7 Peão.....................................................................................................................xvi
2.3.3.8 Super Peão...........................................................................................................xvi
2.3.4 Fim do jogo................................................................................................................xvi
V

3. Representação do Estado do Jogo xviii

4. Representação de um Movimento xx

5. Visualização do Tabuleiro xxiv

6. Conclusões e Perspectivas de Desenvolvimento xxvi

Bibliografia 27
VI

Lista de Figuras

Figura 1: Configuração inicial do tabuleiro xiii

Figura 2: “Salto” do elefante xv

Figura 3: Movimentos/capturas do macaco xv

Figura 4: Movimentos do crocodilo xvi

Figura 5: Movimentos da girafa. As setas representam movimentos ou capturas, e is


círculos representam movimentos sem possibilidade de captura. xvi

Figura 6: Movimentos do peão e super peão xvii

Figura 7: Fim de jogo com vitória das brancas xviii

Figura 8: Comparação entre diferentes modos de visualização xxvi

Figura 9: Fluxograma que ilustra o modo do funcionamento do Congo 29

Figura 10: Captura de ecrâ com um possível meio-jogo 1 30

Figura 11: Captura de ecrâ com um possível meio-jogo 2 31


VII

Lista de Tabelas

Tabela 1: Representação das peças na lista de listas xix

Tabela 2: Designações formais dos conjuntos de movimentos xx

Tabela 3: Conjuntos de movimentos por peça xxi


8

Glossário

Elephant Roll – No Congo diz-se que existem um elephant roll quando dois
elefantes do mesmo jogador estão colocados ao longo de uma linha ou coluna de modo a
poderem capturar qualquer posição da mesma linha ou coluna em que se encontram.
Stalemate – Diz-se que acontece stalemate quando no xadrez, um jogador não pode
fazer nenhuma jogada sem por o seu rei em cheque. Desta forma dá-se um empate. No
Congo não existe cheque. Se o leão é ameaçado por uma peça adversária e não é de
alguma forma protegido, no turno seguinte pode ser capturado terminando o jogo.
9

Capítulo 1

1. Introdução

1.1 Enquadramento
Este trabalho enquadra-se na realização de objectivos pedagógicos da disciplina de
Programação em Lógica, do 1º semestre, do 3º ano, da Licenciatura em Engenharia
Informática e de Computação da Faculdade de Engenharia da Universidade do Porto.
Estes objectivos apresentam-se explicitados na secção 3 deste capítulo.

1.2 Motivação
O jogo Congo é um jogo semelhante ao Xadrez o que só por si já o torna
interessante. Alem disso o Congo apresenta características únicas num jogo de tabuleiro,
como a existência de um rio, elevando ainda mais o grau de interesse. Existem multiplas
regras, e usam-se várias estratégias complexas para obter uma condição de vitória. Em
resumo , é um jogo naturalmente desafiante para os seus jogadores, que testa as suas
capacidades de pensamento estratégico e lógico.
Outra possível razão para a escolha deste jogo em particular é a sua grande
popularidade, sendo uma das variantes de xadrez mais jogadas. Acrescentando ao desafio
o desejo de criar uma implementação de grande qualidade, para os padrões da maioria dos
seus jogadores.

1.3 Objectivos
Os objectivos deste trabalho intersectam os da disciplina:
● Adquirir familiaridade com os paradigmas da programação em lógica e com a
linguagem Prolog.
● Desenvolver as competências de raciocínio abstracto e de representação de
problemas de forma declarativa ao invés do que tinha-mos feito até agora na
programação funcional;
10

● Reconhecer as categorias de problemas em que a programação em lógica é


particularmente adequada, e pode ser usada com vantagem em relação á
programação funcional;
● E ainda construir aplicações completas em Prolog com ligação a outras linguagens,
neste caso a a C++;

1.4 Estrutura do Relatório


Este trabalho encontra-se estruturado em seis capítulos dos quais, o primeiro é esta
introdução. No segundo capítulo é descrito o jogo em si, de uma forma detalhada e com
recurso a imagens ilustrativas. No terceiro capítulo é descrito, como é representado o
estado do jogo na nossa implementação em Prolog. Seguidamente, no quarto capítulo,
apresenta-se a forma de representação Prolog de todos os movimentos possíveis no jogo.
O quinto capítulo é sobre os predicados Prolog de visualização do estado do jogo. Por
último, o sexto capítulo, localiza o trabalho realizado no “todo” do projecto final, e
enumera algumas perspectivas de desenvolvimentos futuros.
São ainda incluídos anexos com o código fonte, e algumas capturas de ecrã da
interface, assim como outras secções auxiliares.
11

Capítulo 2

2. Descrição do jogo

2.1 Introdução
O Congo é um jogo muito semelhante ao Xadrez, na medida em que é um jogo de
tabuleiro por turnos em que existem várias peças diferentes por jogador e o objectivo é
capturar apenas uma das peças (o rei no caso do xadrez). As diferenças mais notórias entre
os dois jogos é a existência de um rio na linha do meio, onde as peças podem eventual-
mente “afogar-se”, e obviamente o facto de as peças se moverem de maneira diferente (ver
figura 1). Existem também outras diferenças que serão descritas mais detalhadamente nas
próximas secções deste capítulo.

2.2 História
O Congo foi inventado por Demian Freeling quando este tinha apenas sete anos,
em 1982. Tornou-se rapidamente na segunda variante de Xadrez mais popular no clube de
jogos "Fanatic" na Twente University, Noruega. Existem poucos jogos criados por
crianças tão jovens que sejam tão interessantes para os adultos. Christian Freeling, o pai
de Demian, é um criador de jogos muito conhecido e autor do sítio www.mindsports.com
juntamente com Ed Van Zon. É de facto notável que o jogo Congo apareça na capa do
livro David Pritchard's, 'The Encyclopedia of Chess Variants' (G&P Publications, P.O.
Box 20, Godalming, Surrey GU8 4YP, UK. - ISBN 0-9524142-0-1).
12

2.3 Regras do Jogo

2.3.1 Tabuleiro, Regras Básicas e Notação


O Congo joga-se num tabuleiro de 7 linhas por 7 colunas, como ilustra a figura
seguinte.

Figura 1: Configuração inicial do tabuleiro

Na linha central existe um rio, a azul, e os quadrados de 3x3 células cinzentos, designam-
se por castelos dos leões.

As regras básicas são as seguintes:


● Um jogador controla as peças brancas e outro as pretas.
● Cada jogador tem inicialmente 14 peças: 1 leão, 2 elefantes, 1 macaco, 1 crocodilo,
1 girafa, 1 zebra e 7 peões.
● Os jogadores jogam alternadamente por turnos; brancas jogam primeiro.
● Cada jogador é obrigado a efectuar um e só um movimento de uma peça por turno
(no caso do macaco um movimento pode ser composto por vários sub-movimentos
como será explicado posteriormente).

Para qualquer peça com a excepção do crocodilo, que não se afoga, e do Leão que não
pode entrar no rio:
● Se uma peça termina o seu movimento no rio, tem que o abandonar no próximo
turno ou afoga-se;
● A peça afogada é removida no fim do turno quer se tenha movido dentro do rio,
quer não. Qualquer captura que faça e termine no rio é válida.
13

2.3.2 Objectivo
O objectivo do Congo é capturar o Leão do oponente. Ao contrário do xadrez não
há nenhuma regra que proíba o Leão de se mover para uma posição em que fique em
cheque, seria simplesmente capturado e finalizaria o jogo. Como é obrigatório os
jogadores moverem sempre uma peça no seu turno, não existe stalemate (ver glossário).

2.3.3 Peças e Movimentos


Ao contrário do Xadrez, no qual as peças capturam sempre na posição em que
terminam o movimento, no Congo existem várias peças que tem movimentos sem captura
e movimentos com captura. Também no Congo nem todas as peças capturam a posição em
que terminam o movimento: o macaco captura as peça(s) sobre as quais salta, à
semelhança do que acontece nas Damas.
Por outro lado existem vários movimentos que dependem da posição da peça no
tabuleiro, como no caso dos leões, crocodilos e peões. Por isso é necessário distinguir
entre movimentos que não podem ser capturas e movimentos que podem ser capturas, e
ainda os casos em que os movimentos são saltos e não se vêem afectados pelas peças
sobre as quais se salta. Estas e outras situações referentes a movimentos/capturas serão
descritas mais detalhadamente nos parágrafos seguintes.

2.3.3.1 Leão
O leão movimenta-se e captura como o rei do xadrez, ou seja para 1 célula á sua
volta em qualquer direcção. Contudo não pode sair do seu "castelo" de 3x3 células.
Adicionalmente, se um leão está na mesma coluna que o leão adversário, ou na
mesma diagonal, e não existem outras peças entre eles, ambos estão em cheque e o
jogador ao qual o turno actual pertence pode capturar o leão adversário e ganhar o jogo.

2.3.3.2 Elefante
O elefante pode mover-se e capturar uma ou duas células ao longo da linha ou
coluna em que se encontra. O movimento de duas células é um salto para a célula final e
não é afectado pela existência de peças de qualquer das equipas, na célula sobre a qual
salta.
14

Figura 2: “Salto” do elefante

2.3.3.3 Macaco
Os macacos movem-se (mas não capturam) como o rei do xadrez. Estes, capturam
saltando (sobre a peça capturada) ao longo das linhas, colunas ou diagonais, para a célula
imediatamente a seguir, que tem que estar vazia. O macaco pode efectuar múltiplas
capturas no mesmo turno (embora não seja obrigado), desde que não salte sobre a mesma
peça mais que um vez.

Figura 3: Movimentos/capturas do macaco

2.3.3.4 Crocodilo
O crocodilo move-se e captura como o rei no xadrez. Contudo dependendo se
encontra em terra ou no rio:
● Quando em terra também se pode mover e capturar qualquer célula na coluna
até ao rio (incluindo a célula do rio).
● Quando no rio, o crocodilo pode mover-se e capturar qualquer outra célula do
rio. Como já foi referido anteriormente o crocodilo não se afoga.
15

Figura 4: Movimentos do crocodilo

2.3.3.5 Girafa
As girafas podem mover-se e capturam para a segunda célula ao longo da linha,
coluna ou diagonal em que se encontra, sem se ver afectada por qualquer peça sobre a qual
salte, seja ela branca ou preta. Também pode mover-se (mas não capturar) como o rei do
xadrez.

Figura 5: Movimentos da girafa. As setas representam movimentos ou capturas, e is


círculos representam movimentos sem possibilidade de captura.

2.3.3.6 Zebra
A zebra move-se e captura como o cavalo do xadrez, ou seja: avança duas células
ao longo da linha ou coluna em que se encontra; vira noventa graus para um dos lados;
avança uma célula ao longo da linha ou coluna para onde se encontra virada. O
movimento da zebra é um salto e não se vê afectado pelas peças de qualquer das cores,
sobre as as quais salta.
16

2.3.3.7 Peão
Os peões, podem mover-se e capturar para a frente: uma célula na mesma coluna
para a frente, ou uma célula na diagonal para a frente. Quando estão na linha
imediatamente a seguir ao rio podem retroceder, movendo-se (mas não capturando) uma
ou duas células para trás. Quando um peão atinge a última linha é promovido para "super
peão", descrito a seguir. Observe a figura seguinte que ilustra os movimentos do peão e
“super peão”.

Figura 6: Movimentos do peão e super peão

2.3.3.8 Super Peão


Os super peões movem-se e capturam como os peões e adicionalmente podem
mover-se e capturar uma célula para o lado. Também podem retroceder como o peão (uma
ou duas células para trás), mas a possibilidade de realização deste movimento já não
depende da posição da peça em relação ao rio. Podem também retroceder uma ou duas
células na diagonal (mas não capturar).

2.3.4 Fim do jogo


Na figura seguinte ilustra-se um fim de jogo, em que o leão preto não podendo sair
do castelo nem mover-se na mesma coluna “E”, é obrigado a mover-se para a coluna “D”
onde é capturado pelo leão adversário.
17

Figura 7: Fim de jogo com vitória das brancas


18

Capítulo 3

3. Representação do Estado do Jogo


O estado é representado por uma lista com sete listas de sete elementos.
O estado inicial do jogo é o seguinte:
[[ 5, 3, 2, 1, 2, 4, 6],
[ 8, 8, 8, 8, 8, 8, 8],
[ 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0],
[16,16,16,16,16,16,16],
[13,11,10, 9,10,12,14]]

O espaço vazio é representado pelo valor 0. As restantes peças assumem a representação


apresentada no quadro seguinte.

Valor das peças na representação do


tabuleiro Quantidade inicial
Peças
por jogador
Jogador 1 (Cima) Jogador 2 (Baixo)

Leão 1 9 1

Elefante 2 10 2

Macaco 3 11 1

Crocodilo 4 12 1

Girafa 5 13 1

Zebra 6 14 1

Peão 7 15 7

Super Peão 8 16 0
19

Tabela 1: Representação das peças na lista de listas


Na representação do tabuleiro apenas aparecem as peças móveis. Os elementos imóveis,
como o rio e os castelos são tratados internamente pela sua posição.
Contudo para que seja possível aplicar a regra dos afogamentos é necessário
guardar informação sobre à quantos turnos uma peça está no rio. A solução que
adoptamos foi criar uma lista de sete elementos que representa a profundidade das peças
no rio. O valor zero significa que não existe nenhum peça no rio na posição
correspondente, e um valor menor que zero significa que existe uma peça, e indica a sua
profundidade.
A configuração inicial da profundidade é [0, 0, 0, 0, 0, 0, 0]. Quando
uma peça termina o seu movimento no rio a posição em que ficou no rio fica com o valor
-1; quando o turno desse jogador termina fica com o valor -2; quando o turno do outro
jogador termina, e se a peça não tiver sido capturada, toma o valor de -3; no fim do turno
do jogador, se este não a tiver tirado do rio o valor da profundidade atinge -4 e é retirada
do tabuleiro. Consulte o anexo 1 que ilustra o funcionamento geral do motor de jogo, e
onde se pode observar quando ocorre o “afundamento” e o “afogamento” de peças.
Em resumo o estado do jogo é representado pelo par de uma lista de listas para a
posição das peças e uma lista para a profundidade das peças no rio. Obviamente, é
também necessário manter a informação do próximo jogador a jogar.
20

Capítulo 4

4. Representação de um Movimento
O Congo, tal como o Xadrez, é caracterizado pela existência de várias peças com
tipos de movimentos diferentes.
Segue-se uma visão mais formal dos tipos de movimento que estão disponíveis
para cada peça.
Para melhor descrever a complexidade dos movimentos possíveis expomos as
seguintes duas tabelas, que abordam a questão dos movimentos de uma forma mais formal
do que a que foi usada no capítulo 2.

Distância
Designaçã (número
Direcção Descrição
o Formal de
células)
N, S, E, W, NE,
QD_1 1 1 célula em Qualquer Direcção
NW, SE, SW
N, S, E, W, NE,
QD_2 2 2 células em Qualquer Direcção
NW, SE, SW
1 ou 2 células na horizontal ou vertical
XY_12 N ,S, E, W 1–2
(direcção X ou Y)
NEE, NNE, SEE,
SSE, NWW,
CX 2+1 Como o Cavalo do Xadrez
NNW, SWW,
SSW
Qualquer número de células na direcção
X_Q E, W 1–6
X
A coluna (direcção Y) até ao Rio (célula
Y_QR N 1–3
do rio incluída)
1 célula para a Frente (na vertical ou
F_1 N, NE, NW 1
diagonal)
X_1 E, W 1 1 célula para um dos lados (direcção X)
Retroceder 1 ou 2 células na mesma
RY_12 S 1–2
coluna (direcção Y)
RD_12 SE. SW 1–2 Retroceder 1 ou 2 células na Diagonal

Tabela 2: Designações formais dos conjuntos de movimentos


A primeira coluna contem a designação do conjunto de movimentos. A segunda
coluna, “Direcção” contem a direcção dos movimentos no conjunto, na notação da bússola
magnética. Estas direcções são sobre o ponto de vista do jogador das brancas.
21

Na tabela seguinte ilustram-se os conjuntos de movimentos disponíveis por peça, e


as condições em que são aplicados. As condições usadas na notação formal de
“Movimento Sem Captura” e “Movimento Com Captura” significam respectivamente:
● in_river – se a peça (neste caso o crocodilo) está no rio;
● after_river – se a peça (neste caso o peão) está depois do rio;
● face_another_lion – se o leão está na mesma coluna ou diagonal que o outro leão e
não existem quaisquer outras peças entre eles.
A última coluna, “Salta Amigo” indica se as peças podem saltar sobre peças do mesmo
jogador ou não.
Movimento Movimento Com Salta
Peça Afoga-se
Sem Captura Captura Amigo
if (face_other_lion)
then
Leão n.a. QD_1 { QD_1 U L_L} não
else
{ QD_1 }
Elefante sim XY_12 XY_12 sim
Macaco sim QD_1 QD_2 não
if (in_river) then
if (in_river) then
{ QD_1 U X_Q }
{ QD_1 U X_Q }
Crocodilo não else não
else
{ QD_1 U
{ QD_1 U Y_QR }
Y_QR }
Girafa sim QD_1 QD_2 sim
Zebra sim CX CX sim
Super F_1 U X_1 U
sim F_1 U X_1 não
Peão RY_12 U RD12
if (after_river)
then
Peão sim { F_1 U RY_12 } F_1 não
else
{ F_1 }
Tabela 3: Conjuntos de movimentos por peça
Esta representação mais formal dos movimentos ajudou, no desenho dos
predicados prolog que os implementam. Embora existam variadíssimos movimentos
diferentes, estes podem ser divididos em dois grandes grupos de predicados: Piece-
(Xi, Yi)-(Xf, Yf) para os movimentos “simples” e
monkey-(Xi, Yi)-[(Xcapture1, Ycapture1)*(Xf1, Yf1),
(Xcapture2, Ycapture2)*(Xf2, Yf2), ..., (Xcapturen,
Ycapturen)*(Xfn, Yfn)] para os saltos eventualmente compostos dos macacos.
Grande parte dos movimentos podem ser descritos na forma: Piece-(Xi,
Yi)-(Xf, Yf), em que (Xi, Yi) são as coordenadas iniciais da peça e (Xf, Yf) as
coordenadas finais. Piece representa o tipo de peça (lion, elephant, etc.) que originou o
22

movimento, embora internamente não seja relevante, torna-se útil para nós humanos
aceder a esta informação.
Existe ainda a necessidade de representar os movimentos, eventualmente
múltiplos, dos macacos. Neste caso, estes são representados por:
monkey-(Xi, Yi)-[(Xcapture1, Ycapture1)*(Xf1, Yf1),
(Xcapture2, Ycapture2)*(Xf2, Yf2), ..., (Xcapturen,
Ycapturen)*(Xfn, Yfn)]
Neste movimento, mais uma vez (Xi, Yi) é a posição inicial da peça, (Xcapturen,
Ycapturen) são as posições capturadas pelo sub-movimentos e (Xfh, Yfh) são as
posições finais dos sub-movimentos, com h de 1 a n. Como já foi dito antes, o macaco é a
única peça que captura a célula sobre a qual salta, e não a célula em que termina o
movimento. Convém notar que a célula no ponto médio de (Xi, Yi) (Xf1, Yf1) e nos pontos
médios de (Xfh, Yfh) (Xfh+1, Yfh+1) com h de 1 a n – 1 são as células capturadas. O n, usado
como índice final dos sub-movimentos do macaco, não será nunca maior que 14, pois 14 é
o número de peças do adversário.
Actualmente tudo o que diz respeito aos movimentos já está implementado. É
inclusivamente possível mostrar no ecrã todos os movimentos possíveis para o jogador 1
(jogador de cima), usando o predicado print_moves(1, Board), onde Board foi instanciado
com um tabuleiro. Por exemplo para a configuração inicial do tabuleiro e considerando
que o eixo dos Y aponta para baixo (notação interna), para o jogador de cima os
movimentos possíveis são.
| ?- initial_board(Board), print_moves(1, Board).
[elephant-(3,1)-(3,3),elephant-(5,1)-(5,3),giraffe-(1,1)-
(1,3),giraffe-(1,1)-(3,3),zebra-(7,1)-(6,3),pawn-(1,2)-
(1,3),pawn-(1,2)-(2,3),pawn-(2,2)-(2,3),pawn-(2,2)-
(3,3),pawn-(2,2)-(1,3),pawn-(3,2)-(3,3),pawn-(3,2)-
(4,3),pawn-(3,2)-(2,3),pawn-(4,2)-(4,3),pawn-(4,2)-
(5,3),pawn-(4,2)-(3,3),pawn-(5,2)-(5,3),pawn-(5,2)-
(6,3),pawn-(5,2)-(4,3),pawn-(6,2)-(6,3),pawn-(6,2)-
(7,3),pawn-(6,2)-(5,3),pawn-(7,2)-(7,3),pawn-(7,2)-(6,3)]

Apresentam-se ainda, a título de exemplo, as jogadas possíveis para para o meio-


jogo 1 (ver anexo “capturas de ecrã”).
| ?- test_moves_board(Board), print_moves(1, Board).

[lion-(5,2)-(5,1),lion-(5,2)-(5,3),lion-(5,2)-(4,2),lion-
(5,2)-(4,1),lion-(5,2)-(4,3),lion-(5,2)-(5,7),elephant-
(3,1)-(3,2),elephant-(3,1)-(4,1),elephant-(3,1)-
23

(3,3),elephant-(3,1)-(5,1),giraffe-(1,1)-(2,2),giraffe-
(1,1)-(1,3),giraffe-(1,1)-(3,3),crocodile-(6,1)-
(6,2),crocodile-(6,1)-(5,1),crocodile-(6,1)-(7,2),crocodile-
(6,1)-(6,3),crocodile-(6,1)-(6,4),zebra-(7,1)-(6,3),pawn-
(1,2)-(1,3),pawn-(1,2)-(2,3),pawn-(6,5)-(6,6),pawn-(6,5)-
(7,6),pawn-(6,5)-(5,6),pawn-(4,6)-(4,7),pawn-(4,6)-
(5,7),pawn-(4,6)-(3,7),pawn-(6,5)-(6,4),pawn-(6,5)-
(6,3),monkey-(2,1)-(3,2),monkey-multiple-(2,1)-
[(2,2)*(2,3)],monkey-multiple-(2,1)-[(2,2)*(2,3),
(2,4)*(2,5)],monkey-multiple-(2,1)-[(2,2)*(2,3),(2,4)*(2,5),
(3,5)*(4,5)]]
24

Capítulo 5

5.Visualização do Tabuleiro
Existem dois predicados com a funcionalidade de visualizar o tabuleiro:
print_board e print_board_advanced. O predicado print_board mostra o
tabuleiro de uma forma muito simples e compacta. Por outro lado,
print_board_advanced mostra o tabuleiro de forma mais inteligível, representando
cada peça numa área de 5 linhas por 9 colunas usando caracteres ASCII e os modos de cor
da consola Linux. Alem da representação das peças, os predicados de visualização
também apresentam o rio, os castelos e a legenda das linhas e colunas.
A representação em “gráficos de texto” de 5 linhas por 9 colunas não permite
grande qualidade na representação gráfica, contudo achamos, que mesmo assim é mais
“amigável” que a simples. Na figura seguinte pode observar-se a saída produzida por
print_board (em cima) e por print_board_advanced (em baixo) numa shell
linux.
25

Figura 8: Comparação entre diferentes modos de visualização


Em cima, na saída de print_board, as letras identificam o tipo de peça e os
números, o jogador a que pertencem. Nos anexos pode encontrar mais capturas de ecrã do
sistema de visualização “gráfico”.
26

Capítulo 6

6.Conclusões e Perspectivas de
Desenvolvimento
Em perspectiva, olhando para o trabalho já realizado, conclui-se que os objectivos
foram cumpridos e adivinha-se que o resto da implementação será também muito
interessante.
Estando a aplicação num ponto em que é capaz de gerar todos os movimentos
possíveis para um dado jogador faltam ainda construir as seguintes partes:
● Interface para perguntar modo de jogo (Humano vs Humano, Computador vs
Computador, Humano vs Computador), interface para perguntar nível de
dificuldade, e ainda uma interface para um jogador efectuar um jogada
● Escolha da melhor jogada de acordo com o nível de dificuldade (Jogada aleatória,
Melhor jogada local, Minimax, etc.)
● Interface de comunicação/controlo usando sockets TCP/IP para modulo em C+
+/OpenGL desenvolvido em LASO
Fazendo o balanço entre o já alcançado e o ainda por alcançar, estima-se que se
tenha completado 35% a 45% do trabalho a realizar.
O jogo Congo alem de ser muito interessante do ponto de vista da inteligência
artificial, também o é do ponto de vista da interface 3D a desenvolver em LASO. Isto
porque além de se desenvolver um modelo de uma peça que pode mover-se em 4
direcções e um tabuleiro (como no caso das damas), no Congo existem 8 peças diferentes
por jogador, com variados movimentos, e ainda um “rio”.
Note-se que, adaptar este motor de jogo para resolver outro qualquer jogo do
género (em tabuleiro, por turnos alternados, estado conhecido), é razoavelmente fácil.
Basta para isso alterar a representação do estado, a geração de jogadas, e o método de
avaliação do estado.
Bibliografia

[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://paginas.fe.up.pt/~eol/LP/0809/ (consultado em Outubro de
2008).
[2] Christian Freeling and Ed van Zon, Congo, http://www.mindsports.nl/index.php/side-
dishes/more-games-by-cf?start=31 (consultado em Outubro de 2008)
[3] Leon Sterling e Ehud Shapiro, The Art of Prolog – Advanced Programing Thechniques,
Second Edition; capítulo 16 secção 1 “All-Solutions Predicates”
[4] Daniel Diaz, GNU Prolog Manual, Edition 1,7 (GNU Prolog version 1.2.18)

27
Anexos
Anexo 1: Funcionamento do motor de jogo do Congo

Figura 9: Fluxograma que ilustra o modo do funcionamento do Congo

28
Anexo 2: Capturas de ecrâ

Figura 10: Captura de ecrâ com um possível meio-jogo 1

29
Figura 11: Captura de ecrâ com um possível meio-jogo 2

30
Anexo 3: Código Fonte

% Congo
%
% Autores:
% Carlos Nunes
% Pedro Cerqueira
%
% FEUP PLOG 2008
%
% tested with gnu prolog "gprolog"
% should be ANSI prolog

% 2 - Lion
% 3 - Elephant
% 4 - Monkey
% 5 - Crocodile
% 6 - Giraffe
% 7 - Zebra
% 8 - SuperPawn
% 9 - Pawn

% i 121 6ª 10 -> 12

% order g, m, e , l, e, c, z

river_y(4).
min_x(1).
min_y(1).
max_x(7).
max_y(7).

inside(X, Y):- X >= 1, X =< 7, Y >= 1, Y =< 7.

%inside_castle(Player, X, Y)

31
inside_castle_aux(X):- X >= 3, X =< 5.
inside_castle(1, X, Y):- inside_castle_aux(X), Y =< 3, !.
inside_castle(2, X, Y):- inside_castle_aux(X), Y >= 5.

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

initial_river_depth([0,0,0,0,0,0,0]).

test_moves_board(
[
[ 5, 3, 2, 0, 0, 4, 6],
[ 8,16, 0, 0, 1, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0],
[ 0,15, 0, 0, 0, 0,12],
[ 0, 0,10, 0, 0, 8, 0],
[ 0, 0, 0, 8, 0, 0, 0],
[ 0, 0, 0, 0, 9, 0, 0]
]).

test_board_2(
[
[ 0, 3, 0, 1, 0, 4, 6],
[ 0,16, 0, 0, 3, 0, 0],
[ 0, 0, 0, 0, 0, 5, 0],
[ 0,12, 0, 0, 0, 0, 0],
[ 0, 0,10, 0, 0, 8, 0],
[ 0,16, 0, 8, 0, 0, 0],
[ 0, 0, 0, 0, 9, 0, 0]

32
]).

% up player (front direction is +Y)


player(1).

% down player (front direction is -Y)


player(2).

other_player(Player, Other):-
Other is 2 - (Player - 1).

piece_player(Piece, 1):-
Piece >= 1,
Piece =< 8.
piece_player(Piece, 2):-
Piece >= 9,
Piece =< 16.

piece_type(Piece, Type):- Piece =< 8, Type is Piece, !.


piece_type(Piece, Type):- Piece >= 9, Type is Piece - 8.

%piece(player, type, board_value)


piece(1, lion, 1).
piece(1, elephant, 2).
piece(1, monkey, 3).
piece(1, crocodile, 4).
piece(1, giraffe, 5).
piece(1, zebra, 6).
piece(1, superpawn, 7).
piece(1, pawn, 8).

piece(2, lion, 9).


piece(2, elephant, 10).
piece(2, monkey, 11).
piece(2, crocodile, 12).

33
piece(2, giraffe, 13).
piece(2, zebra, 14).
piece(2, superpawn, 15).
piece(2, pawn, 16).

lion(Piece):-piece_type(Piece, 1).
elephant(Piece):-piece_type(Piece, 2).
monkey(Piece):-piece_type(Piece, 3).
crocodile(Piece):-piece_type(Piece, 4).
giraffe(Piece):-piece_type(Piece, 5).
zebra(Piece):-piece_type(Piece, 6).
superpawn(Piece):-piece_type(Piece, 7).
pawn(Piece):-piece_type(Piece, 8).

% == PRINT BOARD ==

% advanced print board

horizontal_sep:-
reset_color,
write(' +---------+---------+---------+---------+---------
+---------+---------+'),
nl.

print_board_advanced(Board):-
nl,
write(' A B C D E F
G'),
nl,
print_board_advanced_aux(Board, 1), !.

print_board_advanced_aux([], _):-
horizontal_sep,
!.

print_board_advanced_aux( [Line | LinesRem] , Y):-


horizontal_sep,

34
print_line_adv(1, Line, Y),
Y1 is Y + 1,
print_board_advanced_aux(LinesRem, Y1), !.

numer_or_not(SubLineNum, Y):-
0 =:= (SubLineNum + 2) mod 5,
write(Y), !.

numer_or_not(_, _):-
write(' ').

print_line_adv( 6, _ , _):-!.

print_line_adv(SubLineNum, Line, Y):-


reset_color,
write(' '),
numer_or_not(SubLineNum, Y),
write(' |'),
print_subline(SubLineNum, Line, 1, Y),
reset_color,
nl,
SLN is SubLineNum + 1,
print_line_adv(SLN, Line, Y).

print_subline(_, [], _, _):-!.

print_subline(SubLineNum, [Cell | LineRem], X, Y):-


print_subcell(Cell, SubLineNum, X, Y),
X1 is X + 1,
print_subline(SubLineNum, LineRem, X1, Y).

set_color(1, 0):-
write('[01;31m').

set_color(2, 0):-
write('[01;37m').

35
% river colors
set_color(1, -1):-
write('[01;31;44m').

set_color(2, -1):-
write('[01;37;44m').
% verde 32 amarelo 33 white 37
% castle colors
set_color(1, -2):-
write('[01;31;47m').

set_color(2, -2):-
write('[01;37;47m').

reset_color:-
write('[00m').

print_subcell( Cell, SubLineNum , X, Y):-


piece_type(Cell, Type),
piece_player(Cell, Player),
inside_castle(_, X, Y),
set_color(Player, -2),
txt( Type, SubLineNum ),
reset_color,
write('|'),
!.

print_subcell( Cell, SubLineNum , _, Y):-


river_y(Y),
piece_type(Cell, Type),
piece_player(Cell, Player),
set_color(Player, -1),
txt( Type, SubLineNum ),
reset_color,
write('|'),
!.

36
print_subcell( Cell, SubLineNum , _, _):-
piece_type(Cell, Type),
piece_player(Cell, Player),
set_color(Player, 0),
txt( Type, SubLineNum ),
reset_color,
write('|'),
!.

print_subcell(_ , _ , X, Y):-
inside_castle(_, X, Y),
set_color(_, -2),
txt(0, _),
reset_color,
%write('[01;47m'),
write('|'),
!.

print_subcell( _, _, _, Y ):-
river_y(Y),
set_color(1, -1),
txt(0, _),
reset_color,
%write('[01;44m'),
write('|'),
!.

print_subcell(_, _, _, _ ):-
reset_color,
txt(0, _),
write('|').

% == END PRINT BOARD ==

% end of advanced print board

37
print_board_header:-
write(' A B C D E F G'), nl.

print_board(Board):-
nl,
print_board_header,
print_lines(1,Board),
print_board_header,!.

print_lines(_,[]).
print_lines(N,[Line|RemBoard]):-
write(N), write(' '), print_line(N, Line), write(N), nl,
N2 is N+1,
print_lines(N2, RemBoard).

print_line(_, []).
print_line(N, [Cell|RemBoard]):-
river_y(Ry),
N \= Ry,
print_cell(Cell), write(' '),
print_line(N,RemBoard), !.

print_line(N, [0|RemBoard]):-
% Cell =:= 0, % vazio
print_cell(-1), write(' '),
print_line(N, RemBoard), !.

print_line(N, [Cell|RemBoard]):-
print_cell(Cell), write(' '),
print_line(N, RemBoard).

print_cell(0):-write(' ').
print_cell(-1):-write('~~'). % just for printing, theere are no -1 in map
print_cell(-2):-write('..'). % just for printing, theere are no -1 in map

print_cell(1):-write('L1').

38
print_cell(2):-write('E1').
print_cell(3):-write('M1').
print_cell(4):-write('C1').
print_cell(5):-write('G1').
print_cell(6):-write('Z1').
print_cell(7):-write('S1').
print_cell(8):-write('P1').

print_cell(9):-write('L2').
print_cell(10):-write('E2').
print_cell(11):-write('M2').
print_cell(12):-write('C2').
print_cell(13):-write('G2').
print_cell(14):-write('Z2').
print_cell(15):-write('S2').
print_cell(16):-write('P2').

% == END PRINT BOARD ==

abs(N, -N):- N < 0.


abs(N, N):- N >= 0.

% ============================
% movement coords predicates
% ============================
move_coords( (x0, yn, D), X, Y, X1, Y1):- X1 is X, Y1 is Y - D, inside(X1,
Y1).
move_coords( (x0, ys, D), X, Y, X1, Y1):- X1 is X, Y1 is Y + D, inside(X1,
Y1).
move_coords( (xe, y0, D), X, Y, X1, Y1):- X1 is X + D, Y1 is Y, inside(X1,
Y1).
move_coords( (xw, y0, D), X, Y, X1, Y1):- X1 is X - D, Y1 is Y, inside(X1,
Y1).
move_coords( (xe, yn, D), X, Y, X1, Y1):-
X1 is X + D, Y1 is Y - D, inside(X1, Y1).
move_coords( (xw, yn, D), X, Y, X1, Y1):-
X1 is X - D, Y1 is Y - D, inside(X1, Y1).

39
move_coords( (xe, ys, D), X, Y, X1, Y1):-
X1 is X + D, Y1 is Y + D, inside(X1, Y1).
move_coords( (xw, ys, D), X, Y, X1, Y1):-
X1 is X - D, Y1 is Y + D, inside(X1, Y1).

% movement coords for zebras


% NNE (North North East)
move_coords_zebra(X, Y, X1, Y1):- X1 is X + 1, Y1 is Y - 2, inside(X1, Y1).
% NEE
move_coords_zebra(X, Y, X1, Y1):- X1 is X + 2, Y1 is Y - 1, inside(X1, Y1).
% SSW
move_coords_zebra(X, Y, X1, Y1):- X1 is X - 1, Y1 is Y + 2, inside(X1, Y1).
% SWW
move_coords_zebra(X, Y, X1, Y1):- X1 is X - 2, Y1 is Y + 1, inside(X1, Y1).
% NNW
move_coords_zebra(X, Y, X1, Y1):- X1 is X - 1, Y1 is Y - 2, inside(X1, Y1).
% NWW
move_coords_zebra(X, Y, X1, Y1):- X1 is X - 2, Y1 is Y - 1, inside(X1, Y1).
% SSE
move_coords_zebra(X, Y, X1, Y1):- X1 is X + 1, Y1 is Y + 2, inside(X1, Y1).
% SEE
move_coords_zebra(X, Y, X1, Y1):- X1 is X + 2, Y1 is Y + 1, inside(X1, Y1).

%invertY(X, Y, X1, Y1):- X1 is X, Y1 is -Y.

% ============================
% BOARD RELATED UTILS
% ===========================

minimum(A, B, A):- A < B.


minimum(A, B, B):- A >= B.
maximum(A, B, B):- A < B.
maximum(A, B, A):- A >= B.

empty(X, Y, Board):-
what_is_at(X, Y, Board, 0).

40
empty_path_line(X, Y, X1, Board):-
minimum(X, X1, Xmin),
maximum(X, X1, Xmax),
Xmin1 is Xmin + 1,
Xmin1 =< Xmax,
empty_path_line_aux(Xmin1, Y, Xmax, Board), !.

empty_path_line_aux(X, Y, Xmax, Board):-


X \= Xmax,
empty(X, Y, Board),
X1 is X + 1,
empty_path_line_aux(X1, Y, Xmax, Board).

empty_path_line_aux(X, _, X, _).

% ================

empty_path_column(X, Y, Y1, Board):-


minimum(Y, Y1, Ymin),
maximum(Y, Y1, Ymax),
Ymin1 is Ymin + 1,
Ymin1 =< Ymax,
empty_path_column_aux(X, Ymin1, Ymax, Board), !.

empty_path_column_aux(X, Y, Ymax, Board):-


Y \= Ymax,
empty(X, Y, Board),
Y1 is Y + 1,
empty_path_column_aux(X, Y1, Ymax, Board).

empty_path_column_aux(_, Y, Y, _).

middle_cell(X, Y, Xf, Yf, Xmid, Ymid):-


Xinc is (Xf - X) // 2,
Yinc is (Yf - Y) // 2,
abs(Xinc, Xinc_a),

41
Xinc_a =< 1,
abs(Yinc, Yinc_a),
Yinc_a =< 1,
Xmid is X + Xinc,
Ymid is Y + Yinc.

from_other_player(Player, X, Y, Board):-
other_player(Player, Other),
what_is_at(X, Y, Board, W),
piece_player(W, Other).

what_is_at(X, Y, Board, W):-


inside(X, Y),
min_y(Ymin),
what_is_at_aux(X, Y, Ymin, Board, W),
!.

what_is_at_aux(_, _, _, [], _).

what_is_at_aux(X, Y, Y, [Line|_], W):-


min_x(Xmin),
what_is_at_line(X, Xmin, Line, W).

what_is_at_aux(X, Y, BoardY, [_|RemBoard], W):-


Y \= BoardY,
BoardY \= Y,
Y1 is BoardY + 1,
what_is_at_aux(X, Y, Y1, RemBoard, W).

what_is_at_line(_, _, [], _).

what_is_at_line(X, LineX, [_|RemLine], W):-


X \= LineX,
X1 is LineX + 1,
what_is_at_line(X, X1, RemLine, W).

what_is_at_line(X, X, [Cell|_], Cell).

42
% ============================
% change board cells
% ============================

change_line(_, _, _, [], []).

change_line(X, Value, Bx, [C|LineRes], [C|NewRes]):-


Bx \= X,
Bx1 is Bx + 1,
change_line(X, Value, Bx1, LineRes, NewRes).

change_line(X, Value, X, [_ | LineRes], [Value|NewRes]):-


Bx1 is X + 1,
change_line(X, Value, Bx1, LineRes, NewRes).

test1:-
initial_board(B),
change_board(3, 4, 9, B, Newboard),
print_board(Newboard).

change_board(X, Y, Value, Board, NewBoard):-


inside(X, Y),
min_y(Ymin),
change_board_aux(X, Y, Value, Ymin, Board, NewBoard),
!.

change_board_aux(_, _, _, _, [], []).

change_board_aux(X, Y, Value, By, [Line | BoardRes], [Line| NewRes] ):-


Y \= By,
By1 is By + 1,
change_board_aux(X, Y, Value, By1, BoardRes, NewRes).

change_board_aux(X, Y, Value, Y, [Line | BoardRes], [NewLine| NewRes]):-


change_line(X, Value, 1, Line, NewLine),

43
By1 is Y + 1,
change_board_aux(X, Y, Value, By1, BoardRes, NewRes).

% end change board cells

apply_move(Player, Piece-(Xi, Yi)-(Xf, Yf), Board, NewBoard):-


% set as empty_value
change_board(Xi, Yi, 0, Board, NewBoard1),
piece(Player, Piece, PieceValue),
change_board(Xf, Yf, PieceValue, NewBoard1, NewBoard),
!.

apply_move(Player, monkey-submove-(Xi,Yi)-[(Xcapture,Ycapture)*(Xf,Yf)],
Board, NewBoard):-
change_board(Xi, Yi, 0, Board, NewBoard1),
change_board(Xcapture, Ycapture, 0, NewBoard1, NewBoard2),
piece(Player, monkey, PieceValue),
change_board(Xf, Yf, PieceValue, NewBoard2, NewBoard).

apply_move(_, monkey-multiple-(_,_)-[], Board, Board).

apply_move(Player, monkey-multiple-(Xi,Yi)-[(Xcapture,Ycapture)*(Xf,Yf)|
Resto], Board, NewBoard):-
apply_move(Player, monkey-submove-(Xi,Yi)-[(Xcapture,Ycaptu-
re)*(Xf,Yf)], Board, Board1),
apply_move(Player, monkey-multiple-(Xf,Yf)-Resto, Board1, NewBo-
ard),
!.

% increase river pieces depth information


inc_river_pieces_depth( [], [] ).

inc_river_pieces_depth( [ PieceDepth | RiverDepthRest ], [ NewPieceDepth |


NewRiverDepthRest ] ):-
PieceDepth \= 0,
NewPieceDepth is PieceDepth - 1,
inc_river_pieces_depth(RiverDepthRest, NewRiverDepthRest), !.

44
inc_river_pieces_depth( [ PieceDepth | RiverDepthRest ], [ PieceDepth | Ne-
wRiverDepthRest ] ):-
PieceDepth =:= 0, % no piece in this river position
inc_river_pieces_depth(RiverDepthRest, NewRiverDepthRest), !.

% from Damas by Luis Paulo Reis


membrotab(Pec,X,Y,Tab):-
membro_pos_lista(Linha, Y, Tab),
membro_pos_lista(Pec, X, Linha).

membro_pos_lista(Membro, N, Lista):-
membro_pos_procura(Membro, 1, N, Lista).

membro_pos_procura(Membro, N, N, [Membro|_]).
membro_pos_procura(Membro, P, N, [_|T]):-
P2 is P+1,
membro_pos_procura(Membro, P2, N, T).
% end of from Damas by Luis Paulo Reis

print_moves(Player, Board):-
%initial_board(Board),
list_moves(Player, Board, Lista),
nl, write(Lista),
print_board(Board),
print_board_advanced(Board).

list_moves(Player, Board, Lista):-


findall(Mov, valid_move(Player,Mov,Board), Lista).

valid_move(Player, lion-(X,Y)-(Xf,Yf) , Board):-


piece(Player, lion, BoardValue),
membrotab(BoardValue, X, Y, Board),
move_coords( (_, _, 1), X, Y, Xf, Yf),
inside_castle(Player, Xf, Yf),
( empty(Xf,Yf, Board) ; from_other_player(Player, Xf, Yf, Board) ).

45
% lion special capture of oposite lion (same column)
valid_move(Player, lion-(X,Y)-(Xf,Yf) , Board):-
piece(Player, lion, BoardValue),
membrotab(BoardValue, X, Y, Board),
% where is the other lion?
other_player(Player, OtherPlayer),
piece(OtherPlayer, lion, OBoardValue),
membrotab(OBoardValue, OX, OY, Board),
X =:= OX,
% no one between them
empty_path_column(X, Y, OY, Board),
Xf is OX,
Yf is OY.

% lion special capture of oposite lion diagonals


valid_move(Player, lion-(X,Y)-(Xf,Yf) , Board):-
piece(Player, lion, BoardValue),
membrotab(BoardValue, X, Y, Board),
% where is the other lion?
other_player(Player, OtherPlayer),
piece(OtherPlayer, lion, OBoardValue),
membrotab(OBoardValue, OX, OY, Board),
( (X =:= 3, Y =:=3, OX =:= 5, OY =:= 5) ; (X =:= 5, Y =:=3, OX =:=
3, OY =:= 5) ),
middle_cell(X, Y, OX, OY, Xmid, Ymid),
% no one between them
empty(Xmid, Ymid, Board),
Xf is OX,
Yf is OY.

valid_move(Player, elephant-(X,Y)-(Xf,Yf) , Board):-


piece(Player, elephant, BoardValue),
membrotab(BoardValue, X, Y, Board),
(
move_coords( (x0, ys, 1), X, Y, Xf, Yf) ;
move_coords( (x0, yn, 1), X, Y, Xf, Yf) ;
move_coords( (xe, y0, 1), X, Y, Xf, Yf) ;

46
move_coords( (xw, y0, 1), X, Y, Xf, Yf) ;
% elephant "jumps"
move_coords( (x0, ys, 2), X, Y, Xf, Yf) ;
move_coords( (x0, yn, 2), X, Y, Xf, Yf) ;
move_coords( (xe, y0, 2), X, Y, Xf, Yf) ;
move_coords( (xw, y0, 2), X, Y, Xf, Yf)
),
( empty(Xf,Yf, Board) ; from_other_player(Player, Xf, Yf, Board) ).

valid_move(Player, giraffe-(X,Y)-(Xf,Yf) , Board):-


piece(Player, giraffe, BoardValue),
membrotab(BoardValue, X, Y, Board),
(
move_coords( (_, _, 1), X, Y, Xf, Yf) ;
% giraffe "jumps"
move_coords( (_, _, 2), X, Y, Xf, Yf)
),
( empty(Xf,Yf, Board) ; from_other_player(Player, Xf, Yf, Board) ).

% crocodile 1 cell distance moves/captures


valid_move(Player, crocodile-(X,Y)-(Xf,Yf) , Board):-
piece(Player, crocodile, BoardValue),
membrotab(BoardValue, X, Y, Board),
move_coords( (_, _, 1), X, Y, Xf, Yf),
( empty(Xf,Yf, Board) ; from_other_player(Player, Xf, Yf, Board) ).

% crocodile path to river move/capture


valid_move(Player, crocodile-(X,Y)-(Xf,Yf) , Board):-
piece(Player, crocodile, BoardValue),
membrotab(BoardValue, X, Y, Board),
river_y(Yriver),
Y < Yriver, %% only works for player 1
(
move_coords( (x0, ys, 2), X, Y, Xf, Yf) ;
move_coords( (x0, ys, 3), X, Y, Xf, Yf)
),
Yf =< Yriver, %% only works for player 1

47
empty_path_column(X, Y, Yf, Board),
( empty(Xf,Yf, Board) ; from_other_player(Player, Xf, Yf, Board) ).

% crocodile in river move/capture


valid_move(Player, crocodile-(X,Y)-(Xf,Yf) , Board):-
piece(Player, crocodile, BoardValue),
membrotab(BoardValue, X, Y, Board),
river_y(Y),
%Y =:= Yriver,
(
move_coords( (xe, y0, 2), X, Y, Xf, Yf) ;
move_coords( (xe, y0, 3), X, Y, Xf, Yf) ;
move_coords( (xe, y0, 4), X, Y, Xf, Yf) ;
move_coords( (xe, y0, 5), X, Y, Xf, Yf) ;
move_coords( (xe, y0, 6), X, Y, Xf, Yf) ;
move_coords( (xw, y0, 2), X, Y, Xf, Yf) ;
move_coords( (xw, y0, 3), X, Y, Xf, Yf) ;
move_coords( (xw, y0, 4), X, Y, Xf, Yf) ;
move_coords( (xw, y0, 5), X, Y, Xf, Yf) ;
move_coords( (xw, y0, 6), X, Y, Xf, Yf)
),
empty_path_line(X, Y, Xf, Board),
( empty(Xf,Yf, Board) ; from_other_player(Player, Xf, Yf, Board) ).

valid_move(Player, zebra-(X,Y)-(Xf,Yf) , Board):-


piece(Player, zebra, BoardValue),
membrotab(BoardValue, X, Y, Board),
move_coords_zebra(X, Y, Xf, Yf),
( empty(Xf,Yf, Board) ; from_other_player(Player, Xf, Yf, Board) ).

% superpawn capture/move moves


valid_move(Player, superpawn-(X,Y)-(Xf,Yf) , Board):-
piece(Player, superpawn, BoardValue),
membrotab(BoardValue, X, Y, Board),
(
move_coords( (x0, ys, 1), X, Y, Xf, Yf) ;
move_coords( (xe, ys, 1), X, Y, Xf, Yf) ;

48
move_coords( (xw, ys, 1), X, Y, Xf, Yf) ;
move_coords( (xe, y0, 1), X, Y, Xf, Yf) ;
move_coords( (xw, y0, 1), X, Y, Xf, Yf)
),
( empty(Xf,Yf, Board) ; from_other_player(Player, Xf, Yf, Board) ).

% superpawn retreat moves (not capture. 1 cell distance)


valid_move(Player, superpawn-(X,Y)-(Xf,Yf) , Board):-
piece(Player, superpawn, BoardValue),
membrotab(BoardValue, X, Y, Board),
(
move_coords( (x0, yn, 1), X, Y, Xf, Yf) ;
move_coords( (xe, yn, 1), X, Y, Xf, Yf) ;
move_coords( (xw, yn, 1), X, Y, Xf, Yf)
),
empty(Xf,Yf, Board).

% superpawn retreat moves (not capture, 2 cell distance)


valid_move(Player, superpawn-(X,Y)-(Xf,Yf) , Board):-
piece(Player, superpawn, BoardValue),
membrotab(BoardValue, X, Y, Board),
(
move_coords( (x0, yn, 2), X, Y, Xf, Yf) ;
move_coords( (xe, yn, 2), X, Y, Xf, Yf) ;
move_coords( (xw, yn, 2), X, Y, Xf, Yf)
),
middle_cell(X, Y, Xf, Yf, Xmid, Ymid),
empty(Xmid, Ymid, Board),
empty(Xf, Yf, Board).

% pawn move/capture
valid_move(Player, pawn-(X,Y)-(Xf,Yf) , Board):-
piece(Player, pawn, BoardValue),
membrotab(BoardValue, X, Y, Board),
( move_coords( (x0, ys, 1), X, Y, Xf, Yf) ;
move_coords( (xe, ys, 1), X, Y, Xf, Yf) ;
move_coords( (xw, ys, 1), X, Y, Xf, Yf) ),

49
( empty(Xf,Yf, Board) ; from_other_player(Player, Xf, Yf, Board) ).

% pawn retreat move (not capture) when after river (1 cell distance)
valid_move(Player, pawn-(X,Y)-(Xf,Yf) , Board):-
piece(Player, pawn, BoardValue),
membrotab(BoardValue, X, Y, Board),
river_y(Yriver),
Yafter_river is Yriver + 1,
Yafter_river == Y,
move_coords( (x0, yn, 1), X, Y, Xf, Yf),
empty(Xf,Yf, Board).

% pawn retreat move (not capture) when after river (2 cell distance)
valid_move(Player, pawn-(X,Y)-(Xf,Yf) , Board):-
piece(Player, pawn, BoardValue),
membrotab(BoardValue, X, Y, Board),
river_y(Yriver),
Yafter_river is Yriver + 1,
Yafter_river == Y,
move_coords( (x0, yn, 2), X, Y, Xf, Yf),
middle_cell(X, Y, Xf, Yf, Xmid, Ymid),
empty(Xmid,Ymid, Board),
empty(Xf,Yf, Board).

% simple monkey moves (not captures)


valid_move(Player, monkey-(X,Y)-(Xf,Yf) , Board):-
piece(Player, monkey, BoardValue),
membrotab(BoardValue, X, Y, Board),
move_coords( (_, _, 1), X, Y, Xf, Yf),
empty(Xf,Yf, Board) .

% monkey multiple jumps


%
% inspired on Damas by Luis Paulo Reis
valid_move(Player, monkey-multiple-Pos-[PCome*Pf], Board):-
valid_monkey_submove(Player, monkey-submove-Pos-[PCome*Pf], Board),
apply_move(Player, monkey-submove-Pos-[PCome*Pf], Board, Board2),

50
optional_submove(Player,Pf,Board2).

valid_move(Player, monkey-multiple-Pos-[PCome*P2|Resto], Board):-


valid_monkey_submove(Player, monkey-submove-Pos-[PCome*P2], Board),
apply_move(Player, monkey-submove-Pos-[PCome*P2], Board, Board2),
valid_move(Player, monkey-multiple-P2-Resto, Board2).

optional_submove(Player, Pini, Board):-


valid_monkey_submove(Player, monkey-submove-Pini-_, Board), !.

optional_submove(_,_,_).

valid_monkey_submove(Player, monkey-submove-(X,Y)-[(XCome,YCome)*(Xf,Yf)],
Board):-
piece(Player, monkey, BoardValue),
membrotab(BoardValue, X, Y, Board),
move_coords( (_, _, 2), X, Y, Xf, Yf),
empty(Xf,Yf, Board),
middle_cell(X, Y, Xf, Yf, XCome, YCome),
from_other_player(Player, XCome, YCome, Board).

% end of inspired on Damas by Luis Paulo Reis

txt(0,_):-write(' ').

txt(1,1):-write(' ///\\\\ ').


txt(1,2):-write(' ////. \\ ').
txt(1,3):-write(' ||| _|').
txt(1,4):-write(' ||| __/').
txt(1,5):-write(' ||| \\ ').

txt(2,1):-write(' / | ').
txt(2,2):-write(' | o | ').
txt(2,3):-write(' | /\\_ ').
txt(2,4):-write(' <==/ ').
txt(2,5):-write(' \\\\ ').

51
txt(3,1):-write(' ___ ').
txt(3,2):-write(' ^|o o|^ ').
txt(3,3):-write(' | " | ').
txt(3,4):-write(' \\_/ ').
txt(3,5):-write(' ').

txt(4,1):-write(' ').
txt(4,2):-write(' \\ _ ').
txt(4,3):-write(' \\/.\\_ ').
txt(4,4):-write(' ------- ').
txt(4,5):-write(' ').

txt(5,1):-write(' oo ').
txt(5,2):-write(' ||/\\ ').
txt(5,3):-write(' | . \\ ').
txt(5,4):-write(' | _ \\ ').
txt(5,5):-write(' | | \\/ ').

txt(6,1):-write(' ___ ').


txt(6,2):-write(' / \\\\\\ ').
txt(6,3):-write(' / . | ').
txt(6,4):-write(' _ | ').
txt(6,5):-write(' / \\_/ ').

txt(7,1):-write(' |\\/\\/| ').


txt(7,2):-write(' \\__/ ').
txt(7,3):-write(' | | ').
txt(7,4):-write(' |__| ').
txt(7,5):-write(' /____\\ ').

txt(8,1):-write(' _ ').
txt(8,2):-write(' /_\\ ').
txt(8,3):-write(' \\ / ').
txt(8,4):-write(' |_| ').
txt(8,5):-write(' /___\\ ').

52