/*================================================================
|
| Travel Agent Tools.
| 
| This file defines rules based on the flight database provided as database.pl.
|
| The database has three types of atomic predicates:
|   1) segment(flight(Airline,Number), OriginAirport, DestinationAirport, DepartureTime, ArrivalTime)
|   2) airport(Abbreviation, State, GMT)
|   3) airline(Code,Name)
|
| flight(Airline,Number) is a functor that represents a particular flight,
| but note that airlines often define a flight to have multiple segments.
| So it is not enough to say that you are using flight(ua,10), but
| you would need to differentiate between whether you are using the leg
| from LGA -> IAH, from IAH-> DEN, or DEN -> BOI.
|
| time(H,M) is always expressed in 24-hour time, such that 0 <= H <= 23,
| 0 <= M <= 59.
| 
| All flight times are expressed in local time for the relevant airport
| (and without any use of daylight savings times).
| 
| The airport abbreviation is the standard 3-letter code (e.g. stl).
| The airport's GMT time is an integer that represents the difference
| in the number of hours between the airport's local time and
| Greenwich Mean Time. For example, St. Louis is at -6 GMT, which means that when
| it is 11:00am in Greenwich, it is 5:00am in St. Louis.
| 
| The Airline Names are only necessary for pretty printing
|
+================================================================*/


/*----------------------------------------------------------------
| Predicate:  minutes(time(H,M), N).
| 
| N is the number of minutes from the start of the day until time(H,M).
| 
| Preconditions: H and M must be bound
| 
| Examples:
| 
| ?- minutes(time(13,45), N).
|   N = 825.
| 
| ?- minutes(time(0,0), N).
|   N = 0.
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate:  as_early(T1,T2).
| 
| true if time T1 is at least as early in the day as T2.
| (We assume that both are expressed in the same timezone).
| 
| Preconditions: both T1 and T2 must be bound.
| 
| Examples:
| ?- as_early(time(5,30), time(8,45)).
|  true.
| 
| ?- as_early(time(5,30), time(5,30)).
|  true.
| 
| ?- as_early(time(23,58), time(0,05)).
|  false.
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate:  between(T1,T2,T3).
| 
| true if time T2 is within the cyclical range [T1,T3].
| (We assume that all times are expressed in the same timezone).
| 
| Preconditions: all of T1, T2, and T3 must be bound.
| 
| Examples:
| ?- between(time(5,30), time(7,13), time(8,45)).
|  true.
| 
| ?- between(time(5,30), time(8,45), time(8,45)).
|  true.
| 
| ?- between(time(5,30), time(5,30), time(8,45)).
|  true.
| 
| ?- between(time(5,30), time(4,30), time(8,45)).
|  false.
| 
| ?- between(time(5,30), time(11,30), time(8,45)).
|  false.
| 
| ?- between(time(5,30), time(5,30), time(5,30)).
|  true.
| 
| ?- between(time(5,30), time(5,29), time(5,30)).
|  false.
| 
| ?- between(time(22,15), time(23,49), time(1,23)).
|  true.
| 
| ?- between(time(22,15), time(1,15), time(1,23)).
|  true.
| 
| ?- between(time(22,15), time(5,05), time(1,23)).
|  false.
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate:  elapsed(T1,T2,M).
| 
| Elapsed time from T1 to T2 is M, where T1 and T2 are
| time(H,M) expressions and M expresses the number of minutes elapsed
| 
| Preconditions: both T1 and T2 must be bound.
| 
| T1 and T2 are assumed to be expressed in the same time zone, and that
| T2 is the next occurrence of that time of day following T1. That is,
| the elapsed time should be in the range [0,1439], as it is strictly less than 24 hours.
| 
| Examples:
| ?- elapsed(time(5,30), time(8,45), M).
|  M = 195.
| 
| ?- elapsed(time(23,58), time(0,05), M).
|  M = 7
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate:  gmt(Airport, Local, Global)
| 
| True if Global is the GMT time that is equal to the Local time expressed at Airport.
| This should be applicable with either one of Local or Global being unbound. That is
| 
| Preconditions: Airport and at least one of Local or Global must be bound.
| 
| Examples:
| ?- gmt(stl, time(11,30), G).
|  G = time(17,30).
| 
| ?- gmt(stl, L, time(17,30)).
|  L = time(11,30).
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate: flight_time(F, Origin, Destination, T)
| 
| True if the segment of flight F from Origin to Destination has
| an elapsed time of T minutes (taking into consideration the time zones
| of the airports).
| 
| Preconditions: F, Origin, and Destination must be bound
| 
| Examples:
| ?- flight_time(flight(aa,1040), stl, ord, T).
|   T = 75.
| 
| ?- flight_time(flight(dl,2088), stl, slc, T).
|   T = 197.
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate: flies(Airline, Airport).
| 
| True if Airline has at least one flight into or out of Airport
| 
| Examples:
| ?- flies(as,stl).      /* Alaskan Airlines */
|   true.
| 
| ?- flies(ha,stl).      /* Hawaiian Airlines */
|   false.
| 
| ?- setof(A, flies(A,pvd), L).
|   L = [b6, dl, e9, ev, ua, us, wn, yv].
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate: nonstop(Origin, Destination).
| 
| True if there exists a direct flight segment from Origin to Destination.
| 
| Examples:
| ?- nonstop(stl,den).      /* Denver */
|   true.
| 
| ?- nonstop(stl,cos).      /* Colorado Springs */
|   false.
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate: nonstop(Origin, Destination, Airline).
| 
| True if Airline operates a direct flight segment from Origin to Destination.
| 
| Examples:
| ?- nonstop(stl,den,wn).      /* Southwest Airlines */
|   true.
| 
| ?- nonstop(stl,den,aa).      /* American Airlines */
|   false.
| 
| ?- setof(D, nonstop(stl,D,dl), L).    /* Destinations from St. Louis on Delta */
|   L = [atl, dtw, msp, slc].
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate: arrivals(Airport, Start, End, L).
| 
| L is a list of all flights that arrive at Airport during the interval
| starting at time Start and ending with time End (where it is possible
| that the interval wraps around midnight).
| 
| Preconditions: Airport, Start, and End must be bound
| 
| Examples:
| 
| ?- arrivals(stl, time(10,00), time(10,10), L).
| L = [flight(e9, 3360), flight(e9, 4102), flight(wn, 4)].
| 
| ?- arrivals(stl, time(9,25), time(9,25), L).
| L = [flight(wn, 2425), flight(wn, 340), flight(wn, 3482), flight(wn, 3861), flight(wn, 683), flight(wn, 749)].
| 
| ?- arrivals(lax, time(23,50), time(0,45), L).
| L = [flight(aa, 1035), flight(aa, 2497), flight(b6, 677), flight(dl, 2363), flight(ua, 1445)]
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate: wait(F1, Airport, F2, W)
| 
| W is the wait time (in minutes) between the arrival of F1 at Airport
| and the subsequent departure of F2.
| 
| Preconditions: F1, Airport, and F2 must be bound.
| 
| Examples:
|
| ?- wait(flight(wn,369), mdw, flight(wn,369), W).
| W = 50 ;
|
| ?- wait(flight(wn,2766), mdw, flight(wn,2766), W).
| W = 40 ;
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate: connecting(F1, Airport, F2, MinGap, MaxGap)
| 
| true if it is possible to arrive at Airport on F1 and depart on F2.
| 
| To make a connection the gap between the arrival of F1 and subsequent
| departure of F2 must be at least MinGap minutes, and at most MaxGap minutes.
| 
| Preconditions: Airport, MinGap, MaxGap must be bound.
| 
| Examples:
| 
| ?- connecting(flight(wn,1359), stl, F, 20, 40).
| F = flight(fl, 544) ;
| F = flight(wn, 1281) ;
| F = flight(wn, 1359) ;
| F = flight(wn, 2319) ;
| 
| ?- connecting(F, stl, flight(wn,1359), 20, 40).
| F = flight(e9, 3360) ;
| F = flight(e9, 4102) ;
| F = flight(aa, 1266) ;
| F = flight(wn, 1359) ;
| F = flight(wn, 2319) ;
| F = flight(wn, 4) ;
| 
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate: connecting_airline(F1, Airport, F2, MinGap, MaxGap)
| 
| Similar to connecting predicate, except that F1 and F2 must use same airline.
| 
| Examples:
| 
| ?- connecting_airine(flight(wn,1359), stl, F, 20, 40).
| F = flight(wn, 1281) ;
| F = flight(wn, 1359) ;
| F = flight(wn, 2319) ;
| 
| ?- connecting_airline(F, stl, flight(wn,1359), 20, 40).
| F = flight(wn, 1359) ;
| F = flight(wn, 2319) ;
| F = flight(wn, 4) ;
|
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate: travel_time(Itinerary, T)
| 
| True if the end-to-end travel time for the given itinerary is T.
|
| Examples:
|
| ?- travel_time([pwm, flight(b6, 609), jfk], T).
| T = 83 .
| 
| ?- travel_time([pwm, flight(b6, 609), jfk, flight(dl, 1394), pdx], T).
| T = 520 .
| 
| ?- travel_time([pwm, flight(ev, 4091), ewr, flight(wn, 369), mdw, flight(wn, 2766), pdx], T).
| T = 594 .
| 
| /* Travel from Pago Pago, American Somoa to St. Croix, U.S. Virgin Islands */
| ?- travel_time([ppg, flight(ha,466), hnl, flight(ua,106), lax, flight(dl,1406), dtw, flight(e9,3489),
|                 phl, flight(aa,1007), mia, flight(aa,1165), stx], T).
| T = 2280 .     /* Note that this is more than 24 hours. */
| 
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate: pretty_print(Itinerary)
| 
| Produces pretty output to describe itinerary, which is represented
| as an odd-length alternating list of airport/flight/airport
| progression, such as:
| 
|  [ppg, flight(ha,466), hnl, flight(ua,106), lax, flight(dl,1406), dtw,
|   flight(e9,3489), phl, flight(aa,1007), mia, flight(aa,1165), stx]
| 
| The output for this example appears as:
| 
|   Depart from PPG at 23:20 on Hawaiian Airlines flight #466 arriving at HNL at 5:40
|   Depart from HNL at 13:34 on United Airlines flight #106 arriving at LAX at 21:00
|   Depart from LAX at 23:00 on Delta Airlines flight #1406 arriving at DTW at 6:26
|   Depart from DTW at 8:10 on Pinnacle Airlines flight #3489 arriving at PHL at 10:04
|   Depart from PHL at 12:35 on American Airlines flight #1007 arriving at MIA at 15:25
|   Depart from MIA at 16:45 on American Airlines flight #1165 arriving at STX at 20:20
|   Total travel time is 2280 minutes.
| 
| Note: string atoms can be uppercased using the built-in predicate upcase_atom(Original,Upper).
| 
+----------------------------------------------------------------*/
% ... your code here ...




/*----------------------------------------------------------------
| Predicate: plan(Origin, Destination, MinConnect, MaxHops, MaxTime, Itinerary)
| 
| Generate an itinerary going from Origin to Destination
| (which never passes through any airport more than once)
| subject to the following additional constraints.
|
| MinConnect represents the tightest connection allowed, expressed in minutes
|   (e.g., 30 means that there must be at least 30 minutes between one arrival and connecting departure)
|
| MaxHops represents the maximum number of segments that may be used
|     (e.g., 1 means that it must be a nonstop)
| 
| MaxTime represents the maximum end-to-end travel time for a passenger that is allowed.
|  That is, in actual clock time, the length from the very first departure to the final arrival.
| 
| Example:
| 
| ?- plan(pwm, pdx, 30, 3, 600, I).   /* From Portland, Maine to Portland, Oregon in 10 hours */
| I = [pwm, flight(b6, 609), jfk, flight(dl, 1394), pdx] ;
| I = [pwm, flight(ev, 6046), iad, flight(ua, 1671), pdx] ;
| I = [pwm, flight(ev, 6046), iad, flight(ua, 72), den, flight(ua, 745), pdx] ;
| I = [pwm, flight(ev, 4091), ewr, flight(wn, 369), mdw, flight(wn, 2766), pdx] ;
| 
| (although order of results may vary)
+----------------------------------------------------------------*/
% ... your code here ...




/*====================================== Extra Credit ======================================*/

/*---------------------------------------------------------------------------------------
| Be the first to convince me that one of my published examples produces the wrong result.
| (+1 extra credit per example).
+----------------------------------------------------------------------------------------*/


/*----------------------------------------------------------------
| Predicate: plan(Origin, Destination, EarliestDeparture, LatestDeparture,
|                 MinConnect, MaxHops, MaxTime, Itinerary)
| 
| EarliestDeparture is a time specification that is the earliest time
|  of day the traveler is able to depart the origin.
|
| LatestDepaurture is a time specification that is the latest time of day the traveler
|  is able to depart the origin.
|
| MinConnect represents the tightest connection allowed, expressed in minutes
|   (e.g., 30 means that there must be at least 30 minutes between one arrival and connecting departure)
|
| MaxHops represents the maximum number of segments that may be used
|     (e.g., 1 means that it must be a nonstop)
| 
| MaxTime represents the maximum end-to-end travel time for a passenger that is allowed.
|  That is, in actual clock time, the length from the very first departure to the final arrival.
+----------------------------------------------------------------*/
