How long's left?

21

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

Geza Kerecsenyi

Posted 6 years ago

Reputation: 1 892

For your first test case, would 4:37 also be a valid output, since that would take 10 syllable's to say? – Quinn – 6 years ago

1@Quinn, the spec states that we should output the earliest time. – Shaggy – 6 years ago

1@Shaggy whoops, so it does thanks - by the time I sort my answer out I think my pizza will be burnt – Quinn – 6 years ago

Are we allowed to assume the input can be padded, i.e. 4 minutes and 43 seconds could be inputted as "04:43"? – Vedvart1 – 6 years ago

1@Vedvart1 OK, that's fine – Geza Kerecsenyi – 6 years ago

Can I return a Datetime object with the two numbers in the minutes and seconds property? – Embodiment of Ignorance – 6 years ago

@JoKing fixed now. – Geza Kerecsenyi – 6 years ago

@EmbodimentofIgnorance of course - like I said, you can output in any (appropriate) format. – Geza Kerecsenyi – 6 years ago

Is 0:00 a valid input? – Daniil Tutubalin – 6 years ago

@DaniilTutubalin Yes, but there are no possible outputs. – Geza Kerecsenyi – 6 years ago

Answers

4

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

Arnauld

Posted 6 years ago

Reputation: 111 334

Could you please add an explanation? – Geza Kerecsenyi – 6 years ago

@GezaKerecsenyi Done. :-) – Arnauld – 6 years ago

Thanks. It was mostly the 30774612>>2*n%(n>12?20:26)&3 part I was confused about. – Geza Kerecsenyi – 6 years ago

1g=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) – Embodiment of Ignorance – 6 years ago

@EmbodimentofIgnorance Thanks. It was off by 1, but nicely done without testing anyway. ;) – Arnauld – 6 years ago

Bad news: for f(0)(0) it outputs [0, 0]. It should output 0. – Daniil Tutubalin – 6 years ago

@DaniilTutubalin Thanks for reporting this. Fixed. – Arnauld – 6 years ago

Now I can safely propose improvement to 106 bytes: m=>d=F=s=>m|s?(g=n=>n&&(n%10==7)+6-(n-11?n<13?2:n<21|n%10<1:0))(m)+g(s)-1^d?F(s?s-1:m--&&59,d=-~d):[m,s]:0

I removed +!!(m*s). Instead I replaced 5 with 6 inside g() lambda. So we kinda count and both for minutes and seconds. If one of them is zero, then g(0) is zero as well, so and is not counted. Otherwise it is counted. But we get one extra and in this case, so I added -1 in the end of expression. – Daniil Tutubalin – 6 years ago

1@DaniilTutubalin Cool. I saved another byte from there by having g() returning the opposite result and XOR'ing with ~d. – Arnauld – 6 years ago

Nice trick! I felt that this -1 may be shaved, but didn't know how. – Daniil Tutubalin – 6 years ago

If somehow you make d=1 in the beginning instead of zero-ish, you may remove ~ and replace d=-~d with d++. But I am not sure how to do it without extra brackets. (d=-1 should also work). – Daniil Tutubalin – 6 years ago

2

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.

Vedvart1

Posted 6 years ago

Reputation: 179

1If you take input on two separate lines: m=int(input()) s=int(input()), you can save 2 bytes. – Matthew Anderson – 6 years ago

1

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!

Embodiment of Ignorance

Posted 6 years ago

Reputation: 7 014

1

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.

Nick Kennedy

Posted 6 years ago

Reputation: 11 829

0

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.

JosiahRyanW

Posted 6 years ago

Reputation: 2 600