:- ['2_special_flux'].

:- ['perform1'].

init(Z0) :-
      Z0 = [at(2), carries(1, 2), carries(2, 3), empty(3), request(2, 4), request(1, 5), request(1, 2)].

poss(pickup(B,R), Z) :- holds(empty(B), Z),
                        holds(at(R1), Z),
                        holds(request(R1,R), Z).

poss(deliver(B), Z) :- holds(at(R), Z),
                       holds(carries(B,R), Z).

poss(go(D), Z) :- holds(at(R), Z), (D=up, R<6 ; D=down, R>1).

state_update(Z1, pickup(B, R), Z2) :-
   holds(at(R1), Z1),
   update(Z1, [carries(B,R)], [empty(B),request(R1,R)], Z2).

state_update(Z1, deliver(B), Z2) :-
   holds(at(R), Z1),
   update(Z1, [empty(B)], [carries(B,R)], Z2).

state_update(Z1, go(D), Z2) :-
   holds(at(R), Z1),
   ( D = up -> R1 is R + 1
             ; R1 is R - 1 ),
   update(Z1, [at(R1)], [at(R)], Z2).


main :- init(Z), main_loop(Z).

main_loop(Z) :-
   poss(deliver(B), Z)     -> execute(deliver(B), Z, Z1),
                              main_loop(Z1) ;
   poss(pickup(B,R), Z)    -> execute(pickup(B,R), Z, Z1),
                              main_loop(Z1) ;
   continue_delivery(D, Z) -> execute(go(D), Z, Z1),
                              main_loop(Z1) ;
   true.

continue_delivery(D, Z) :-
   ( holds(empty(_), Z), holds(request(R1,_), Z)
     ;
     holds(carries(_,R1), Z) ),
   holds(at(R), Z),
   ( R < R1 -> D = up
             ; D = down ).
