--- /dev/null
+/* least_time.pl
+ *
+ * By Mark Thom, 2020
+ *
+ * find_min_time/2 solves a problem sometimes posed in the first round
+ * of Google interviews: given a time of day in 24 H format, what is the
+ * lexographically least permutation of the time that is itself a
+ * valid time in 24 H format?
+ *
+ * Full generality is achieved using the reif library.
+ */
+
+:- module(least_time, [find_min_time/2,
+ write_time_nl/1]).
+
+
+:- use_module(library(dcgs)).
+:- use_module(library(format)).
+:- use_module(library(reif)).
+
+
+permutation([], []).
+permutation([X|Xs], Ys) :-
+ permutation(Xs, Yss),
+ select(X, Ys, Yss).
+
+
+valid_time([H1,H2,M1,M2], T) :-
+ memberd_t(H1, [0,1,2], TH1),
+ memberd_t(H2, [0,1,2,3,4,5,6,7,8,9], TH2),
+ memberd_t(M1, [0,1,2,3,4,5], TM1),
+ memberd_t(M2, [0,1,2,3,4,5,6,7,8,9], TM2),
+ ( maplist(=(true), [TH1, TH2, TM1, TM2]) ->
+ ( H1 =:= 2 ->
+ ( H2 =< 3 ->
+ T = true
+ ; T = false
+ )
+ ; T = true
+ )
+ ; T = false
+ ).
+
+
+permuted_times(Time, PermutedTimes) :-
+ setof(P, permutation(Time, P), PermutedTimes0),
+ tfilter(valid_time, PermutedTimes0, PermutedTimes).
+
+
+find_min_time(Time, Min) :-
+ valid_time(Time, true),
+ permuted_times(Time, PermutedTimes),
+ find_min_time_(PermutedTimes, Time, Min).
+
+find_min_time_([], Min, Min).
+find_min_time_([Time|Times], MinSoFar, Min) :-
+ ( Time @< MinSoFar ->
+ find_min_time_(Times, Time, Min)
+ ; find_min_time_(Times, MinSoFar, Min)
+ ).
+
+
+write_time_nl(Time) :-
+ format("\"~w~w:~w~w\"~n", Time).