Find the nearest clock hands

15

1

Challenge

Given a number of seconds past midnight, output the smallest angle between any two hands on a clock face, using as few bytes as possible.

You may assume that the number of seconds is always less than 86400. Angles may be represented in degrees or radians.

A reference solution is at: http://ideone.com/eVdgC0

Test Cases (results in degrees)

0 -> 0
60 -> 0.5
600 -> 5
3600 -> 0
5400 -> 45
6930 -> 84.75
50000 -> 63.333

Clarificarions

  • The clock has 3 hands: hours, minutes and seconds.
  • All hands move continuously, thus hour and minute hands can be found between graduations on the clock face.

toto

Posted 2015-07-29T10:41:47.937

Reputation: 163

Related challenge (minute and hour hands only, in degrees) – Sp3000 – 2015-07-29T10:43:28.343

1You should probably specificy that there is a second hand on the clock. – isaacg – 2015-07-29T11:35:24.393

Can you add some test cases? – Beta Decay – 2015-07-29T12:54:42.497

@BetaDecay, I've shown some in my answer. They focus on hands pointing near 1, 6 and 11, so the 1 and 11 are closest in each case. – Hand-E-Food – 2015-07-29T13:03:18.463

1On some clocks, the minute hand jumps to the next minute when the second hand reaches the top. On others, it moves continuously. I figure this is a clock where it moves continuously? Also, while it's clear once you read carefully, I initially found "second hand" ambiguous, because most clocks have at least two hands anyway, so adding the "second hand" really adds a third hand. – Reto Koradi – 2015-07-29T13:50:42.700

@RetoKoradi But then again, no one refers to the second hand as the third hand and in turn would confuse more people if changed – Beta Decay – 2015-07-29T14:00:05.757

I have updated the question to address these points. – toto – 2015-07-29T14:02:41.720

1@BetaDecay Certainly. I might have said something like: "The clocks has three hands: hours, minutes, and seconds." – Reto Koradi – 2015-07-29T14:03:09.767

Answers

10

CJam, 36 35 34 32 30 bytes

riP*30/_60/_C/]2m*::-:mc:mC$3=

The output is in radians. I've verified the solutions for all 86400 possible inputs.

Try it online in the CJam interpreter.

Idea

Since radians is a full lap, each minute/second interval on the clock is 2π/60 = π/30 radians wide.

Thus, dividing the number of seconds by π/30 yields the position of the second hand.

The minute hand moves at one sixtieth of the pace of the second hand, so dividing the result from above by 60 yields the position of the minute hand.

Likewise, dividing the last result by 12 yields the position of the hour hand.

Note that our three quotient from above are not necessarily in the range [0,2π).

By calculating all nine possible differences of the hands' angles, we obtain three 0's (angular distance between a hand and itself) and the six distances between the different hands.

If the closest hands are on a half that does not include 12, one of the differences from above will be the desired output (mod ).

However, at 01:55:30 (for example), the hour hand is at an angle of 1.008 rad (57.75 deg) and the minute hand at an angle of 5.812 rad (333.00 deg) from 12, giving a difference of 4.804 rad (275.25 deg). By subtracting this result from a full lap, we obtain the angle measured "in the other direction", which equals 1.479 rad (84.75 rad).

Now, rather than mapping each angle θ in [0,2π) and conditionally subtracting the result from π, we can simply calculate arccos(cos(θ)), since cos is both periodic and even, and arccos always yields a value in [0,π).

Skipping over the three smallest results (all zero), the fourth smallest will be the desired output.

Code

ri                             e# Read an integer from STDIN.
  P*30/                        e# Multiply by π and divide by 30.
       _60/                    e# Divide a copy by 60.
           _C/                 e# Divide a copy by 12.
              ]2m*             e# Push the array of all pairs of quotients.
                  ::-          e# Replace each pair by its difference.
                     :mc       e# Apply cosine to each difference.
                        :mC    e# Apply arccosine to each cosine.
                           $3= e# Sort and select the fourth smallest element.

Alternate version (34 bytes)

rd6*_60/_C/]360f%2m*::m360X$f-+$6=

The output is in degrees and no trigonometric functions are used.

Try it online in the CJam interpreter.

Dennis

Posted 2015-07-29T10:41:47.937

Reputation: 196 637

9

Mathematica, 40 bytes

Min@Abs@Mod[#{11,708,719}/120,360,-180]&

Explanation: Let t be number of seconds since midnight. The position of each hand is

hour: t/120 (mod 360)
min:  t/10 (mod 360)
sec:  6t (mod 360)

To calculate the absolute angular distance between x degrees and y degrees, we can mod y - x by 360 into the range [-180, 180] and then take the absolute value. (Note that there is no restriction on x and y.) So this function just calculates the pairwise differences t/10-t/120, 6t-t/10, and 6t-t/120 and does that.

jcai

Posted 2015-07-29T10:41:47.937

Reputation: 973

Sorry, not familiar with Mathematica, but does this actually accept an argument or variable for the number of seconds since midnight? – Winny – 2015-07-29T19:35:00.997

1@Winny Yes, it's a pure function (indicated by &) and the first argument it's passed is referred to inside as #. – jcai – 2015-07-29T19:37:41.423

7

Python, 65

lambda n,l={720,60,1}:6*min((n/x-n/y)%60for x in l for y in{x}^l)

The distance traveled by the hour, minute, and second hand, in units of 1/60 of the circle are h,m,s = n/720, n/60, n/1. We can take these mod 60 to get their position on the circle from 0 to 60.

If we take their difference mod 60, we get the number of units that one is in front of the other. We take all six possible differences, find the min, then multiply by 6 to rescale to 360 degrees.

The two-layer list comprehension first chooses the first hand as represented by 720, 60, or 1, then chooses the other hand out of that set with the first choice removed via set xor.

I tested this exhaustively against the reference code.

xnor

Posted 2015-07-29T10:41:47.937

Reputation: 115 687

6

C#, 163 152 bytes

This creates every hand twice to count for wrap-around, then loops through every combination and finds the minimum angle between hands. Calculations are performed in 60 divisions, then multiplied by 6 to get degrees.

Indented for clarity:

float F(int s){
    float b=60,c;
    float[]a={c=s/b/b%12*5,c+b,c=s/b%b,c+b,s%=60,s+b};
    for(s=36;s-->0;)
        b=s%6!=s/6&(c=(c=a[s%6]-a[s/6])<0?-c:c)<b?c:b;
    return b*6;
}

Example output:

    0 seconds, 00:00:00, smallest angle is 0°
43200 seconds, 12:00:00, smallest angle is 0°
86399 seconds, 23:59:59, smallest angle is 0.09164429°
 3330 seconds, 00:55:30, smallest angle is 54.75°
39930 seconds, 11:05:30, smallest angle is 60.25001°
21955 seconds, 06:05:55, smallest angle is 65.49998°
21305 seconds, 05:55:05, smallest angle is 59.50001°
 5455 seconds, 01:30:55, smallest angle is 75.45831°
41405 seconds, 11:30:05, smallest angle is 44.95834°

Hand-E-Food

Posted 2015-07-29T10:41:47.937

Reputation: 7 912

Nice solution to account for wrap around – toto – 2015-07-29T13:37:38.573

2

TI-BASIC, 17 bytes

min(cos⁻¹(cos(ΔList(Ans{6,.1,5!⁻¹,6

Uses Dennis's arccos(cos( to normalize distances; however, rather than calculating all pairwise distances, it only calculates the three needed using ΔList([seconds],[minutes],[hours],[seconds].

This program expects Degree mode and returns the answer in degrees.

EDIT: 5! is one byte shorter than 120.

lirtosiast

Posted 2015-07-29T10:41:47.937

Reputation: 20 331