24
\$\begingroup\$

How long's left?

Recently, I was making pizza using a 5-minute timer on my phone. When someone walked in and asked me how long was left, I was confused for a moment at first as to how to answer the question. You see, if the timer at the current moment was at 3:47, by the time I had read out 'Three minutes and forty seven seconds' aloud, the time would have changed. Therefore, I need to find a time that the timer would reach just as I finish reading it out.

This is your challenge: to automate this process. Given a time in any appropriate format (":" delimited, or as a minute and second argument), output the earliest time from that current moment which would take an equal amount of time to read out as it would take for the timer to get to. We're assuming that each syllable takes 1 second to read out.

Further rules

  • You must count 'minutes' and 'seconds' as two of the syllables each, as well as an 'and' between them.
  • The pizza will never take more than 59:59 to cook.
  • '11 minutes and 0 seconds' is not 10 syllables: you must simplify to '11 minutes' (i.e 5 syllables). Same goes with minutes: '0 minutes and 7 seconds' is also only counted as 4 syllables.
  • Your program can give the output in any format: an array of [minutes, seconds], or even as <minutes> minutes and <seconds> seconds (normal text written out).
  • Standard loopholes apply.
  • This is , so shortest answer in bytes wins.

Test cases

All inputs as (minutes, seconds)

(4, 47) = (4, 38) (Four MiNutes And ThirTy Eight SeConds - 9 syllables/seconds)
(1, 1) = (0, 56) (FifTy-Six SeConds - 5 syllables/seconds)
(59, 57) = (59, 46) (FifTy Nine Minutes And Forty Six SeConds - 11 syllables/seconds)
(0, 10) = null/error/0 (no positive answer)

Syllable count reference

For reference, here are the number of syllables in each number up to 59.

0,0 (does not need to be counted)
1,1
2,1
3,1
4,1
5,1
6,1
7,2
8,1
9,1
10,1
11,3
12,1
13,2
14,2
15,2
16,2
17,3
18,2
19,2
20,2
21,3
22,3
23,3
24,3
25,3
26,3
27,4
28,3
29,3
30,2
31,3
32,3
33,3
34,3
35,3
36,3
37,4
38,3
39,3
40,2
41,3
42,3
43,3
44,3
45,3
46,3
47,4
48,3
49,3
50,2
51,3
52,3
53,3
54,3
55,3
56,3
57,4
58,3
59,3
\$\endgroup\$
10
  • \$\begingroup\$ For your first test case, would 4:37 also be a valid output, since that would take 10 syllable's to say? \$\endgroup\$
    – Quinn
    Commented Jul 12, 2019 at 19:48
  • 1
    \$\begingroup\$ @Quinn, the spec states that we should output the earliest time. \$\endgroup\$
    – Shaggy
    Commented Jul 12, 2019 at 19:58
  • 1
    \$\begingroup\$ @Shaggy whoops, so it does thanks - by the time I sort my answer out I think my pizza will be burnt \$\endgroup\$
    – Quinn
    Commented Jul 12, 2019 at 20:00
  • \$\begingroup\$ Are we allowed to assume the input can be padded, i.e. 4 minutes and 43 seconds could be inputted as "04:43"? \$\endgroup\$
    – Vedvart1
    Commented Jul 12, 2019 at 20:16
  • 1
    \$\begingroup\$ @Vedvart1 OK, that's fine \$\endgroup\$ Commented Jul 12, 2019 at 20:36

5 Answers 5

4
\$\begingroup\$

JavaScript (ES6),  112 106  105 bytes

A shorter version based on a suggestion by @EmbodimentofIgnorance
6 more bytes saved by @DaniilTutubalin

Takes input as (minutes)(seconds). Returns [minutes, seconds] or \$0\$ if there's no solution.

m=>d=F=s=>m|s?(g=n=>n&&(n%10!=7)-7+(n-11?n<13?2:n<21|n%10<1:0))(m)+g(s)^~d?F(s?s-1:m--&&59,d=-~d):[m,s]:0

Try it online!


JavaScript (ES6),  126  119 bytes

Takes input as (minutes)(seconds). Returns [minutes, seconds] or \$0\$ if there's no solution.

m=>d=F=s=>m|s?(g=n=>n&&2+(30774612>>2*n%(n>12?20:26)&3)+(n>12)+(n>19))(m)+g(s)+!!(m*s)^d?F(s?s-1:m--&&59,d=-~d):[m,s]:0

Try it online!

Commented

m =>                  // m = minutes
d =                   // d = delta in seconds between the initial time and the current time,
                      //     initialized to a non-numeric value (zero-ish)
F = s =>              // F is a recursive function taking s = seconds
  m | s ? (           // if either m or s is not 0:
    g = n =>          //   g is a helper function taking an integer n in [0..59]
      n &&            //     return 0 if n = 0
      2 + (           //     otherwise, start with 2 for either 'mi-nutes' or 'se-conds'
        30774612 >>   //     add the base number of syllables (0 to 3) corresponding to n
        2 * n %       //     using a bitmask of 13 entries x 2-bit:
                      //       12 11 10  9  8  7  6  5  4  3  2  1  0
                      //       01 11 01 01 01 10 01 01 01 01 01 01 00
        (n > 12 ? 20  //     using n MOD 10 if n is greater than 12
                : 26) //     or just n otherwise
        & 3           //     isolate the two least significant bits
      ) +             //   
      (n > 12) +      //     add 1 syllable for '-teen' or '-ty' if n is greater than 12
      (n > 19)        //     add 1 more syllable for 'x-ty' if n is greater than 19
  )(m) +              //   invoke g for the minutes
  g(s) +              //   invoke g for the seconds
  !!(m * s)           //   add 1 syllable for 'and' if both m and s are non-zero
  ^ d ?               //   if the result is not equal to the delta:
    F(                //     otherwise, do a recursive call:
      s ? s - 1       //       decrement s if it's not 0,
        : m-- && 59,  //       or decrement m and restart with s = 59
      d = -~d         //       increment the delta
    )                 //     end of recursive call
  :                   //   else:
    [m, s]            //     success: return [m, s]
:                     // else:
  0                   //   failure: return 0
\$\endgroup\$
11
  • \$\begingroup\$ Could you please add an explanation? \$\endgroup\$ Commented Jul 13, 2019 at 9:12
  • \$\begingroup\$ @GezaKerecsenyi Done. :-) \$\endgroup\$
    – Arnauld
    Commented Jul 13, 2019 at 9:44
  • \$\begingroup\$ Thanks. It was mostly the 30774612>>2*n%(n>12?20:26)&3 part I was confused about. \$\endgroup\$ Commented Jul 13, 2019 at 11:34
  • 1
    \$\begingroup\$ g=x=>x&&(x%10==7)+(x==11?6:x<13?4:x<21|x%10<1?5:6) might work (untested since Internet is down and using my phone) \$\endgroup\$
    – Gymhgy
    Commented Jul 13, 2019 at 14:20
  • 1
    \$\begingroup\$ @DaniilTutubalin Cool. I saved another byte from there by having g() returning the opposite result and XOR'ing with ~d. \$\endgroup\$
    – Arnauld
    Commented Jul 13, 2019 at 23:03
2
\$\begingroup\$

Python 3, 287 285 bytes

m=int(input())
s=int(input())
y=lambda w:3+(w[-1]=='7')-(w[-1]=='0')-(w[0]in'01')*(1+(w[0]=='0'))+(w=='11')-(w=='12')
z=lambda m,s:(2+y(f'{m:02d}'))*(m!=0)+(2+y(f'{s:02d}'))*(s!=0)+(m!=0!=s)
q=lambda t: (m-(t+60-s-1)//60,(s-t)%60)
print([q(t) for t in range(s+60*m) if z(*q(t))==t][0])

Try it online!

It's not a very clever solution - it's mostly striaghtforward. Takes 'm:s' m and s as separate inputs (doesn't need to be padded), and outputs (m,s). Throws an error if there's no valid output.

The program relies heavily on implicitly casting booleans to 0 and 1. The first line takes input. The second line defines a lambda function y which gives the syllables in a number - it assumes a base of 3 syllables, then adds 1 if it ends in 7, subtracts 1 if it ends in 0, and subtracts 1 if it's in the 10's and 2 if it's in the single digits. Twelve and eleven are manually adjusted at the end. The third line is a lambda for the syllables in the whole expression. Finally, fourth line gives the time after t seconds. Fifth line is the output - it builds an array of all the times that satisfy the problem, and outputs the first one.

EDIT 1: Thanks to Matthew Anderson in the comments, 2 bytes were shaved off by taking the inputs separately.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ If you take input on two separate lines: m=int(input()) s=int(input()), you can save 2 bytes. \$\endgroup\$ Commented Jul 16, 2019 at 17:59
1
\$\begingroup\$

C# (Visual C# Interactive Compiler), 141 bytes

a=>b=>((a=Enumerable.Range(1,b+=a*60).Last(i=>new[]{i/60,i%60}.Sum(x=>x<1?0:(x%10==7?4:3)+(x==11?3:x<13?1:x<21|x%10<1?2:3))-1==b-i))/60,a%60)

Try it online!

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

Jelly, 46 bytes

ḅḶbɗ60Ṛµ“÷ṢḣxE⁻Ṇ⁹ƬƝwɼỤṡl’ḃ4+2;0⁸ịS+ṬS$’)=JTị⁸Ḣ

Try it online!

A monadic link taking as its argument the time as [minutes, seconds] and returning the appropriate time to say as [minutes, seconds] or [seconds] if less than a minute.

\$\endgroup\$
0
\$\begingroup\$

CJam, 102 bytes

60:X;q~\X*+:W_{;(__X%\X/{_196656821516111872\_A%K+e<_{(2*m>3&3.5+}{\;}?@}2*+i+\X*+_W=!2$0<-}g;_X%\X/S@

Try it online!

Just a boring old magic-number binary look-up-table, nothing to see here.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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