
/**************************************************************************/
/*	            Indigolog OAA Elevator controller                     */
/*		 ########################################                 */
/*                  Alexei Lapouchnian, December 2000                     */
/*                                                                        */
/*                  based on Elevator Controller agent                    */
/*                      written by Hector Levesque                        */
/**************************************************************************/

/*GENERAL*******************************************************************/
:- multifile prim_action/1, prim_fluent/1, causes_val/4, poss/2, proc/2,
exog_action/1.

/*FLUENTS********************************************************************/
prim_fluent(floor).             /* the floor the elevator is on */
prim_fluent(lights).            /* call buttons of all floors as a list */
prim_fluent(opened).		/* the status of the elevator doors */

/*PRIMITIVE ACTIONS**********************************************************/

%Bring the elevator down one floor
prim_action(down).              
execute(down,_) :- write('down'), nl, oaa_Solve(down,[/*reply(none)*/]).
%cannot move down if already on the first floor or if doors are open
poss(down,neg(or(floor=1,opened))).

%Bring the elevator up one floor
prim_action(up). 
execute(up,_) :- write('up'), nl, oaa_Solve(up,[/*reply(none)*/]).
%cannot move up if already on the top floor or if doors are open
poss(up,neg(or(floor=6,opened))).

%Turn the call button off after serving the floor
prim_action(off(N)) :- fl(N).
execute(off(N),_) :- write('off'), nl, oaa_Solve(off(N),[/*reply(none)*/]).
poss(off(N),  and(floor=N,and(lighton(N),opened))).


%Open the elevator doors
prim_action(open_doors(N)) :- fl(N).
execute(open_doors(N),_) :- write('open_doors'),nl, 
	oaa_Solve(open_doors(N),[reply(none)]).
poss(open_doors(N), and(floor=N,lighton(N))).
		
%Close the elevator doors
prim_action(close_doors(N)) :- fl(N).
execute(close_doors(N),_) :- write('open_doors'),nl, 
	oaa_Solve(close_doors(N),[reply(none)]).
poss(close_doors(N), and(opened,floor=N)).


%Check the current floor
prim_action(current_floor).
execute(current_floor, Cur_floor) :- write('current floor:'), 
             oaa_Solve(current_floor(Cur_floor),[]), write(Cur_floor), nl.
poss(current_floor, true).
% current_floor is a sensing action - specify which fluent is updated by it
senses(current_floor, floor).   

/***************************************************************************/

/*****************************************************************************
 *                                                                           * 
 *	      CAUSES_VAL CLAUSES AND EXOG_OCCURS FOR OAA EVENTS		     *
 *                                                                           *
 *****************************************************************************/
exog_action(update_buttons(Vector)).
causes_val(update_buttons(V),lights, V, true).

/*CAUSAL LAWS****************************************************************/
causes_val(up,   floor, N, N is floor+1).
causes_val(down, floor, N, N is floor-1).
causes_val(off(N), lights, L, repl(lights,L,N,0)).
causes_val(open_doors(N),opened,true,true).
causes_val(close_doors(N),opened,false,true).

/*INITIAL SITUATION**********************************************************/
% Initial state: floor is 1 (default), the button states are unknown.
initially(floor, 1).
%Initially the doors are closed
initially(opened, false).

/*DOMAIN DEFINITIONS*********************************************************/
% Definition of fl(N) - possible floors
fl(N) :- N=1; N=2; N=3; N=4; N=5; N=6.

/*CATCH-ALL FOR ACTIONS W/O BoDIES*******************************************/
execute(_,_) :- true.
exog_occurs(_) :- fail.

/****************************************************************************/

% Definitions of complex conditions.
proc(below_floor(N), floor<N).
proc(above_floor(N), floor>N).
proc(next_floor_to_serve(N), lighton(N)).
proc(lighton(N), nth(lights,N,1)).
proc(floor_waiting, member(1,lights)).

repl([_|L],[X|L],1,X).
repl([Y|L1],[Y|L2],N,X) :- repl(L1,L2,M,X), N is M+1.

nth([X|_],1,X).
nth([_|L],N,X) :- nth(L,M,X), N is M+1.

member(X,[X|_]).
member(X,[_|L]) :- member(X,L).

% Definitions of complex actions.
proc(go_floor(N), while(neg(floor=N), if(below_floor(N),up,down))).
proc(serve_floor(N), [go_floor(N),open_doors(N),off(N),close_doors(N)]).			  
proc(handle_reqs(Max),      
    ndet( ?(neg(some(n,nth(lights,n,1)))),
            pi(n, pi(m, [ ?(and(nth(lights,n,1), m is Max - abs(floor-n))),
                          ?(m > 0),
			  serve_floor(n), 
			  handle_reqs(m) ] )))).

%______________________________________________________________________

proc(minimize_motion(Max),  /* iterative deepening search */
    ndet( [handle_reqs(Max)], pi(m, [?(m is Max+1), minimize_motion(m)]))).

%The main procedure
proc(control, 
[
	current_floor,
	prioritized_interrupts(
	[
		interrupt(member(1,lights),search(minimize_motion(0))),
		interrupt(true,no_op)
	])

]).


/*INITIALIZATION*************************************************************/ 

% Declaration of capabilities.
initial_solvables([solvable(update_buttons(Vector), [], [])]).
% Specify the name of the agent.
agent_name(elevator_controller).
