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 2019-07-12T17:46:50.233

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 – 2019-07-12T19:48:43.760

1@Quinn, the spec states that we should output the earliest time. – Shaggy – 2019-07-12T19:58:45.027

1@Shaggy whoops, so it does thanks - by the time I sort my answer out I think my pizza will be burnt – Quinn – 2019-07-12T20:00:39.583

Are we allowed to assume the input can be padded, i.e. 4 minutes and 43 seconds could be inputted as "04:43"? – Vedvart1 – 2019-07-12T20:16:35.397

1@Vedvart1 OK, that's fine – Geza Kerecsenyi – 2019-07-12T20:36:58.820

Can I return a Datetime object with the two numbers in the minutes and seconds property? – Embodiment of Ignorance – 2019-07-13T07:56:37.023

@JoKing fixed now. – Geza Kerecsenyi – 2019-07-13T08:15:58.123

@EmbodimentofIgnorance of course - like I said, you can output in any (appropriate) format. – Geza Kerecsenyi – 2019-07-13T08:16:50.590

Is 0:00 a valid input? – Daniil Tutubalin – 2019-07-13T18:28:55.870

@DaniilTutubalin Yes, but there are no possible outputs. – Geza Kerecsenyi – 2019-07-13T18:44:18.337

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 2019-07-12T17:46:50.233

Reputation: 111 334

Could you please add an explanation? – Geza Kerecsenyi – 2019-07-13T09:12:04.517

@GezaKerecsenyi Done. :-) – Arnauld – 2019-07-13T09:44:56.260

Thanks. It was mostly the 30774612>>2*n%(n>12?20:26)&3 part I was confused about. – Geza Kerecsenyi – 2019-07-13T11:34:05.283

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 – 2019-07-13T14:20:53.753

@EmbodimentofIgnorance Thanks. It was off by 1, but nicely done without testing anyway. ;) – Arnauld – 2019-07-13T14:48:36.940

Bad news: for f(0)(0) it outputs [0, 0]. It should output 0. – Daniil Tutubalin – 2019-07-13T18:54:06.793

@DaniilTutubalin Thanks for reporting this. Fixed. – Arnauld – 2019-07-13T22:06:44.377

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 – 2019-07-13T22:33:44.730

1@DaniilTutubalin Cool. I saved another byte from there by having g() returning the opposite result and XOR'ing with ~d. – Arnauld – 2019-07-13T23:03:30.203

Nice trick! I felt that this -1 may be shaved, but didn't know how. – Daniil Tutubalin – 2019-07-13T23:18:02.267

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 – 2019-07-13T23:35:30.993

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 2019-07-12T17:46:50.233

Reputation: 179

1If you take input on two separate lines: m=int(input()) s=int(input()), you can save 2 bytes. – Matthew Anderson – 2019-07-16T17:59:49.250

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 2019-07-12T17:46:50.233

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 2019-07-12T17:46:50.233

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 2019-07-12T17:46:50.233

Reputation: 2 600