Você está na página 1de 5

Resolvendo Desafios de Lgica com Prolog

Dado que em Prolog fcil criar estruturas (termos compostos) e fazer buscas sujeitas a certas restries, fcil resolver os tais desafios de lgica usando a linguagem. O tipo de desafio de lgica em questo similar aquele teste de Einstein que algumas correntes de email dizem que s meia-dzia de pessoas no mundo conseguem resolver (o que uma grande balela). Vrias informaes (mas no todas) so dadas sobre um conjunto de indivduos, e preciso deduzir as informaes que faltam para chegar na soluo. Resolver um problema desses em Prolog uma forma de explorar vrias caractersticas de linguagem e alguns padres de uso. A Coquetel publica uma linha de revistas de Desafios de Lgica desse tipo, usando uma tabela para ajudar a cruzar as informaes e resolver o problema. Esses problemas so um pouco diferentes porque algumas informaes no esto nas dicas, mas apenas nas listas de atributos nas tabelas, e porque s vezes preciso raciocinar por excluso (assumindo que no existem duas pessoas com o mesmo atributo). Para a soluo (em Prolog) de um puzzle simples no estilo do teste de Einstein, vejaesse post acol. Aqui vou mostrar a soluo para um problema de uma revista Desafios de Lgica (nmero 98). Sem colocar a tabela, aqui esto as informaes dadas (espero que a Coquetel no me processe): Desafio: Primeiro de Abril Quatro pessoas que gostam de pregar peas decidiram tornar o primeirode abril inesquecvel, ou seja, com muitas brincadeiras. Cada um pregou uma pea numa vtima diferente usando um objeto inofensivo. Nomes: Ana, Ester, Pablo, Rodolfo Sobrenomes: Fontes, Levis, Matoso, Salgado Brincadeiras: Almofada de barulho, Aranha falsa, Foto alterada, Mosca falsa Vtimas: Irmo, Me, Pai, Tia Dicas: 1. 2. 3. 4. 5. Ana deu risadas enquanto colocava uma aranha falsa na comida de sua vtima. A pessoa de sobrenome Salgado (que no Ana) pregou uma pea em seu irmo. A pessoa de sobrenome Matoso colocou uma almofada de barulho na cadeira de sua vtima. Rodolfo pregou uma pea em sua tia, mas no foi ele que usou a almofada de barulho. A brincadeira feita por Levis inclua uma mosca falsa. A vtima de Ester foi seu pai.

Para garantir que todas as possibilidades so examinadas e so testadas posteriormente, incluindo as partes de deduo por excluso, decidi usar o padro gerar e testar (generate-and-test) que comum em Prolog: gerar todas as possibilidades e ir restringindo (testando) at achar a soluo.

Gerao
Comeando com a gerao: o procedimento a seguir gera todas as configuraes possveis, se for usado backtracking. Para representar as informaes de uma pessoa, usei uma estrutura

p(Nome, Sobrenome, Brincadeira,

Vtima).
/* p(Nome, Sobrenome, Brincadeira, Vitima) */ gera(p(N, S, B, V)) :member(N, [ana, ester, pablo, rodolfo]), member(S, [fontes, levis, matoso, salgado]), member(B, [almofada, aranha, foto, mosca]), member(V, [irmao, mae, pai, tia]).

O procedimento gera as possibilidades corretas usando o predicado pr-definido member, garantindo que o nome gerado ser um entre [ana, ester, pablo, rodolfo], e por a vai. Podemos testar a gerao fazendo uma consulta como
?- gera(P).

O prximo passo gerar no s um indivduo, mas uma soluo completa, que so quatro indivduos. Se simplesmente usarmos
?- gera(P1), gera(P2), gera(P3), gera(P4).

sero gerados muitos grupos com indivduos repetidos. Precisamos garantir a gerao de quatro indivduos diferentes em todos os atributos. No funciona se tentarmos usar P1 \= P2 e por a vai, porque o Prolog vai dizer que duas estruturas que diferem em apenas um dos termos so diferentes. Por exemplo,
?- p(ana, fontes, almofada, irmao) \= p(ana, fontes, almofada, mosca). true.

Precisamos diferenciar todos os atributos. Alm disso, preciso ter quatro indivduos diferentes dois a dois, pois se P1 diferente de P2 e P2 diferente de P3, possvel que P1 seja igual a P3, e por a vai. Assim, definimos
dif(p(N1, S1, B1, V1), p(N2, S2, B2, V2)) :N1 \= N2, S1 \= S2, B1 \= B2, V1 \= V2.

todas_dif(P1, P2, P3, P4) :dif(P1, P2), dif(P1, P3), dif(P1, P4), dif(P2, P3), dif(P2, P4), dif(P3, P4).

Agora, se testarmos uma consulta do tipo


?- gera(P1), gera(P2), gera(P3), gera(P4), todas_dif(P1, P2, P3, P4).

S veremos solues em que as quatro pessoas so diferentes em todos os atributos. Falta testar as possibilidades geradas com as dicas dadas no problema para encontrar a soluo.

Testes
A soluo consiste de quatro indivduos, todos diferentes (usando o critrio de diferena discutido), que se encaixem nas dicas dadas pelo problema. A ideia capturada no procedimento que resolve o problema:

solucao(S) :S = [P1, P2, P3, P4], gera(P1), gera(P2), gera(P3), gera(P4), todas_dif(P1, P2, P3, P4), member(p(ana, _, aranha, _), S), member(p(N, salgado, _, irmao), S), N \= ana, member(p(_, matoso, almofada, _), S), member(p(rodolfo, _, B, tia), S), B \= almofada, member(p(_, levis, mosca, _), S), member(p(ester, _, _, pai), S).

O primeiro objetivo da soluo apenas diz que S (a soluo) uma lista de tamanho 4, formada por P1, P2, P3 e P4. Na segunda e terceira linha do corpo da clusula, temos o padro de gerao discutido antes. Depois, cada linha um teste que representa uma dica do problema. O primeiro teste diz que Ana usou a Aranha como brincadeira, mas no conhecemos seu sobrenome nem qual foi sua vtima; esse indivduo faz parte da soluo (usando o predicado prdefinido member). A segunda diz que a pessoa de sobrenome Salgado pregou uma pea no irmo; no conhecemos o nome dessa pessoa, mas sabemos que no Ana, como expresso pela desigualdade seguinte. As outras linhas traduzem as outras dicas, sem maiores novidades. Carregando o cdigo inteiro em um sistema Prolog como o SWI-Prolog, e fazendo a consulta
?- solucao(S).

A resposta dever aparecer aps algum tempo. Dependendo do computador, isso pode demorar alguns minutos, o que ruim. Alm disso, so retornadas solues equivalentes, em que apenas a ordem dos indivduos muda. Isso tudo demonstra que o sistema Prolog est buscando em um espao de estados muito maior do que necessrio. Podemos fazer isso de maneira mais eficiente.

Gerao mais eficiente


No afeta a resoluo dizer que o primeiro indivduo na soluo tem nome Ana, o segundo Ester, o terceiro Pablo e o quarto Rodolfo. Isso restringe o espao de busca sem eliminar a soluo. Se gerarmos as possibilidades j prendendo esses atributos, a busca pela soluo se torna muito mais rpida. Definimos um novo predicado para gerar as possibilidades mais eficientemente:
gera_ef(P1, P2, P3, P4) :P1 = p(ana, _, _, _), P2 = p(ester, _, _, _), P3 = p(pablo, _, _, _), P4 = p(rodolfo, _, _, _),

gera(P1), gera(P2), gera(P3), gera(P4), todas_dif(P1, P2, P3, P4).

Depois s usar esse predicado na busca pela soluo. Alm disso, s precisamos de uma soluo, ento vamos incluir um corte no final para evitar clculos inteis. O resultado
solucao2(S) :S = [P1, P2, P3, P4], gera_ef(P1, P2, P3, P4), member(p(ana, _, aranha, _), S), member(p(N, salgado, _, irmao), S), N \= ana, member(p(_, matoso, almofada, _), S), member(p(rodolfo, _, B, tia), S), B \= almofada, member(p(_, levis, mosca, _), S), member(p(ester, _, _, pai), S), !.

E agora uma consulta do tipo


?- solucao2(S).

Vai achar a soluo muito mais rpido. O cdigo completo pode ser visto aqui.
P.S.: Agora que o github abriu o cdigo para deteco de linguagens e syntax highlighting, queria ter tempo de

1/ * P (Nome, sobrenome, Brincadeira, Vitima) * / 2 3Gera ( p ( N , 4 5 6 7 8 9diferenas ( p ( N1 , 10 11 12todas_dif ( P1 , 13 P2 , P3 , P4 ) : P3 ), DIF ( P1 , P4 ), N1 \ = N2 , S1 , S1 B1 , \ = V1 ), B1 p ( N2 , \ = B2 , S2 , V1 B2 , \ = V2 )) V2 . : S , B , V )) : ster , pablo , rodolfo ]), salgado ]), mosca ]),

membro ( N , membro ( S , membro ( B , membro ( V ,

[ ana ,

[ Fontes , [ almofada , [ irmao ,

levis ,

Matoso , foto ,

aranha , pai ,

mae ,

tia ]).

S2 ,

DIF ( P1 ,

P2 ),

DIF ( P1 ,

14 15

DIF ( P2 ,

P3 ),

DIF ( P2 ,

P4 ),

DIF ( P3 ,

P4 ).

16Soluo ( S ) 17 18 19 20 21 22 23 24 25 26 27gera_ef ( P1 , 28 29 30 31 32 33 34 35solucao2 ( S ) 36 37 38 39 40 41 42 43 44 45 S = P1 P2 P3 P4 = = = = S =

: [ P1 , P2 , P3 , P4 ], Gera ( P3 ), P4 ), _ ), S ), S ), S ), B \ = almofada , N \ = ana , Gera ( P4 ),

Gera ( P1 ),

Gera ( P2 ), P2 , _ , P3 ,

todas_dif ( P1 , membro ( p ( ana , membro ( p ( N , membro ( p ( _ ,

aranha , _ ,

salgado , Matoso , _ ,

irmao ), _ ),

almofada , B , mosca , _ , tia ), _ ),

membro ( p ( rodolfo , membro ( p ( _ ,

S ), S ), S ).

levis , _ ,

membro ( p ( ster ,

pai ),

P2 ,

P3 ,

P4 ) _ , _ , _ , _ , _ ,

: _ ), _ ), _ ), _ ), Gera ( P4 ),

p ( ana , p ( ster , p ( pablo ,

_ , _ , _ ,

p ( rodolfo ,

Gera ( P1 ),

Gera ( P2 ), P2 , P3 ,

Gera ( P3 ), P4 ).

todas_dif ( P1 ,

: [ P1 , P2 , P2 , P3 , P4 ], P4 ), _ ), S ), S ), S ), B \ = almofada , N \ = ana ,

gera_ef ( P1 ,

P3 , _ ,

membro ( p ( ana , membro ( p ( N , membro ( p ( _ ,

aranha , _ ,

salgado , Matoso , _ ,

irmao ), _ ),

almofada , B , mosca , _ , tia ), _ ),

membro ( p ( rodolfo , membro ( p ( _ ,

S ), S ), S ),

levis , _ ,

membro ( p ( ster , !.

pai ),

Você também pode gostar