# Problem
Write and fully demonstrate a program that selects a set of acceptable meeting times for a set of people. Each person provides a set of free time slots. For example:
```prolog
free(ann,slot(time(8,0,am),time(9,0,am))).
free(ann,slot(time(10,0,am),time(11,0,am))).
free(ann,slot(time(8,0,pm),time(9,0,pm))).
free(bob,slot(time(7,0,am),time(8,30,am))).
free(bob,slot(time(10,0,am),time(11,0,am))).
free(bob,slot(time(11,30,am),time(9,0,pm))).
free(carla,slot(time(8,0,am),time(9,0,am))).
free(carla,slot(time(10,0,am),time(10,15,am))).
free(carla,slot(time(11,0,am),time(8,30,pm))).
free(dave,slot(time(8,0,am),time(9,0,am))).
free(dave,slot(time(10,0,am),time(11,0,am))).
free(ed,slot(time(9,0,am),time(10,0,am))).
```
shows that Bob has three time slots that are free, one of which is 7:00 AM to 8:30 AM. Bob's not very busy!
Start with a simpler problem. A skeletal solution is:
```prolog
#!/bin/gprolog --consult-file
:- include('data.pl').
% Your code goes here.
main :- findall(Person,
meetone(Person,slot(time(8,30,am),time(8,45,am))),
People),
write(People), nl, halt.
:- initialization(main).
```
When complete, this program will print the names of people who can meet from 8:30 AM to 8:45 AM. This will be Ann, Carla, and Dave. If the "query" was for 5:30 to 6:45 AM there would be no solutions.
Then, extend your solution to the complete problem. A skeletal solution is:
```prolog
#!/bin/gprolog --consult-file
:- include('data.pl').
:- include('uniq.pl').
% Your code goes here.
people([ann,bob,carla]).
main :- findall(Slot, meet(Slot), Slots),
uniq(Slots, Uniq),
write(Uniq), nl, halt.
:- initialization(main).
```
When complete, this program will print a list of compatible meeting times for Ann, Bob, and Carla: 8:00 AM to 8:30 AM, 10:00 AM to 10:15 AM, and 8:00 PM to 8:30 PM.
Given two time slots, there are several ways in which they can overlap, but some are symmetric. Draw pictures. Your predicate will need a rule for each way. Use the `\==` predicate to avoid zero-length meetings. A big hint is for your predicate to "return" a new time slot modeling the overlap.
A general Prolog hint is to use one or more variables to pass data "into" a predicate, and another variable to "return" data.
You'll also need a predicate for comparing two times (e.g. `lte`).
Test your solution thoroughly, by modifying `data.pl` and the list of people who want to meet.
# Process
I think the easiest predicate to create first is the predicate for comparing two times, `lte`.
The predicate `lte` is going to take the form of a rule, since it would only be satisfied under certain conditions. Times are formatted in our data like so:
```prolog
time(Hour, Minute, Period)
```
So, the beginning line would look something like this:
```prolog
lte(time(Hour1, Minute1, Period1), time(Hour2, Minute2, Period2)) :-
```
This rule is read as, "A pair of times satisfies the predicate `lte` if ..." or "A pair of times has a less than or equal to relation if ..."
Now, we need to ask ourselves, "What conditions make the first time less than or equal to the second time?" Those conditions are when:
1. The period of the first time is AM and the period of the second time is PM.
2. The hour of the first time is less than or equal to the hour of the second time.
3. The minute of the first time is less than or equal to the minute of the second time.
If any condition is true, then we can skip all remaining conditions after it.
We need to create a way to compare AM and PM. The easiest would be to associate AM and PM with numbers. In Prolog, it would look like this pair of facts with the same predicate:
```prolog
period(am, 0).
period(pm, 1).
```
These two predicates make it so that `am` is associated with `0` and `pm` is associated with `1`. We can call `period()` from inside the rule like so:
```prolog
lte(time(Hour1, Minute1, Period1), time(Hour2, Minute2, Period2)) :-
period(Period1, PeriodNumber1),
period(Period2, PeriodNumber2),
```
Since `PeriodNumber1` and `PeriodNumber2` are new variables, they will take on the value in the `period` fact which is matched using the values of `Period1` and `Period2` respectively. For example, calling `period(Period1, PeriodNumber1)` will match `period(am, 0)` if `Period1` is equal to `am`, causing `PeriodNumber1` to be set to `0`.
```prolog
lte(time(Hour1, Minute1, Period1), time(Hour2, Minute2, Period2)) :-
period(Period1, PeriodNumber1),
period(Period2, PeriodNumber2),
( PeriodNumber1 < PeriodNumber2
; PeriodNumber1 = PeriodNumber2,
( Hour1 < Hour2
; Hour1 = Hour2, Minute1 =< Minute2
)
).
```
With a way to determine if a time is less than or equal to another, we now need a predicate to determine if a person can meet between 8:30 AM and 8:45 AM. What conditions would need to be true for that to be the case? Those conditions are when:
1. The person's free time starts before or at 8:30 AM.
2. The person's free time ends before or at 8:45 AM.
```prolog
meetone(Person, slot(Start, End)) :-
free(Person, slot(FreeStart, FreeEnd)),
lte(FreeStart, Start),
lte(End, FreeEnd).
```
This is the final section of code that completes `meetone.pl`:
```prolog
meetone(Person, slot(Start, End)) :-
free(Person, slot(FreeStart, FreeEnd)),
lte(FreeStart, Start),
lte(End, FreeEnd).
lte(time(Hour1, Minute1, Period1), time(Hour2, Minute2, Period2)) :-
period(Period1, PeriodNumber1),
period(Period2, PeriodNumber2),
( PeriodNumber1 < PeriodNumber2
; PeriodNumber1 = PeriodNumber2,
( Hour1 < Hour2
; Hour1 = Hour2, Minute1 =< Minute2
)
).
period(am, 0).
period(pm, 1).
```
The output of `meetone.pl` is:
```
[ann,carla,dave]
```
The `period()` fact and `lte()` rule can be copied to `meet.pl` to finish that program.
# Answer
...