28
\$\begingroup\$

My Alarm Clock

I'm American, and so is my (digital) alarm clock. To set the alarm, it starts at the time it was previously. Hitting the hour button moves it up one hour, and hitting the minute button moves it up one minute. Hitting both buttons at the same time resets it to midnight (12:00 am), and counts as two button presses.

When the hours exceed their cap (12), it resets to 1 and toggles the AM/PM light. When the minutes exceed their cap (59), they reset to 0, without affecting the hours.

The Task

Your task is, given a starting time and a target time, to output the optimal number of buttons presses needed to set my alarm to the target time.

You may take input in whatever format suits you best. The only data your program should need is hours and minutes, for both inputs. That means that you, for example, may take data as milliseconds since epoch, and extract the hours and minutes, but you may not encode anything into the year, month, second, etc. Note that while you may, for example, input using "military time" (or regular time for most of the world), but that doesn't change how my clock works.

Examples

1:15 pm -> 2:30 am

You could push down both buttons to reset to 12:00 am, then increment to 2:30 am, which would be 2+2+30 = 34 button presses. You could also increment to 2:30 am, which would be 13+15 = 28 button presses. Therefore, your output is 28.

3:58 am -> 4:02 am

You could reset and increment, which would be 2+4+2 = 8 button presses. You could also increment, which would be 1+4 = 5 button presses. Therefore, your output is 5.

10:55 pm -> 1:00 am

You could reset and increment, which would be 2+1 = 3 button presses. You could also increment, which would be 3+5=8 button presses. Therefore, your output is 3.

1:00 am -> 1:59 pm

You could reset and increment, but that would be three more presses than just incrementing. Therefore, your output is 12+59 = 71.

Test Cases

Current  Target   = Output
1:15pm   2:30am   = 28
3:58am   4:02am   = 5
10:55pm  1:00am   = 3
1:00am   1:59pm   = 71
12:00am  12:00am  = 0
6:51pm   12:00am  = 2
2:01pm   11:00pm  = 25
2:01pm   11:01pm  = 9
12:59am  12:01am  = 2
11:50am  12:00pm  = 11
\$\endgroup\$
9
  • \$\begingroup\$ Sandbox \$\endgroup\$
    – Stephen
    Commented Aug 9, 2017 at 15:15
  • 13
    \$\begingroup\$ Holy crap! Pressing the two buttons does reset my (European) alarm clock to 0:00 as well... All these years spent pressing the buttons too many times... O_o \$\endgroup\$
    – Arnauld
    Commented Aug 9, 2017 at 15:29
  • 8
    \$\begingroup\$ "military time (or regular time for most of the world)"...the term you're looking for is "24-hour time". \$\endgroup\$
    – Jakob
    Commented Aug 9, 2017 at 16:08
  • 12
    \$\begingroup\$ @Jakob No, the term he's looking for is "regular time". Americans use irregular time, irregular dates, irregular units, etc. etc. \$\endgroup\$
    – Neil
    Commented Aug 9, 2017 at 20:49
  • 1
    \$\begingroup\$ @StepHen I am in the UK and had no idea what you meant by "military time" until Jakob explained it. 24hr time makes perfect sense to me \$\endgroup\$
    – Darren H
    Commented Aug 10, 2017 at 5:43

10 Answers 10

8
\$\begingroup\$

JavaScript (ES6), 73 56 54 52 50 bytes

Uses 24 hour format. Takes input as 4 integers representing the hours & minutes of each time.

(g,l,h,m)=>Math.min(2+h+m,(h-g+24)%24+(m-l+60)%60)

Try it

Enter the times in 24-hour format, with the : separator.

o.innerText=(f=

(g,l,h,m)=>Math.min(2+h+m,(h-g+24)%24+(m-l+60)%60)

)(+(x=(i.value="01:00").split`:`)[0],+x[1],+(y=(j.value="13:59").split`:`)[0],+y[1]);oninput=_=>o.innerText=f(+(x=i.value.split`:`)[0],+x[1],+(y=j.value.split`:`)[0],+y[1])
label,input{font-family:sans-serif;font-size:14px;height:20px;line-height:20px;vertical-align:middle}input{margin:0 5px 0 0;width:100px;}
<label for=i>Current: </label><input id=i type=time><label for=j>Target: </label><input id=j type=time><pre id=o>


Explanation

(To be updated shortly.)

(g,l,h,m)=>

Anonymous function taking the integers as arguments via parameters g, l, h & m, where g & l are, respectively, the hours & minutes of the current time and h & m are the hours & minutes of the target time.

2+h+m

First, we calculate how many button presses are needed if we just reset the clock, which is simply 2 (for the reset) plus the target hour and the target minute.

h-g+24*(h<g)

Next we calculate how many button presses are needed to reach the target hour. We do this by subtracting the current hour from target hour. However, if the current hour is less than the target, this will give us a negative number so we rectify that by adding 24 multiplied by checking if h<g (which returns a boolean but is implicitly cast to integer 1, if true, or 0 if false by the mathematical operations.

+m-l+60*(m<l)

We use a similar formula to calculate the number of presses to get from the current minute to the target minute and add that to the hour presses.

Math.min()

Finally, we get the minimum of the 2 numbers to give us our result.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Could you do (h-g+24)%24+(m-l+60)%60? \$\endgroup\$
    – Arnauld
    Commented Aug 9, 2017 at 20:13
7
\$\begingroup\$

Pyth, 29 bytes

This challenge obviously doesn't advantage golfing languages, that's why it's so long. On the other hand, this is improved by the fact that Pyth is Python-based, so we can abuse its negative modulus.

hS,+%-eQ@Q1 60%-@Q2hQ24+2s>Q2

Test Suite. Numbers in Pyth do not support leading zeros.

\$\endgroup\$
5
\$\begingroup\$

Husk, 16 bytes

§▼ṁ→(Σz%e24 60z-

Try it online!

Takes arguments as two lists [hours,minutes], for start and end time, in 24h format.

I'm quite happy about how much I was able to golf this one, I find interesting how arguments are managed in this composition of functions.

The function which calculates how many key presses we need if reset is not allowed is the following:

Σz%e24 60z-
         z-    elementwise subtract the two times
 z%e24 60      take the hours difference modulo 24 and the minutes difference modulo 60
Σ              sum the two resulting numbers

The interesting part is that since the rest of this solution can work only with a single list as argument, this one gets partially applied to the first argument of the whole program, "eating" it and leaving only the second argument visible both for itself and the rest of the program.

Next, we compute how many key presses we need if we reset the time to 0:00

ṁ→    take the sum of each element of the list increased by 1

As said before, this operates only on the second argument (the final time), and computes hours+minutes+2, just in a golfier way.

Finally, §▼ is the part that passes the second argument to both functions, and returns the lesser of the two results.

\$\endgroup\$
5
\$\begingroup\$

Jelly, 19 bytes

_⁵%24µ+⁴_⁶%60µ«³+⁴¤

Try it online!

Input as 4 integers (end-hour, end-minute, start-hour, start-minute)

\$\endgroup\$
2
3
\$\begingroup\$

C# (.NET Core), 56 bytes

(H,M,h,m)=>Math.Min(((h+24-H)%24)+((m+60-M)%60),(2+h+m))

Try it online!

Very similar to the Javascript answer. Bools in C# don't convert easily to numbers, so instead of [diff]+24*(H<h) I did ([diff]+24)%24 which effectively does the same thing.

\$\endgroup\$
3
  • \$\begingroup\$ You can remove the parenthesis around 2+h+m for -2 bytes. \$\endgroup\$ Commented Aug 10, 2017 at 7:15
  • \$\begingroup\$ I've created a port of your answer in Java 8, and noticed you can golf an additional four bytes by removing more parenthesis, ending with this (H,M,h,m)=>Math.Min((h+24-H)%24+(m+60-M%60),2+h+m) \$\endgroup\$ Commented Aug 10, 2017 at 7:41
  • 1
    \$\begingroup\$ Wouldn't you have to make it System.Math.Min ? \$\endgroup\$
    – LiefdeWen
    Commented Aug 10, 2017 at 8:46
3
\$\begingroup\$

Haskell, 41 bytes

(a#b)c d=min(a+b+2)$mod(a-c)24+mod(b-d)60

Pretty straightforward. Takes input as four arguments using 24-hour time: end hour, end minute, start hour, start minute.

\$\endgroup\$
2
\$\begingroup\$

Python 3, 43 bytes

lambda a,b,c,d:min((c-a)%24+(d-b)%60,2+c+d)

Try it online!

Input as 4 integers (start-hour, start-minute, end-hour, end-minute)

\$\endgroup\$
8
  • \$\begingroup\$ @StepHen Whoops. Easy fix. \$\endgroup\$
    – hyperneutrino
    Commented Aug 9, 2017 at 15:28
  • \$\begingroup\$ Fails for 2 01 11 00? In your answer, how do you determine if the time is AM or PM, if you don't take that as input? \$\endgroup\$
    – Mr. Xcoder
    Commented Aug 9, 2017 at 15:37
  • \$\begingroup\$ @Mr.Xcoder; I get 13 for that input using the TIO, which is correct (reset+11<9+59). \$\endgroup\$
    – Shaggy
    Commented Aug 9, 2017 at 15:39
  • 2
    \$\begingroup\$ Does % always return a positive number in Python? \$\endgroup\$
    – Shaggy
    Commented Aug 9, 2017 at 16:00
  • 4
    \$\begingroup\$ @Shaggy it always returns the sign of the right side of the %. 1%24 = 1, 1%-24 = -23. It's very helpful for this question. \$\endgroup\$
    – Stephen
    Commented Aug 9, 2017 at 16:02
2
\$\begingroup\$

Java 8, 54 50 bytes

(h,m,H,M)->Math.min((H-h+24)%24+(M-m+60)%60,H+M+2)

Port of @KamilDrakari's C# answer (after I golfed 2 6 bytes).

Explanation:

Try it here.

(h,m,H,M)->       // Method with four integer parameter and integer return-type
  Math.min(       //  Return the lowest of the following two:
                  //   The hours:
   (H-h           //    Second hours - first hours inputs
       +24)       //    +24 so we won't have negative numbers
           %24    //    mod-24 to get the hours
   +              //   And add the minutes:
    (M-m          //    Second minutes - first minutes inputs
         +60)     //    +60 so we won't have negative numbers
             %60  //    mod-60 to get the minutes
    ,H+M          //  And compare it to the second hours + second minutes inputs
        +2)       //   +2 for the added +24 and +60 to get the positive modulo arguments
\$\endgroup\$
1
\$\begingroup\$

Perl 5, 71 +2 (-ap) = 73 bytes

($w,$x,$y,$z)=@F;$_=($r=2+$y+$z)>($c=($y-$w+24)%24+($z-$x+60)%60)?$c:$r

Try it online!

Takes input in 24 hour format (military time), separated by spaces, start time first, end time second: HH MM hh mm

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

Retina, 106 bytes

\d+
$*
 (1*):(1*)
 24$*1$1:60$*1$2#11$1$2
(1*):(1* )\1(1{24})?
$2
(1*) (1*):\1(1{60})?
$2
(1+)#(?!\1)

\G1

Try it online! Link includes test cases. Takes input as current and desired times in regular 24 hour time with a space separating the two times. Explanation:

\d+
$*

Convert to unary.

 (1*):(1*)
 24$*1$1:60$*1$2#11$1$2

This does two things; it adds 24 hours and 60 minutes to the desired hours and minutes, and it also adds 2 to the sum of the original desired hours and minutes, i.e. the the number of button presses to set using a reset.

(1*):(1* )\1(1{24})?
$2

Subtract the current hours from the desired hours, and subtract the 24 we added on if we can.

(1*) (1*):\1(1{60})?
$2

Similarly for the minutes. This also adds the two results together.

(1+)#(?!\1)

If the number of presses to set using the current time is more than the number of presses to set using a reset, delete it.

\G1

Convert the first remaining number back to decimal.

\$\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.