The problem
An elevator in a tower of seven floors numbered from 0 to 6. The hardware and software components are:
- A cabin, with doors and a command panel to choose a destination
- An Elevator Shaft, which moves the Cabin and present at each floor a button to call the Cabin
- A Command And Control (C2) software receives information and send messages to : opens and closes the doors and moves or stops the Cabin
Elevator Shaft send to C2 the location of the Cabin as a percentage: 0 is the bottom of the tower, 1.0 is the top.
A typical use case is:
- The cabin is at floor 0
- At time = 80, user "U1" at floor 6 press the "call" button, the cabin moves from 0 to 6
- At time = 100, user "U2" call the cabin from floor 2, when the cabin is at floor 2, C2 stops it, opens the doors, close the doors and get going to 6
- At time = 150, user "U2", from the Cabin press "floor 0" button, its request in memorized, and it will be executed after the arrival at 6
- The cabin finally arrive at floor 6, C2 stops, opens the doors, closes the doors and send a message to Elevator Shaft to go to floor 0
The context
This problem has been well solved in Java and C++, with 90/100 lines of code.
It has also been specified with a tool named Stimulus, in a declarative form which can be "executed" (it works!). I'm trying to code the declarative requirements in Prolog to measure the distance between a formal, declarative, executable specification and the Prolog code.
My question
The whole problem require a lot of clauses, I try to solve one by one.
First, I need the predicate: "is the cabin has to stop at location #N?"
I write the clause stopIsRequired
which is verified when a user want to stop at the nth floor (see scenario, at #2 and #6 here) AND the current location of the elevator cabin is at the requested floor (0.33 and 1.0 here).
Here is my first try:
#!/usr/bin/swipl
epsilon( 0.01 ).
floor_locations([ 0.0, 0.17, 0.33, 0.5, 0.67, 0.83, 1.0 ]).
scenario([ false, false, true, false, false, false, true ]).
stopIsRequired( [true|_], CabinLocation, [Floor_location|_] ) :-
Distance is abs( CabinLocation - Floor_location ),
epsilon( Epsilon ),
Distance =< Epsilon,
!.
stopIsRequired( [false|Floor_has_to_be_served_list_tail], CabinLocation, [_|Floor_locations_tail] ) :-
stopIsRequired( Floor_has_to_be_served_list_tail, CabinLocation, Floor_locations_tail ).
stopIsRequired( [], _, [] ).
/*--------------------------------- TESTS ---------------------------------*/
scenario([ false, false, true, false, false, false, true ]).
stopIsRequired_tests( [Location|Locations] ) :-
scenario( Scenario ),
floor_locations( Floor_locations ),
CabinLocation is Location + 0.005,
stopIsRequired( Scenario, CabinLocation, Floor_locations ),
format( "Cabin must stop when location equals ~w~n", [CabinLocation]),
stopIsRequired_tests( Locations ).
stopIsRequired_tests( [_|Locations] ) :-
stopIsRequired_tests( Locations ).
stopIsRequired_tests( [] ).
stopIsRequired_tests :-
floor_locations( Locations ),
stopIsRequired_tests( Locations ).
I expect that stopIsRequired_tests
prints "Cabin must stop when location equals 0.335" and "Cabin must stop when location equals 1.005" but only "Cabin must stop when location equals 0.335" is printed.