:- [flux]. :- ['cleanbot_simulator']. elementary_action(clean). elementary_action(go). elementary_action(turn). state_update(Z1, clean, Z2, []) :- holds(at(X,Y), Z1), update(Z1, [cleaned(X,Y)], [], Z2). state_update(Z1, turn, Z2, []) :- holds(facing(D), Z1), (D#<4 #/\ D1#=D+1) #\/ (D#=4 #/\ D1#=1), update(Z1, [facing(D1)], [facing(D)], Z2). state_update(Z1, go, Z2, [Light]) :- holds(at(X,Y), Z1), holds(facing(D), Z1), adjacent_point(X, Y, D, X1, Y1), update(Z1, [at(X1,Y1)], [at(X,Y)], Z2), light_perception(X1, Y1, Light, Z2). light_perception(X, Y, Percept, Z) :- X_east #= X+1, X_west #= X-1, Y_north #= Y+1, Y_south #= Y-1, ( Percept = false, not_holds(occupied(X_east,Y), Z), not_holds(occupied(X,Y_north), Z), not_holds(occupied(X_west,Y), Z), not_holds(occupied(X,Y_south), Z) ; Percept = true, or([occupied(X_east,Y),occupied(X,Y_north), occupied(X_west,Y),occupied(X,Y_south)], Z) ). adjacent_point(X, Y, D, X1, Y1) :- [X,Y,X1,Y1] :: 1..6, D :: 1..4, (D#=1) #/\ (X1#=X) #/\ (Y1#=Y+1) #\/ (D#=2) #/\ (X1#=X+1) #/\ (Y1#=Y) #\/ (D#=3) #/\ (X1#=X) #/\ (Y1#=Y-1) #\/ (D#=4) #/\ (X1#=X-1) #/\ (Y1#=Y). init(Z0) :- Z0 = [at(1,1),facing(1) | Z], not_holds(occupied(1,1), Z), not_holds_all(at(_,_), Z), not_holds_all(cleaned(_,_), Z), not_holds_all(occupied(_,0), Z0), not_holds_all(occupied(_,7), Z0), not_holds_all(occupied(0,_), Z0), not_holds_all(occupied(7,_), Z0), not_holds(occupied(1,2), Z), not_holds(occupied(2,1), Z), not_holds(occupied(2,2), Z), duplicate_free(Z0). main :- init(Z0), execute(clean, Z0, Z1), Choicepoints = [1,1,[1,2]], Backtrack = [], main_loop(Choicepoints, Backtrack, Z1). main_loop([X,Y,Choices|Choicepoints], Backtrack, Z) :- Choices = [Direction|Directions] -> ( go_in_direction(X, Y, Direction, Z, Z1) -> execute(clean, Z1, Z2), holds(at(X1,Y1), Z2), Choicepoints1 = [X1,Y1,[1,2,3,4], X, Y, Directions | Choicepoints], Backtrack1 = [X,Y|Backtrack], main_loop(Choicepoints1, Backtrack1, Z2) ; main_loop([X,Y,Directions|Choicepoints], Backtrack, Z) ) ; backtrack(Choicepoints, Backtrack, Z). backtrack(_, [], Z) :- final_output(Z). backtrack(Choicepoints, [X,Y|Backtrack], Z) :- go_back_to_room(X, Y, Z, Z1), main_loop(Choicepoints, Backtrack, Z1). go_in_direction(X, Y, D, Z1, Z2) :- adjacent_point(X, Y, D, X1, Y1), \+ knows(cleaned(X1,Y1), Z1), knows_not(occupied(X1,Y1), Z1), turn_to(D, Z1, Z), execute(go, Z, Z2). go_back_to_room(X, Y, Z1, Z2) :- holds(at(X1,Y1), Z1), adjacent_point(X1, Y1, D, X, Y), turn_to(D, Z1, Z), execute(go, Z, Z2). turn_to(D, Z1, Z2) :- knows(facing(D), Z1) -> Z2 = Z1 ; execute(turn, Z1, Z), turn_to(D, Z, Z2). final_output(Z) :- var(Z), !. final_output([F|Z]) :- ( F = occupied(_,_) -> write(F), nl ; F = cleaned(_,_) -> write(F), nl ; true ), final_output(Z).