15
\$\begingroup\$

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.
\$\endgroup\$
  • \$\begingroup\$ Related challenge (minute and hour hands only, in degrees) \$\endgroup\$ – Sp3000 Jul 29 '15 at 10:43
  • 1
    \$\begingroup\$ You should probably specificy that there is a second hand on the clock. \$\endgroup\$ – isaacg Jul 29 '15 at 11:35
  • \$\begingroup\$ Can you add some test cases? \$\endgroup\$ – Beta Decay Jul 29 '15 at 12:54
  • 1
    \$\begingroup\$ On 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. \$\endgroup\$ – Reto Koradi Jul 29 '15 at 13:50
  • 1
    \$\begingroup\$ @BetaDecay Certainly. I might have said something like: "The clocks has three hands: hours, minutes, and seconds." \$\endgroup\$ – Reto Koradi Jul 29 '15 at 14:03
10
\$\begingroup\$

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.

\$\endgroup\$
9
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ Sorry, not familiar with Mathematica, but does this actually accept an argument or variable for the number of seconds since midnight? \$\endgroup\$ – Winny Jul 29 '15 at 19:35
  • 1
    \$\begingroup\$ @Winny Yes, it's a pure function (indicated by &) and the first argument it's passed is referred to inside as #. \$\endgroup\$ – jcai Jul 29 '15 at 19:37
7
\$\begingroup\$

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.

\$\endgroup\$
6
\$\begingroup\$

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°
\$\endgroup\$
  • \$\begingroup\$ Nice solution to account for wrap around \$\endgroup\$ – toto Jul 29 '15 at 13:37
2
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.