Alarm Optimization

28

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

Stephen

Posted 2017-08-09T15:15:25.497

Reputation: 12 293

Sandbox – Stephen – 2017-08-09T15:15:31.950

13Holy 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 – Arnauld – 2017-08-09T15:29:26.620

@StepHen, I know you're very relaxed on the input format here, but could you throw an eye at my JS solution, let me know if it's OK to take input like that? – Shaggy – 2017-08-09T15:30:28.663

@Arnauld I discovered it by chance as well - since then I've done these mental gymnastics in my head to figure out which was optimal when trying to reset my alarm :P – Stephen – 2017-08-09T15:30:36.163

@Shaggy yup that's fine. Same thing that HyperNeutrino's Python answer is doing – Stephen – 2017-08-09T15:31:10.643

8"military time (or regular time for most of the world)"...the term you're looking for is "24-hour time". – Jakob – 2017-08-09T16:08:55.833

@Jakob I know that's the term, but (unless I'm mistaken) very few people would call it that casually, as if you use it it's just regular time - I may be mistaken though. – Stephen – 2017-08-09T16:10:56.887

12@Jakob No, the term he's looking for is "regular time". Americans use irregular time, irregular dates, irregular units, etc. etc. – Neil – 2017-08-09T20:49:58.760

1@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 – Darren H – 2017-08-10T05:43:59.573

Answers

5

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.

Leo

Posted 2017-08-09T15:15:25.497

Reputation: 8 482

8

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.

Shaggy

Posted 2017-08-09T15:15:25.497

Reputation: 24 623

1Could you do (h-g+24)%24+(m-l+60)%60? – Arnauld – 2017-08-09T20:13:39.680

7

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.

Mr. Xcoder

Posted 2017-08-09T15:15:25.497

Reputation: 39 774

5

Jelly, 19 bytes

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

Try it online!

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

HyperNeutrino

Posted 2017-08-09T15:15:25.497

Reputation: 26 575

1https://i.stack.imgur.com/mYVF7.jpg – ETHproductions – 2017-08-09T19:04:23.063

@ETHproductions ಠ_ಠ – HyperNeutrino – 2017-08-09T19:04:56.377

3

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.

Kamil Drakari

Posted 2017-08-09T15:15:25.497

Reputation: 3 461

You can remove the parenthesis around 2+h+m for -2 bytes. – Kevin Cruijssen – 2017-08-10T07:15:19.543

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)

– Kevin Cruijssen – 2017-08-10T07:41:01.580

1Wouldn't you have to make it System.Math.Min ? – LiefdeWen – 2017-08-10T08:46:29.553

3

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.

Silvio Mayolo

Posted 2017-08-09T15:15:25.497

Reputation: 1 817

2

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)

HyperNeutrino

Posted 2017-08-09T15:15:25.497

Reputation: 26 575

@StepHen Whoops. Easy fix. – HyperNeutrino – 2017-08-09T15:28:27.063

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? – Mr. Xcoder – 2017-08-09T15:37:47.790

@Mr.Xcoder; I get 13 for that input using the TIO, which is correct (reset+11<9+59). – Shaggy – 2017-08-09T15:39:21.027

@Mr.Xcoder 24 hour time – HyperNeutrino – 2017-08-09T15:39:24.317

Ok, ok... I seem to have misunderstood. – Mr. Xcoder – 2017-08-09T15:39:50.203

@Mr.Xcoder my input spec was very loose, you can do basically whatever you want to get the input – Stephen – 2017-08-09T15:52:23.093

2Does % always return a positive number in Python? – Shaggy – 2017-08-09T16:00:59.617

4@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. – Stephen – 2017-08-09T16:02:41.143

2

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

Kevin Cruijssen

Posted 2017-08-09T15:15:25.497

Reputation: 67 575

1

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

Xcali

Posted 2017-08-09T15:15:25.497

Reputation: 7 671

1

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.

Neil

Posted 2017-08-09T15:15:25.497

Reputation: 95 035