(ns trains | |
(:import java.time.LocalDateTime | |
java.time.format.DateTimeFormatter)) | |
(def trips | |
;; Each trip is a uni-directional trip. | |
[{:id 0, | |
:stops [{:stop "Wynyard" | |
:time "2015-07-15T18:47"} | |
{:stop "Town Hall" | |
:time "2015-07-15T18:49"} | |
{:stop "Central" | |
:time "2015-07-15T18:53"} | |
{:stop "Redfern" | |
:time "2015-07-15T18:55"}]} | |
{:id 1, | |
:stops [{:stop "Wynyard" | |
:time "2015-07-15T18:48"} | |
{:stop "Town Hall" | |
:time "2015-07-15T18:50"} | |
{:stop "Redfern" | |
:time "2015-07-15T18:54"} | |
{:stop "Redfern" | |
:time "2015-07-15T18:56"}]}]) | |
(defn- parse-date | |
[date-str] | |
(LocalDateTime/parse date-str DateTimeFormatter/ISO_DATE_TIME)) | |
(defn- is-date-after? | |
[date1 date2] | |
(.isAfter (parse-date date1) | |
(parse-date date2))) | |
(defn goes-to? | |
"Returns 'true' if the given trip stops at the origin THEN the destination." | |
[origin destination trip] | |
(let [ts (filter #(or (= origin %) | |
(= destination %)) | |
(map :stop (:stops trip)))] | |
(if (seq ts) | |
(and (= origin (first ts)) | |
(= destination (first (rest ts))))))) | |
(defn- get-stop-info | |
"Gets the stop info for a stop in the context of a given trip" | |
[trip stop] | |
(if-let [ts (seq (filter #(= stop (:stop %)) (:stops trip)))] | |
(first ts))) | |
(defn is-after? | |
"Returns 'true' if the given trip gets to the origin after the given time." | |
[origin time trip] | |
(if-let [stop-info (get-stop-info trip origin)] | |
(is-date-after? (:time stop-info) | |
time))) | |
(defn get-all-trips | |
"Returns all trips after 'time-now' that can take someone from 'origin' to 'destination'" | |
[trips time-now origin destination] | |
(->> trips | |
(filter (partial goes-to? origin destination)) | |
(filter (partial is-after? origin time-now)))) | |
(defn- get-time-at | |
"Given a stop and a trip, gets the time of the trip at that stop" | |
[stop trip] | |
(if-let [stop-info (get-stop-info trip stop)] | |
(:time stop-info))) | |
(defn earliest | |
"Given a stop and 2 trips, returns the trip which arrives | |
at that stop earlier" | |
[stop trip1 & [trip2 _]] | |
(if (and trip2 | |
(is-date-after? (get-time-at stop trip1) | |
(get-time-at stop trip2))) | |
trip2 | |
trip1)) | |
(defn get-earliest | |
[trips time-now origin destination] | |
(let [reduce-fn (partial earliest origin) | |
candidates (get-all-trips trips time-now origin destination)] | |
(if (seq candidates) | |
(reduce reduce-fn | |
candidates)))) | |
(defn run-tests | |
"Some really basic tests (obviously we'd use clojure.test for this in a real app)" | |
[] | |
(assert (= 0 (:id (get-earliest trips "2015-07-15T18:46" "Wynyard" "Town Hall")))) | |
(assert (= 1 (:id (get-earliest trips "2015-07-15T18:47" "Wynyard" "Town Hall")))) | |
(assert (nil? (get-earliest trips "2015-07-15T18:48" "Wynyard" "Town Hall"))) | |
(assert (nil? (get-earliest trips "2015-07-15T18:46" "Town Hall" "Wynyard")))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment