59
\$\begingroup\$

Since I saw the first one a few years ago, I always was subjugated by this kind of word clock where the time is actually spelled out by words being lit up or not into a meaningful sentence.

A Word Clock

The text displayed on that clock is the following.

IT IS HALF TEN
QUARTER TWENTY
FIVE MINUTES TO
PAST TWO THREE
ONE FOUR FIVE
SIX SEVEN EIGHT
NINE TEN ELEVEN
TWELVE O'CLOCK

Your task is to write such a working clock. Words are lit up if and only if they're relevant to printing the current time. Otherwise, they're lit down. Words are "lit up" by being printed and are "lit down" by being replaced by a number of spaces being the length of the word.

Example: if the current time is 17:23, the printed text must be exactly the following:

IT IS 
        TWENTY
FIVE MINUTES
PAST
         FIVE

Rules

  1. The time printed is the 12h variant, but without AM/PM.
  2. The rounding is done on the base of minutes only (seconds are totally irrelevant). The rounding is done to the closest multiple of 5. So, for example, even though 17:52:38 really is closest to 17:55, but since the seconds are irrelevant, 17:52 is actually rounded down to 17:50, and the text printed is "IT IS TEN MINUTES TO SIX" (with relevant spacing). So if XX is a multiple of five, XX will be used from HH:(XX-2):00 until HH:(XX+2):59. The word MINUTES must appear if FIVE, TEN or TWENTY are lit up in the minutes section (before "TO" or "PAST").
  3. All irrelevant words are replaced by as many spaces as needed to keep the text where it is located in the template above. Trailing spaces may be trimmed. Spaces relevant to keeping the text at the expected position must be kept.
  4. Trailing lines may be trimmed as well. Relevant empty lines are still required to appear. Example:

    IT IS      TEN
    
         MINUTES
    PAST TWO
    
  5. Do not light up TEN on the first line or FIVE on the third line when these values refer to the hours.

  6. You may accept an input. If you accept an input, the input will be the time to print in any valid format you want (string, list of integers, native time type your language support, ...), but no parameters are allowed if they're not related to the time to print. If you support no input, then you must use the current time. If you support both, that's better but there's no bonus ;)
  7. Your code may be a program, a function, a lambda but not snippet.
  8. If your language supports printing in any way, it must print the result (in a file, on the standard output, I don't mind). If your language doesn't support printing in any way, it is allowed to simply "return" the expected text. The result may be either all uppercase or all lowercase, not a mix of both.
  9. Standard loopholes apply.
  10. This is code-golf so the shortest code wins!
  11. In the measure of possible, please provide a link to an online interpreter of your language.

Test cases

Input:  <no input> (the current local time is 19:20)
Output:     
IT IS
        TWENTY
     MINUTES
PAST 

    SEVEN

Input: 13:15
Output: (empty line is being printed)
IT IS
QUARTER

PAST
ONE

Input: 13:58
Output: (rounding)
IT IS


     TWO



       O'CLOCK

Input: 14:30
Output: (half is always a edge-case)
IT IS HALF


PAST TWO

Input: 15:35
Output: (light up "TO")
IT IS
        TWENTY
FIVE MINUTES TO

    FOUR

Input: 10:00
Output: (do not use the TEN or FIVE on the first line when referring to the hours)
IT IS





    TEN
      O'CLOCK

Input: 12:00
Output: (O'CLOCK and a lot of empty lines)
IT IS






TWELVE O'CLOCK
\$\endgroup\$
  • 8
    \$\begingroup\$ Great challenge, I really like it! \$\endgroup\$ – Timtech Jan 18 '17 at 1:45

13 Answers 13

14
\$\begingroup\$

PHP, 387 384 353 352 342 323 310 306 298 293 291 bytes

Thanks @Christoph for golfing along with his excellent findings!
At least 45 bytes are on his account; 16 or more inspired by him.

A Marvel Team Up!

IT IS <?foreach([HALF,TEN,QUARTER,TWENTY,FIVE,MINUTES,TO,PAST,TWO,THREE,ONE,FOUR,FIVE,SIX,SEVEN,EIGHT,NINE,TEN,ELEVEN,TWELVE,"O'CLOCK"]as$w)echo strstr([w,ghj,dhj,ej,fhj,fghj,cj,fghi,fhi,ei,dhi,ghi][$m=date(i)/5+.5].mklnopqrstuvm[date(h)-($m<7)],99+$i)?$w:$w^$w^"       ","
  "[$i++%3^$i<3];

loops through the data and checks if the current index is in a generated string that contains the indexes of the words to light up (mapped to letters); appends linebreak or space depending on the index.

May yield notices if you dont´t use the default value for error_reporting (22519).

Test it online.

breakdown

IT IS <?
foreach([HALF,TEN,QUARTER,TWENTY,FIVE,MINUTES,TO,PAST,  // loop through words
TWO,THREE,ONE,FOUR,FIVE,SIX,SEVEN,EIGHT,NINE,TEN,ELEVEN,TWELVE,"O'CLOCK"]as$w)
    echo strstr(                    // search word index in ...
        [w,ghj,dhj,ej,fhj,fghj,cj,fghi,fhi,ei,dhi,ghi][$m=date(i)/5+.5] // minutes & co
        .mklnopqrstuvm[date(h)-($m<7)]                          // hours (-1 if minutes<33)
    ,99+$i                          // (map 0..20 to c..w)
    )?$w:$w^$w^"       ",           // if found, print string, else print spaces
    "\n  "[$i++%3^$i<3];            // if $i in [3,5,8,...], print newline, else space

Golfs:

  • $x/5+.5|0 is two bytes shorter than round($x/5).
  • Two calls of date(h) are one byte shorter than assigning the date result to a variable.
  • Using a single assigment golfed away the variable that the light-up indexes were stored in.
  • A string for the light-up indexes instead of an array saved around 30 bytes.
  • $w<A is three bytes shorter than $w=="\n" - make sure that no space is after a delimiter!
  • abs saved 8 bytes on the minutes word.
  • Thanks @Christoph: Moving from numbers to letters for the map rendered the separators obsolete and allowed one more string instead of array; saved 23+8 bytes.
    Using underscore as the first index allowed to include it into the "it is" alternatives; and it rendered the quotation for the hours obsolete.
  • Duplicating the 1 value in the hours map rendered the modulo obsolete and that with additional golfing saved 10 bytes. Inspired by @Christoph.
  • Calculating the linebreaks and spaces instead of hardcoding them shaved off 19 bytes.
  • Bit logic on strings saves 7 bytes: str_pad("",strlen($w)) -> $w^$w^" ". (Christoph)
  • If strtr´s second parameter is no string, it will be interpreted as an ascii code. saves 5 bytes.
\$\endgroup\$
  • \$\begingroup\$ This is very nice! I tried this implementation in Java when making sure the question was solvable, but it ended up being so complicated I gave up and used a longer, but more straightforward approach! So congrats on succeeding where I failed ;) \$\endgroup\$ – Olivier Grégoire Jan 18 '17 at 13:39
  • 1
    \$\begingroup\$ Beating of the rest: $i++%3^($i<3) to $i++%3^$i<3. I'm officially completly wasted now. I'll take a break until someone matches us. It was really fun. Thank you Titus for your teamwork! \$\endgroup\$ – Christoph Jan 19 '17 at 14:09
  • 1
    \$\begingroup\$ @Christoph You are ... GREAT seems to small a word. \o/ \$\endgroup\$ – Titus Jan 19 '17 at 14:14
18
\$\begingroup\$

TI-Basic, 335 334 bytes

Pretty much perfect, since the TI-84 calcs have 8x16 letter displays, and this is 8x15. Date is taken as input in order to support calcs earlier than TI-84, which do not have internal clocks. With no arguments, Input gets input by default into X and Y, similar to Prompt X,Y. So make X be hours (anything >=0 will work correctly) and have Y be minutes.

Input 
ClrHome
int(Y/5-5.6
Output(1,1,"IT IS
If Ans=~6
Output(8,8,"O'CLOCK
If 2=abs(3-abs(Ans
Output(3,1,"FIVE
If 4=abs(Ans
Output(1,12,"TEN
If 3=abs(Ans
Output(2,1,"QUARTER
If 2=abs(Ans
Output(2,8,"TWENTY
If sum(abs(Ans)={1,2,4,5
Output(3,5,"MINUTES
If not(Ans
Output(1,7,"HALF
If Ans<1 and Ans+6
Output(4,1,"PAST
If Ans>0
Output(3,14,"TO
12fPart(12(^~1)(X+(Y>32->A
If not(Ans
12->A
{21,6,10,25,30,41,45,51,61,66,70,81
.05Ans(A
Output(int(4+Ans),20fPart(Ans),sub("ONE   TWO   THREE FOUR  FIVE  SIX   SEVEN EIGHT NINE  TEN   ELEVENTWELVE",6A-5,6

Note 1: For TI-84+ you can replace Input with something like getTime:Ans(1->X:getTime:Ans(2->Y. Also, int(Y/5-5.6 is equivalent to round(Y/5,0)-6. And no, in this case int( could not be interchanged with iPart(.

Note 2: This prints the input just fine, but for asethetic reasons you probably want Pause at the end of the program to avoid the Done message upon program termination.

Edit: Byte count lowered because tokenized (see note on previous revision), also a bug is fixed thanks to @Neil. Third, fixed a bug I found myself which would have costed 2 bytes but the optimization actually saved 1 byte overall, and I also realized that I am getting input so I don't need to call getTime (duh?). Last, for anyone who wants to confirm this byte count, the only two byte token is sub(.

\$\endgroup\$
  • \$\begingroup\$ It seems to me that after outputting O'CLOCK the code will go on to output PAST too... \$\endgroup\$ – Neil Jan 18 '17 at 11:39
  • 2
    \$\begingroup\$ I count 545 bytes could you please enlighten me? \$\endgroup\$ – Christoph Jan 18 '17 at 14:29
  • 2
    \$\begingroup\$ @Christoph Found the related meta post: meta.codegolf.stackexchange.com/a/4764/29637 \$\endgroup\$ – Christoph Jan 18 '17 at 14:52
  • 1
    \$\begingroup\$ @OlivierGrégoire Actually it's not related to that previous line at all. What it's doing is converting 24-hour to 12-hour time and also to the nearest hour (e.g. rounding with minutes accounted for). Basically, in a normal language it would look something like x+(y>32) mod 12 if the comparison yields 1 or 0 like in TI-Basic. \$\endgroup\$ – Timtech Jan 18 '17 at 23:23
  • 1
    \$\begingroup\$ So @Christoph it seems like you answered your own question with that link, do you still want me to explain? If you want to see where I did the switch from ASCII scoring to tokenized, check revision #4. \$\endgroup\$ – Timtech Jan 18 '17 at 23:24
11
\$\begingroup\$

JavaScript (ES6), 291 303 295 bytes

Takes input as two integers with currying syntax (h)(m)

h=>m=>console.log(`IT IS HALF TEN
QUARTER TWENTY
FIVE MINUTES TO
PAST TWO THREE
ONE FOUR FIVE
SIX SEVEN EIGHT
NINE TEN ELEVEN
TWELVE O'CLOCK`.replace(/\S+/g,w=>(k/=2)&1?w:w.replace(/./g,' '),k=[x=1<<19,88,81,66,84,92,64.5,60,52,34,49,56,x,h=(m<33?h+11:h)%12][m/5+.4|0]*16|6|2048<<(h?h-(h<3):2)))

How it works

The whole clock can be seen as 23 LEDs that are either ON or OFF. So, the clock state is a 23-bit integer.

Bit | Word        Bit | Word
----+--------     ----+--------
00  | IT          12  | ONE
01  | IS          13  | FOUR
02  | HALF        14  | FIVE
03  | TEN         15  | SIX
04  | QUARTER     16  | SEVEN
05  | TWENTY      17  | EIGHT
06  | FIVE        18  | NINE
07  | MINUTES     19  | TEN
08  | TO          20  | ELEVEN
09  | PAST        21  | TWELVE
10  | TWO         22  | O'CLOCK
11  | THREE             

The minutes logic that we need to implement to enable the right words is not as simple as one might think at first glance. A magic-golfing formula may exist but I went the easy way and decided to just hardcode each possible configuration:

Minutes | Words                    | Enabled bits | Value   | Value / 8
--------+--------------------------+--------------+---------+----------
  00    | O'CLOCK                  | 22           | 4194304 | 524288
  05    | FIVE MINUTES PAST        | 6, 7, 9      | 704     | 88
  10    | TEN MINUTES PAST         | 3, 7, 9      | 648     | 81
  15    | QUARTER PAST             | 4, 9         | 528     | 66
  20    | TWENTY MINUTES PAST      | 5, 7, 9      | 672     | 84
  25    | TWENTY FIVE MINUTES PAST | 5, 6, 7, 9   | 736     | 92
  30    | HALF PAST                | 2, 9         | 516     | 64.5
  35    | TWENTY FIVE MINUTES TO   | 5, 6, 7, 8   | 480     | 60
  40    | TWENTY MINUTES TO        | 5, 7, 8      | 416     | 52
  45    | QUARTER TO               | 4, 8         | 272     | 34
  50    | TEN MINUTES TO           | 3, 7, 8      | 392     | 49
  55    | FIVE MINUTES TO          | 6, 7, 8      | 448     | 56

Test cases

let f =

h=>m=>console.log(`IT IS HALF TEN
QUARTER TWENTY
FIVE MINUTES TO
PAST TWO THREE
ONE FOUR FIVE
SIX SEVEN EIGHT
NINE TEN ELEVEN
TWELVE O'CLOCK`.replace(/\S+/g,w=>(k/=2)&1?w:w.replace(/./g,' '),k=[x=1<<19,88,81,66,84,92,64.5,60,52,34,49,56,x,h=(m<33?h+11:h)%12][m/5+.4|0]*16|6|2048<<(h?h-(h<3):2)))
;

[[13,15],[13,58],[14,30],[15,35],[10,0],[12,0]].map(([h, m]) => {
  console.log('h = ' + h, 'm = ' + m);
  f(h)(m);
});

\$\endgroup\$
  • 2
    \$\begingroup\$ Very clever. I was trying to cut some more byte from mine, then I saw this and there's no hope to compete. \$\endgroup\$ – edc65 Jan 18 '17 at 16:02
  • \$\begingroup\$ The task (rule 8) says that it must be printed, not just returned \$\endgroup\$ – smls Jan 18 '17 at 16:02
  • \$\begingroup\$ @smls Oh, you're right. That's fixed. \$\endgroup\$ – Arnauld Jan 18 '17 at 16:06
  • \$\begingroup\$ Very cool. Except the time is wrong :-( Display: h = 13 m =15 Actual time: 14:43 \$\endgroup\$ – Strawberry Jan 19 '17 at 14:41
  • \$\begingroup\$ @Strawberry Please see rule #6. This implementation is using input exclusively, not the local time. \$\endgroup\$ – Arnauld Jan 19 '17 at 14:43
6
\$\begingroup\$

Batch, 789 bytes

@echo off
if not "%1"=="" setlocal&set time=%1
set/a"h=%time:~0,2%,m=6%time:~3,2%%%60+2,h+=m/35,h%%=12,m=6-m/5%%12,n=m%%3,o=m%%2
set p=
set s=
call:c %m:-=% "IT IS HALF" 0 "IT IS      TEN" 4 "IT IS"
call:c %m:-=% QUARTER 3 "        TWENTY" 2 "        TWENTY" 1
if %m% lss 0 set s= TO
call:c 0 "            " %n% "     MINUTES" %o% "FIVE MINUTES"
set s=
set p=PAST 
if %m%==6 set p=     
if %m% lss 0 set p=     
call:c %h% TWO 2 "    THREE" 3
set p=
call:c %h% ONE 1 "    FOUR" 4 "          FIVE" 5
call:c %h% SIX 6 "    SEVEN" 7 "          EIGHT" 8
call:c %h% NINE 9 "     TEN" 10 "         ELEVEN" 11
if %m%==6 set s= O'CLOCK
call:c %h% TWELVE 0 "      "
exit/b
:c
set t=%1
:l
if %t%==%3 echo(%p%%~2%s%&exit/b
shift
shift
if not "%3"=="" goto l
echo(%p%%~2%s%

Note: Trailing space after PAST and 5 trailing spaces on each of the following two lines.

\$\endgroup\$
  • \$\begingroup\$ I ran it and it does just fine (bar one missing space for the hour 3)! I just don't understand what's going on (with call:c for instance)! I should probably learn some batch :) \$\endgroup\$ – Olivier Grégoire Jan 18 '17 at 13:37
  • \$\begingroup\$ @OlivierGrégoire Sadly a space had gone missing but that's fixed now. \$\endgroup\$ – Neil Jan 18 '17 at 14:16
4
\$\begingroup\$

JavaScript, 567 564 551 542 529 527 519 bytes

f=(h,m)=>{c={m6:"HALF ",m2:"TEN\n",m3:"QUARTER ",m4:"TWENTY\n",m1:"FIVE ",m:"MINUTES ",t:"TO\n",p:"PAST ",h2:"TWO ",h3:"THREE\n",h1:"ONE ",h4:"FOUR ",h5:"FIVE\n",h6:"SIX ",h7:"SEVEN ",h8:"EIGHT\n",h9:"NINE ",h10:"TEN ",h11:"ELEVEN\n",h0:"TWELVE ",m0:"O'CLOCK"};l=[];p="push";m=Math.round(m/5);if(m>11){m=0;h++}if(m>6){l[p]("t");m=12-m;h++}else if(m)l[p]("p");if(m%3)l[p]("m");if(m==5)l[p]("m4","m1");else l[p]("m"+m);l[p]("h"+h%12);s="IT IS ";for(k in c)s+=(l.indexOf(k)>=0)?c[k]:c[k].replace(/\S/g," ");console.log(s)}

f(19, 20);
f(13, 15);
f(13, 58);
f(14, 30);
f(15, 35);
f(10, 0);
f(12, 0);

I don't know if it's OK to take hours and minutes as arguments. You said "list of integers". Does it still count?

It's my first time golfing, by the way. What do you think?


Edit: Saved a few bytes by dividing minutes. Thanks, Olivier!

\$\endgroup\$
  • \$\begingroup\$ Yes, the idea behind that rule is that you can take arguments, but only if they relate to the input, which is the time to print. \$\endgroup\$ – Olivier Grégoire Jan 18 '17 at 13:16
  • 1
    \$\begingroup\$ Regarding the golfing, you can probably golf some bytes if you consider dividing your minutes by 5. Also, you might want to move c inside your function. You shouldn't lose any byte by doing so, I guess, but this makes it more like a snippet than a function (to me, at least, maybe JS gurus will say otherwise). \$\endgroup\$ – Olivier Grégoire Jan 18 '17 at 13:21
4
\$\begingroup\$

JavaScript (ES6) 360

A function with input parameters hour (0..23) and minute (0..59).
Using alert for output, as it's the standard output function in javascript even if it's inconvenient. (And it's short)

(k,n,m=(n+2)/5|0,h=(k+(m>6))%12,i=0)=>alert(`IT IS HALF TEN
QUARTER TWENTY
FIVE MINUTES TO
PAST TWO THREE
ONE FOUR FIVE
SIX SEVEN EIGHT
NINE TEN ELEVEN
TWELVE O'CLOCK`.replace(/\S+/g,w=>[,,m-6,m-2&&m-10,m-3&&m-9,m-4&&m-8&&m-5&&m-7,m-1&&m-11&&m-5&&m-7,!(m%3),m<7|m==12,!m|m>6,h-2,h-3,h-1,h-4,h-5,h-6,h-7,h-8,h-9,h-10,h-11,h%12,m%12][i++]?w.replace(/./g,' '):w))

Test Note: for your peace of mind, in the test snippet the alert output is redirected to the page text

F=
(k,n,m=(n+2)/5|0,h=(k+(m>6))%12,i=0)=>alert(`IT IS HALF TEN
QUARTER TWENTY
FIVE MINUTES TO
PAST TWO THREE
ONE FOUR FIVE
SIX SEVEN EIGHT
NINE TEN ELEVEN
TWELVE O'CLOCK`.replace(/\S+/g,w=>[,,m-6,m-2&&m-10,m-3&&m-9,m-4&&m-8&&m-5&&m-7,m-1&&m-11&&m-5&&m-7,!(m%3),m<7|m==12,!m|m>6,h-2,h-3,h-1,h-4,h-5,h-6,h-7,h-8,h-9,h-10,h-11,h%12,m%12][i++]?w.replace(/./g,' '):w))

function alert(x) { O.textContent=x }
function update() { F(+H.value,+M.value) }

update()
input { width:3em }
Hours<input id=H type=number min=0 max=23 value=17 oninput='update()'>
Minutes<input id=M type=number min=0 max=59 value=37 oninput='update()'>
<pre id=O></pre>

\$\endgroup\$
  • \$\begingroup\$ I love your answer! I learned a bunch of stuff from it! However, what's going on with the arrow function that has square brackets? Also, what is the role of i? I can see you get all non-whitespace groups (the "LEDs") and you replace them with whitespace based on the conditions you wrote for each one of them. For example, h-2 it's false only when h == 2, so I presume you invert it somewhere? Can you explain a bit how this works? Perhaps as an edit to your answer? I'd be really thankful! \$\endgroup\$ – Hristiyan Dodov Jan 18 '17 at 21:40
  • \$\begingroup\$ Update - I almost realized what you're doing. You have an array of zero and non-zero elements and you use i to refer to the right one by incrementing it after each regex match. If it's truthy, you replace the matched string with blank spaces, else you leave it as it is. I don't understand one thing, though. replace() uses the return value of the specified function (arrow function in this case). Where do you return a value? I just see a ternary operator. \$\endgroup\$ – Hristiyan Dodov Jan 18 '17 at 22:23
  • 3
    \$\begingroup\$ @HristiyanDodov an arrow function made of just an expression just returns the value of that expression. Example (a,b)=>{ return a+b } is the same as (a,b)=>a+b \$\endgroup\$ – edc65 Jan 18 '17 at 23:28
4
\$\begingroup\$

Python 2, 466,460,449,452,459 449 bytes

As it's allowed to be a function accepting h and m as integers we can save a few bytes. Try it online.

def t(h,m):


m=(2+m)//5
 h=h%12
 n=0
 if m>6:n,m=1,12-m;h+=1
 a="""IT IS _HALF _TEN_
 _QUARTER _TWENTY_
 _FIVE _MINUTES _TO_
 _PAST _TWO _THREE_
 _ONE _FOUR _FIVE_
 _SIX _SEVEN _EIGHT_
 _NINE _TEN _ELEVEN_
 _TWELVE _O'CLOCK""".split("_")
 b=[1,m==6,m==2,1,m==3,3<m<6,1,m in[1,5],m in[1,2,4],n*m,1,(1-n)*m,h==2,h==3,1,h==1,h==4,h==5,1,h==6,h==7,h==8,1,h==9,h==10,h==11,1,h==0,m==0]
 for i,c in enumerate(a):
  if b[i]:print c,
  else:print' '*len(c),

I had a couple of bugs (now fixed) with the logic for TO/PAST vs O'CLOCK. Also saved a few bytes for enumerate, changing the import, and 19<m<26 instead of m in [20,25]. Saved another 8 for working in 5-minute chunks rater than minutes. Rod pointed out some more bugs costing me quite a bit, but I recovered a little with more efficient assignments and a bugfix that worked in my favour.

\$\endgroup\$
  • \$\begingroup\$ Takes a trick from @Titus' PHP answer. I'm losing out to python's == as comparison and I reckon I can improve some of the h tests \$\endgroup\$ – Chris H Jan 18 '17 at 15:57
  • \$\begingroup\$ you can just print c on the last line, c already holds a[i] due enumerate \$\endgroup\$ – Rod Jan 18 '17 at 17:50
  • 1
    \$\begingroup\$ The output format is broken, print add a newline after each print, you can suppress it adding a , after c. Also it should print blank spaces when a word isn't printed, you can fix with an else in the last if else:print' '*len(c), \$\endgroup\$ – Rod Jan 18 '17 at 18:10
  • 1
    \$\begingroup\$ The order of bytes is better if descending. \$\endgroup\$ – Gurupad Mamadapur Jan 18 '17 at 18:42
  • \$\begingroup\$ @Rod, thanks for the bug-spots, even though it makes it much longer \$\endgroup\$ – Chris H Jan 18 '17 at 19:36
2
\$\begingroup\$

Perl 6, 308 296 293 bytes

->\h,\m{my \n=round(m/5)%12;say "IT IS HALF TEN
QUARTER TWENTY
FIVE MINUTES TO
PAST TWO THREE
ONE FOUR FIVE
SIX SEVEN EIGHT
NINE TEN ELEVEN
TWELVE O'CLOCK".subst: /\S+/,{++$==1|2|(0,7,4,5,6,(6|7),3)[min n,12-n]|8*?(n%3)|(23,10,9)[(n+5)/6]|(13,11,12,|(14..*))[(h+m/33-1)%12]??$_!!" "x.comb},:g}

Try it online!

Explanation

The basic structure is as follows:

-> \h, \m {                             # A lambda taking two args (hour and minute).
    my \n = round(m / 5) % 12;          # Index from 0 to 11, representing the minutes.
    say "...".subst: /\S+/, {           # Print the template with each word replaced:
        ++$ == ...|...|...|...          # If counter equals one of expected indices,
            ?? $_                       # then replace the word with itself,
            !! " " x .comb              # else replace it with spaces.
    }, :g                               # (Use global matching.)
}

The expression elided as ...|...|...|... above, is a Junction of integers representing 1-based word indices, and is made up as follows:

  1|2                                   # IT IS
| (0,7,4,5,6,(6|7),3)[min n,12-n]       # FIVE / TEN / QUARTER / TWENTY / TWENTY FIVE / HALF
| 8*?(n%3)                              # MINUTES
| (23,10,9)[(n+5)/6]                    # O'CLOCK / PAST / TO
| (13,11,12,|(14..*))[(h+m/33-1)%12]    # ONE / TWO / THREE / FOUR / FIVE / SIX / SEVEN / ...
\$\endgroup\$
2
\$\begingroup\$

Python3 , (569 bytes)

This answer requires time in format hh mm (space separated integers) .I managed to have '\n' printed, which is inspired by Chris's method.Thanks, Chris! Any help reducing code is appreciated.

H,M=input().split()
w="""HALF _TEN_
_QUARTER _TWENTY_
_FIVE _MINUTES _TO_
_PAST _TWO _THREE_
_ONE _FOUR _FIVE_
_SIX _SEVEN _EIGHT_
_NINE _TEN _ELEVEN_
_TWELVE _O'CLOCK""".split("_")
h,m=int(H),int(M)
if h>12:h-=12
m=(m//5+1)*5 if m%5>2.5 else m//5*5
if m>30:
    m=60-m
    h=(h+1)%12
X=[m==30,m==10,1,m==15,m in[20,25],1,m in[5,25],m not in[0,15,30],int(M)>30 and m!=0,1,m!=0 and int(M)<31,h==2,h==3,1,h==1,h==4,h==5,1,h==6,h==7,h==8,1,h==9,h==10,h==11,1,h in[0,12],m==0]
t="IT IS "
for i in range(0,28):
    if(X[i]):t+=w[i]
    else:t+=" "*len(w[i])
print(t.strip())

Try It Online

\$\endgroup\$
  • \$\begingroup\$ Can you combine w into a single string and then use .split(',')? Should save a few. \$\endgroup\$ – ElPedro Jan 21 '17 at 15:45
  • \$\begingroup\$ Also take your input as H,M=input() where the input is H,M. Two integer sequence is allowed under the rules, Not sure if this works as intended under Python 3. I'm still a 2 guy :-) \$\endgroup\$ – ElPedro Jan 21 '17 at 15:49
  • \$\begingroup\$ Thanks @ElPedro .Saved 57 bytes. H,M=input() didn't work as you doubted. \$\endgroup\$ – EffyCoder Jan 21 '17 at 18:03
1
\$\begingroup\$

Python 2, 443 440 bytes

R=range
w="HALF TEN QUARTER TWENTY FIVE MINUTES TO PAST TWO THREE ONE FOUR FIVE SIX SEVEN EIGHT NINE TEN ELEVEN TWELVE O'CLOCK".split(' ')
h=[10,8,9]+R(11,20)
c=['IT','IS']+[' '*len(x)for x in w]
i,j=input()
i=(i,i+1)[j>30]%13-1
j=int(round(j/5.0)*5.0)%60
for z in[[20],[4,5,7],[1,5,7],[2,7],[3,5,7],[3,4,5,7],[0,7],R(3,7),[3,5,6],[2,6],[1,5,6],R(4,7)][j/5]:c[z]=w[z]
c[h[i]]=w[h[i]]
x=0
for y in[4]+R(6,22,3)+[23]:print' '.join(c[x:y]);x=y

Try it online!

It could probably still benefit from some more golfing. Input is a list of integers e.g. 7,23 = 7:23

\$\endgroup\$
1
\$\begingroup\$

SimpleTemplate, 737 708 bytes

Yeah, verbosity and lack of "real" math hurt the bytecount badly.

{@seth argv.0}{@php$DATA[m]=ceil($DATA[argv][1]/5)*5%60|0}{@ifm}{@ifm is30}{@setA"HALF"}{@/}{@if"@[15]0$@"is matchesm}{@setB"TEN"}{@/}{@if"@[14]5$@"is matchesm}{@setC"QUARTER"}{@/}{@if"@[24]0$@"is matchesm}{@setD"TWENTY"}{@/}{@if"@^[25]?5$@"is matchesm}{@setE"FIVE"}{@/}{@if"@^([235]?5|[1245]0)$@" is matchesm}{@setF"MINUTES"}{@/}{@ifm is greater30}{@setG"TO"}{@else}{@setH"PAST"}{@/}{@else}{@setU"O\'CLOCK"}{@/}{@setZ"","ONE","TWO","THREE","FOUR","FIVE","SIX","SEVEN","EIGHT","NINE","TEN","ELEVEN","TWELVE"}{@setY"J"}{@incbyh Y}{@php$DATA[$DATA[Y]]=$DATA[Z][$DATA[h]]}{@print"IT IS%-6s%s\n%8s%s\n%-5s%-7s %s\n%4s %3s %s\n%3s %4s %s\n%3s %5s %s\n%4s %3s %s\n%6s %s",A,B,C,D,E,F,G,H,J,K,I,L,M,N,O,P,Q,R,S,T,U}

This expects the hour and minutes as the 1st and 2nd parameter on the class.


Ungolfed:

{@set hour argv.0}

{@//The bitwise is required for the `@if minutes is 30`}
{@//Otherwise, I would be forced to write `@if minutes is equal to 30`}
{@php $DATA['minutes'] = ((ceil($DATA['argv'][1] / 5) * 5) % 60) | 0}

{@if minutes}
    {@if minutes is 30}
        {@set A "HALF"}
    {@/}
    {@if "@[15]0$@" is matches minutes}
        {@set B "TEN"}
    {@/}
    {@if "@[14]5$@" is matches minutes}
        {@set C "QUARTER"}
    {@/}
    {@if "@[24]0$@" is matches minutes}
        {@set D "TWENTY"}
    {@/}
    {@if "@^[25]?5$@" is matches minutes}
        {@set E "FIVE"}
    {@/}
    {@if "@^([235]?5|[1245]0)$@" is matches minutes}
        {@set F "MINUTES"}
    {@/}
    {@if m is greater than 30}
        {@set G "TO"}
    {@else}
        {@set H "PAST"}
    {@/}
{@else}
    {@set U "O\'CLOCK"}
{@/}


{@set numbers "", "ONE", "TWO", "THREE", "FOUR", "FIVE", "SIX", "SEVEN", "EIGHT", "NINE", "TEN", "ELEVEN", "TWELVE"}
{@set key "J"}
{@inc by hour key}
{@php $DATA[$DATA['key']] = $DATA['numbers'][$DATA['hour']]}

{@print "IT IS%-6s%s\n%8s%s\n%-5s%-7s %s\n%4s %3s %s\n%3s %4s %s\n%3s %5s %s\n%4s %3s %s\n%6s %s", A, B, C, D, E, F, G, H, J, K, I, L, M, N, O, P, Q, R, S, T, U}

How to run:

  1. Get the code from https://github.com/ismael-miguel/SimpleTemplate
  2. Run the following code:

    <?php
        include 'SimpleTemplate.php';
    
        $template = new SimpleTemplate('<code>');
    
        $template->render($hour, $minutes);
    
        //system-time: $template->render(date('g'), date('i'));
    
  3. Done!

\$\endgroup\$
1
\$\begingroup\$

Java (OpenJDK 9), 437 bytes

(h,m)->{h=(h+m/35+11)%12+1;Object[]s="HALF TEN QUARTER TWENTY FIVE MINUTES TO PAST TWO THREE ONE FOUR FIVE SIX SEVEN EIGHT NINE TEN ELEVEN TWELVE O'CLOCK".split(" ");for(int i=s.length,M[]={1<<20,176,162,132,168,184,129,120,104,68,98,112};i-->0;)s[i]=(7<i&i<20?h==i-(h>3?7:h>1?6:9):(M[(m+2)/5%12]&(1<<i))>0)?s[i]:"";System.out.printf("IT IS %4s %3s%n%7s %6s%n%4s %7s %2s%n%4s %3s %5s%n%3s %4s %4s%n%3s %5s %5s%n%4s %3s %6s%n%6s %7s",s);}

Try it online!

I thought I'd finally give a shot at my challenge ;)

\$\endgroup\$
1
\$\begingroup\$

Perl 5, 487 449 bytes

($a,$_,$h)=localtime;s/[3-7]$/5/;s/[12]$/0/;$m=s/(.?)[89]$/($1+1)*10/er;$_="IT IS half ten
quarter tw
five minutes to
past 2two 3three
1one 4four 5five
6six 7seven 8eight
9nine 10ten 11eleven
12twelve oc";if($m>30){s/to/TO/;$h++;$m=60-$m}elsif($m){s/past/PAST/}$h=$h%12||12;$m!=30?$m%15?s/m\w+/uc$&/e:$m?s/q\w+/uc$&/e:s/oc/O'CLOCK/:s/half/HALF/;$m%10&&!/Q/&&s/five/FIVE/;$m>15&&$m<30?s/tw/TWENTY/:$m==10&&s/ten/TEN/;s/\b$h\w+/uc$&/es;y/a-z0-9/ /;say

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.