/*
Exemplo de integracao entre Interacao, Representacao e Acao

Principais elementos do dominio:

Espaco: grid 10x10 (0..9) de ruas(verticais) e avenidas(horizontais) perpendiculares umas `as outras
Muro: barreira concreta localizada em esquinas de ruas e avenidas
Beeper: objeto que pode estar localizado ou em uma esquina ou na sacola do robo
Robo: agente que se movimenta no espaco e efetua operacoes derivadas das primitivas MOVE, TURNLEFT, PICKBEEPER, PUTBEEPER
           Um robo esta' ORIENTADO em uma de 4 direcoes: norte, sul, leste ou oeste.
           Um robo sempre esta' LOCALIZADO em uma e somente uma esquina.
Sacola: recipiente que um robo carrega consigo e que pode conter objetos.

MOVE: operacao efetuavel por um robo, que resulta em ele passar a localizar-se na esquina adjacente `aquela em que ele se encontra se 
(1) ela existe e (2) nao existe um muro nesta esquina. A esquina adjacente que o robo passa a ocupar e' determinada por sua orientacao.

TURNLEFT: operacao efetuavel por um robo, que resulta em ele passar a orientar-se na direcao determinada por uma rotacao 90 graus `a
esquerda em relacao a sua orientacao corrente.

PICKBEEPER: operacao efetuavel por um robo, que resulta em um incremento de um beeper no numero de beepers contidos na sacola do
robo e em um decremento de um beeper no numero de beepers contidos na esquina em que o robo se encontra. A operacao so' pode ser
realizada se houver ao menos um beeper na esquina onde o robo se encontra.

PUTBEEPER: operacao efetuavel por um robo, que resulta em um decremento de um beeper no numero de beepers contidos na sacola do
robo e em um incremento de um beeper no numero de beepers contidos na esquina em que o robo se encontra. A operacao so' pode ser
realizada se houver ao menos um beeper na sacola do robo.

Interacao:

Um robo chamado Karel obedece a comandos emitidos por um usuario da aplicacao que aqui se constroi. Sao eles: MOVE, TURNLEFT,
PICKBEEPER, PUTBEEPER. Quando as pre-condicaoes associadas aos comandos sao satisfeitas, o efeito do comando e' uma mudanca
no estado do DOMINIO e no da REPRESENTACAO. Quando nao sao, o efeito e' apenas uma mudanca no estado da REPRESENTACAO.
Esta diferenciacao e'  fundamental para ao menos duas funcoes: a de EXPLICACAO e CONVERSACAO e a de CORRECAO DE RUMO.

EXPLICACAO E CONVERSACAO: trata-se de uma funcao que se realiza atraves de perguntas e respostas que nao efetuam quaisquer modifi-
cacoes sobre o estado do dominio.

CORRECAO DE RUMO: trata-se de uma funcao que DESFAZ uma ou mais operacoes feitas no dominio e efetua uma serie arbitraria de
operacoes em seu lugar (e' o tipico UNDO de aplicacoes conhecidas).

Para este tipo de interacao e'  indispensavel uma representacao autonoma para o que o robo efetivamente faz e o que o usuario comanda,
podendo-se associar comandos a seus efeitos, na linha do tempo (ou HISTORICO da aplicacao).

*/

:- dynamic beepers/1.
:- dynamic karel/2. 
:- dynamic history/1.
:- dynamic bkpwalls/1.
:- dynamic bkpbeepers/1.
:- dynamic bkphistory/1.
:- dynamic bkpkarel/2.


%GENERAL KNOWLEDGE ABOUT WORLD, SPACE AND TIME

walls([loc(7,8),loc(6,8),loc(5,8),loc(4,8),loc(3,8),loc(2,8),loc(4,2),loc(4,3),loc(4,4),loc(3,4),loc(3,2),loc(2,2),loc(1,2),loc(0,2),loc(0,3),loc(0,4),
           loc(1,4),loc(9,0),loc(9,1),loc(9,2),loc(8,0),loc(7,0),loc(6,0),loc(6,1),loc(6,2)]).
hypoth([ ]).

start :-
	abolish(beepers/1), abolish(karel/2), abolish(history/1),
	abolish(bkpwalls/1), abolish(bkpbeepers/1),abolish(bkphistory/1), abolish(bkpkarel/2),
	assertz(beepers([loc(bag),loc(2,1),loc(2,3),loc(8,2),loc(7,3),loc(5,9),loc(4,9),loc(3,9),loc(2,9),loc(1,9)])),
	assertz(karel(loc(0,0),ori(n))), assertz(history([t(0,start,ok)])).

% INTERFACE DIRECTIVES
move :- advance_time(move), do(move).
turnleft :- advance_time(turnleft), do(turnleft).
pickbeeper :- advance_time(pickbeeper), do(pickbeeper).	
putbeeper :- advance_time(putbeeper), do(putbeeper).

	
advance_time(X) :- history(H), last(H,t(T,_,_)), NewTime is T+1, append(H,[t(NewTime,X,fail)],NewHistory),abolish(history/1),
		 assertz(history(NewHistory)).

succeed(X) :- history(H), last(H,t(T,start,ok)), append(H,[t(T,X,ok)],NewH), 
	          abolish(history/1), assertz(history(NewH)).
succeed(X) :- history(H), last(H,t(T,X,ok)), append(H,[t(T,X,ok)],NewH), 
	          abolish(history/1), assertz(history(NewH)).
succeed(X) :- history(H), last(H,t(T,X,fail)), delete(H,t(T,X,fail),TempH),append(TempH,[t(T,X,ok)],NewH), 
	          abolish(history/1), assertz(history(NewH)).

%COMMANDS
%MOVE
do(move) :- karel(loc(St,Av),ori(n)), !, not(at_end(karel)), !, not(facing_wall(karel)), X is  St +1,
                     abolish(karel/2), assertz(karel(loc(X,Av),ori(n))), succeed(move).
do(move) :- karel(loc(St,Av),ori(s)), !, not(at_end(karel)), !, not(facing_wall(karel)), X is  St -1, 
                     abolish(karel/2), assertz(karel(loc(X,Av),ori(s))), succeed(move).
do(move) :- karel(loc(St,Av),ori(e)),!, not(at_end(karel)), !, not(facing_wall(karel)),  X is  Av+1, 
                     abolish(karel/2), assertz(karel(loc(St,X),ori(e))), succeed(move).
do(move) :- karel(loc(St,Av),ori(w)), !, not(at_end(karel)), !, not(facing_wall(karel)), X is  Av-1, 
                     abolish(karel/2), assertz(karel(loc(St,X),ori(w))), succeed(move).
do(move) :- fail.

%TURNLEFT
do(turnleft) :- karel(loc(St,Av),ori(n)),
                     abolish(karel/2), assertz(karel(loc(St,Av),ori(w))), succeed(turnleft).
do(turnleft) :- karel(loc(St,Av),ori(w)),
                     abolish(karel/2), assertz(karel(loc(St,Av),ori(s))), succeed(turnleft).
do(turnleft) :- karel(loc(St,Av),ori(s)),
                     abolish(karel/2), assertz(karel(loc(St,Av),ori(e))), succeed(turnleft).
do(turnleft) :- karel(loc(St,Av),ori(e)),
                     abolish(karel/2), assertz(karel(loc(St,Av),ori(n))), succeed(turnleft).
%PUTBEEPER
do(putbeeper) :- karel(loc(St,Av),_), !, beepers([loc(bag)|T]),
                               abolish(beepers/1), append(T,[loc(St,Av)],B), assertz(beepers(B)), succeed(putbeeper).
do(putbeeper) :- fail.		   

%PICKBEEPER
do(pickbeeper) :- karel(loc(St,Av),_), beepers(B), !, in_list(loc(St,Av),B), delete(B,loc(St,Av),TempB),
                               abolish(beepers/1), append([loc(bag)],TempB,NewB), assertz(beepers(NewB)), succeed(pickbeeper).
do(pickbeeper) :- fail.		   


%QUESTION-ANSWERING
%"QUANTOS?" INDAGA SOBRE DADOS QUANTITATIVOS CONTEXTUALIZADOS
howmany(beepers,bag) :- beepers(B), 
			       findall(Y,(in_list(Y,B),Y=loc(bag)),SL),
			       elems_in_list(SL,Z), write('Karel has '), write(Z), write(' beeper(s) in his bag.'),nl.

howmany(beepers,world) :- beepers(B), 
			      findall(Y,(in_list(Y,B),Y=loc(_,_)),SL),
			       elems_in_list(SL,Z), write('At this moment, '), write(Z), write(' beeper(s).'),nl.

%"ONDE ESTA'?" INDAGA SOBRE LOCALIZACAO CORRENTE DE ELEMENTOS UNIVOCAMENTE IDENTIFICAVEIS
%OU DE TODOS OS ELEMENTOS DE UM CONJUNTO
where(karel) :- karel(L,O),!,write('Karel is at corner ('),write(L),write('), facing '),write(O),write('.').
where(walls) :- walls(W), writeout(W,'The walls in this world are located at the following corners: ','').
where(beepers) :- beepers(B), writeout(B,'The beepers in this world are located at the following places: ','').

%"POR QUE NAO?" INDAGA SOBRE FATOS OCORRIDOS
why_not :- history(H), last(H,t(_,move,fail)), at_end(karel), write('Because Karel is at the end of the world.'), nl.
why_not :- history(H), last(H,t(_,move,fail)), facing_wall(karel), write('Because Karel is facing a wall.'), nl.
why_not :- history(H), last(H,t(_,putbeeper,fail)), empty_bag, write('Because Karel has no beepers in his bag.'), nl.
why_not :- history(H), last(H,t(_,pickbeeper,fail)), write('Because there are no beepers where Karel is.'), nl.
why_not :- history(H), last(H,t(_,X,ok)), !, write('But Karel did '), write(X), write(', alright.'), nl.

%"E SE?" INDAGA SOBRE FATOS HIPOTETICOS
what_if :-  hypoth([ ]), abolish(hypoth/1), assertz(hypoth([what_if])),
	   walls(W), beepers(B),history(H), karel(Loc,Ori),
	  assertz(bkpwalls(W)), assertz(bkpbeepers(B)),assertz(bkphistory(H)), assertz(bkpkarel(Loc,Ori)).
ok :- bkpwalls(W), bkpbeepers(B), bkphistory(H), bkpkarel(Loc,Ori),
        abolish(walls/1), abolish(beepers/1),abolish(history/1), abolish(karel/2),
        assertz(walls(W)), assertz(beepers(B)),assertz(history(H)), assertz(karel(Loc,Ori)),
        abolish(bkpwalls/1), abolish(bkpbeepers/1),abolish(bkphistory/1), abolish(bkpkarel/2), abolish(hypoth/1),
        assertz(hypoth([ ])).

% BEGIN UTILITY PREDICATES

empty_bag :- not(beepers([loc(bag)|_])).
at_end(karel) :- karel(loc(St,_),ori(n)), St=9; karel(loc(St,_),ori(s)), St=0; karel(loc(_,Av),ori(w)), Av=0; karel(loc(_,Av),ori(e)), Av=9.
facing_wall(karel) :- karel(loc(St,Av),ori(n)), walls(W), NSt is St+1, in_list(loc(NSt,Av),W); 
		      karel(loc(St,Av),ori(s)), walls(W), NSt is St-1, in_list(loc(NSt,Av),W);
		      karel(loc(St,Av),ori(w)), walls(W), NAv is Av-1, in_list(loc(St,NAv),W); 
		      karel(loc(St,Av),ori(e)), walls(W), NAv is Av+1, in_list(loc(St,NAv),W).

in_list(H,[H|_]).
in_list(X,[_|T]) :- in_list(X,T).

elems_in_list([ ],0).
elems_in_list([_|T],Y) :- elems_in_list(T,X), Y is X+1.

writeout(List,PreText,PostText) :- walls(List), write(PreText),nl,
				 findall([Street,Av], in_list(loc(Street,Av),List),Streets), sort(Streets,SortedStreets),write(SortedStreets),nl,
				 write(PostText),nl. 
writeout(List,PreText,PostText) :- beepers(List), write(PreText),nl,
				 findall([Street,Av], in_list(loc(Street,Av),List),Streets), sort(Streets,SortedStreets),write(SortedStreets),nl,
				 write(PostText),nl. 

%END UTILITY PREDICATES



