word(0, '') :- !.
word(1, 'one') :- !.
word(2, 'two') :- !.
word(3, 'three') :- !.
word(4, 'four') :- !.
word(5, 'five') :- !.
word(6, 'six') :- !.
word(7, 'seven') :- !.
word(8, 'eight') :- !.
word(9, 'nine') :- !.
word(10, 'ten') :- !.
word(11, 'eleven') :- !.
word(12, 'twelve') :- !.

prefix(N, 'twen') :- 2 is N div 10, !.
prefix(N, 'thir') :- (N is 13 ; 3 is N div 10), !.
prefix(N, 'fif') :- (N is 15 ; 5 is N div 10), !.
prefix(N, W) :- N < 20, !, M is N mod 10, word(M, W).
prefix(N, W) :- !, M is N div 10, word(M, W).

postfix(18, 'een') :- !.
postfix(N, 'teen') :- N > 12, N < 20, !.
postfix(N, 'y') :- 8 is N div 10, !.
postfix(_, 'ty') :- !.

hour(0, W) :- !, word(12, W).
hour(H, W) :- !, word(H, W).

minute(0, '') :- !.
minute(M, W) :- M < 10, !,
    word(M, Mw), swritef(W, 'oh %w', [Mw]).
minute(M, W) :- M < 13, !, word(M, W).
minute(M, W) :- M < 20, !,
    prefix(M, Pre), postfix(M, Post),
    swritef(W, '%w%w', [Pre, Post]). 
minute(M, W) :- M < 60, !,
    prefix(M, Pre), postfix(M, Post),
    SndN is M mod 10,
    %word(SndN, Snd), swritef(W, '%w%w %w', [Pre, Post, Snd]).
    ( SndN is 0, !, swritef(W, '%w%w', [Pre, Post]) ;
        !, word(SndN, Snd), swritef(W, '%w%w %w', [Pre, Post, Snd]) ).

mer(H, S) :- H < 12, !, S = 'am'.
mer(_, S) :- S = 'pm'.

% time format: HH:MM
tell_time(T) :-
    split_string(T, ':', '', [Hstr, Mstr]),
    number_string(H, Hstr), H >= 0, H < 24, number_string(M, Mstr),
    mer(H, Mer), H_ is H mod 12,
    tell_time(H_, M, Mer), write('\n').

tell_time(H, 30, Mer) :- !,
    hour(H, Hw), writef('It is half past %w %w.', [Hw, Mer]).

tell_time(H, 15, Mer) :- !,
    hour(H, Hw), writef('It is quarter past %w %w.', [Hw, Mer]).

tell_time(H, 45, Mer) :- !,
    NextH is H + 1, hour(NextH, Hw),
    writef('It is quarter before %w %w.', [Hw, Mer]).

tell_time(H, 0, Mer) :- !,
    hour(H, Hw), writef('It is %w %w', [Hw, Mer]).

tell_time(H, M, Mer) :- !,
    hour(H, Hw), minute(M, Mw),
    writef('It is %w %w %w.', [Hw, Mw, Mer]).

program :-
    read(In), maplist(tell_time, In).