You are given time
$T
in the format hh:mm.Write a script to find the smaller angle formed by the hands of an analog clock at a given time.
HINT: A analog clock is divided up into12
sectors. One sector represents 30 degree(360/12 = 30)
.
Input: $T = '03:10' Output: 35 degree
The distance between the
2
and the3
on the clock is30
degree. For the10
minutes i.e.1/6
of an hour that have passed. The hour hand has also moved1/6
of the distance between the3
and the4
, which adds5
degree (1/6
of30
). The total measure of the angle is35
degree.Input: $T = '04:00' Output: 120 degree
The hint suggests we should calculate the angle the hour hand makes (compared to some base line) and the angle the minute hand makes (compared to the same base line), and calculate the difference.
We will be ignoring that.
In fact, we will not looking at any specific angle the hour or minute hands are making. Instead, we will make use of the following observations:
00:00
, the hour hand and the minute hands align, that is,
the angle between them is 0
°.5.5
°.So, we can calculate the number of minutes after midnight the time
indicates, and multiply that with 5.5
°. This may be a number which
is more than 360
° — each time the minute hand catches up with
the hour hand, the angle with be a multiple of 360
°. So, we will
take the angle module 360
°.
But that may lead to a problem. The number of minutes after midnight
will always be an integer, but once with multiply with 5.5
, we
may not have an integer left. And not every language handles a modulo
operation well if not both operands are integers.
To deal with this, we will measure the angle between the hands in
half-degrees. So, will multiply the number of minutes after midnight
with 11
, and then modulo it with 720
. Since we are required to
report the smaller of the angles, if the calculated angle is more than
360
half-degrees, we subtract the angle from 720
.
What's left is to report the angle in degrees, which means dividing
the calculated number by 2
, so we're back to full degrees.
With the input time in $_
:
my $MIN_PER_HOUR = 60;
my $DIFF_PER_MINUTE = 11;
my $FULL_CIRCLE = 720;
my ($hours, $minutes) = /[0-9]+/g;
my $angle = ($DIFF_PER_MINUTE * ($hours * $MIN_PER_HOUR + $minutes)) %
$FULL_CIRCLE;
$angle = $FULL_CIRCLE - $angle if 2 * $angle >= $FULL_CIRCLE;
say $angle / 2;
Find the full program on GitHub.
BEGIN {
FS = ":"
DIFF_PER_MINUTE = 11
MIN_PER_HOUR = 60
FULL_CIRCLE = 720
}
We're setting FS
here, so AWK will neatly split the input
for us on colons, meaning we have the hours available in $1
,
and the minutes in $2
.
{
angle = (DIFF_PER_MINUTE * ($1 * MIN_PER_HOUR + $2)) % FULL_CIRCLE
if (2 * angle >= FULL_CIRCLE) {
angle = FULL_CIRCLE - angle
}
print (angle / 2)
}
Find the full program on GitHub.
Just like in AWK, Bash can autosplit input for us. We do this
by setting IFS
:
IFS=":"
DIFF_PER_MINUTE=11
MIN_PER_HOUR=60
FULL_CIRCLE=720
We can now directly read hours
and minutes
. But there is a catch.
Hours and minutes of the form 08
or 09
will be interpreted by
Bash as illegal octal numbers. That's not what we want!
We will use a trick: we prepend the number with a 1
(giving us
a three digit number, starting with a 1
), the subtracting 100
!
while read hours minutes
do ((hours = "1$hours" - 100))
((minutes = "1$minutes" - 100))
((angle = (DIFF_PER_MINUTE * (hours * MIN_PER_HOUR + minutes)) %
FULL_CIRCLE))
if ((2 * angle >= FULL_CIRCLE))
then ((angle = FULL_CIRCLE - angle))
fi
Now, Bash only has integer division. So, we first divide angle
by 2
and print the result. Then we check whether angle
is an odd number;
if it is, we print .5
, as the result should have an additional half degree.
printf "%d" $((angle / 2))
if ((angle % 2 == 1))
then printf ".5"
fi
echo
done
Find the full program on GitHub.
The calculations in our bc solution is very similar as the solutions in other languages, but we need to do something special when printing the result:
diff_per_minute = 11
min_per_hour = 60
full_circle = 720
hours = read ()
minutes = read ()
scale = 0
angle = (diff_per_minute * (hours * min_per_hour + minutes)) % full_circle
if (2 * angle >= full_circle) {
angle = full_circle - angle
}
scale = angle % 2
if (angle == 1) {
"0"
}
angle / 2
By default, assuming the -l
isn't used, bc
uses integer arithmetic.
We can change this by assigning to the special variable scale
, which
tells bc to how many decimals after the comma you want results.
But setting it to 1
at the beginning of the program and leaving it
at 1
causes two issues: first, it will always print the number of
degrees with one decimal after the decimal dot — even if the result
is an integer. Furthermore, the modulus operator doesn't work as it
does when scale
is set to 0
.
So, we first set the scale to 0
, then, before printing the result
set scale
to 1
iff angle
is odd. The result is that if the hands
make an angle which is an integer amount of degrees, we print an integer;
otherwise, the result will be an integer and a half.
Another oddity is that bc prints a half as .5
, not 0.5
. To counteract
that, if angle
equals 1
(so, one half-degree), we first print a 0
(which then will be followed by .5
, giving the end result of 0.5
).
Also note that in bc, all variables are in lowercase.
Find the full program on GitHub.
Nothing special about the C solution. C uses integer division if
both its operands are integers, so a similar check as in our Bash
solution on whether angle
is odd, and, if so, print .5
:
# define DIFF_PER_MINUTE 11
# define MIN_PER_HOUR 60
# define FULL_CIRCLE 720
int main (void) {
int hours, minutes;
while (scanf ("%d:%d", &hours, &minutes) == 2) {
int angle = (DIFF_PER_MINUTE * (hours * MIN_PER_HOUR + minutes)) %
FULL_CIRCLE;
if (2 * angle >= FULL_CIRCLE) {
angle = FULL_CIRCLE - angle;
}
printf ("%d", angle / 2);
if (angle % 2) {
printf (".5");
}
printf ("\n");
}
return (0);
}
Find the full program on GitHub.
In Go, things are similar:
import (
"fmt"
)
var DIFF_PER_MINUTE = 11;
var MIN_PER_HOUR = 60;
var FULL_CIRCLE = 720;
func main () {
var hours, minutes int;
for {
var n, err = fmt . Scanf ("%d:%d", &hours, &minutes)
if (err != nil || n != 2) {
break;
}
var angle = (DIFF_PER_MINUTE * (hours * MIN_PER_HOUR + minutes)) %
FULL_CIRCLE;
if (2 * angle >= FULL_CIRCLE) {
angle = FULL_CIRCLE - angle;
}
fmt . Print (angle / 2);
if (angle % 2 == 1) {
fmt . Print (".5")
}
fmt . Print ("\n")
}
}
Find the full program on GitHub.
Java is a bit more verbose, but no surprises here:
import java.util.*;
public class ch2 {
public static void main (String [] args) {
int DIFF_PER_MINUTE = 11; // Half degrees
int MIN_PER_HOUR = 60;
int FULL_CIRCLE = 720; // Half degrees
Scanner scanner = new Scanner (System . in);
try {
while (true) {
String line = scanner . nextLine ();
String [] parts = line . split (":");
int hours = Integer . parseInt (parts [0]);
int minutes = Integer . parseInt (parts [1]);
int angle = (DIFF_PER_MINUTE *
(hours * MIN_PER_HOUR + minutes)) % FULL_CIRCLE;
if (2 * angle >= FULL_CIRCLE) {
angle = FULL_CIRCLE - angle;
}
System . out . print (angle / 2);
if (angle % 2 == 1) {
System . out . print (".5");
}
System . out . print ("\n");
}
}
catch (Exception e) {
//
// EOF
//
}
}
}
Find the full program on GitHub.
local DIFF_PER_MINUTE = 11
local MIN_PER_HOUR = 60
local FULL_CIRCLE = 720
for line in io . lines () do
local _, _, hours, minutes = line : find ("([0-9][0-9]):([0-9][0-9])")
hours = tonumber (hours)
minutes = tonumber (minutes)
local angle = (DIFF_PER_MINUTE * (hours * MIN_PER_HOUR + minutes)) %
FULL_CIRCLE
if 2 * angle >= FULL_CIRCLE
then angle = FULL_CIRCLE - angle
end
print (angle / 2)
end
Find the full program on GitHub.
let DIFF_PER_MINUTE = 11
let MIN_PER_HOUR = 60
let FULL_CIRCLE = 720
require ('readline')
. createInterface ({input: process . stdin})
. on ('line', line => {
let [hours, minutes] = line . trim () . split (":")
angle = (DIFF_PER_MINUTE * (+hours * MIN_PER_HOUR + +minutes)) %
FULL_CIRCLE
if (2 * angle >= FULL_CIRCLE) {
angle = FULL_CIRCLE - angle
}
console . log (angle / 2)
})
Find the full program on GitHub.
ses sysutils;
var
time: string;
hours, minutes, angle: integer;
const
DIFF_PER_MINUTE = 11;
MIN_PER_HOUR = 60;
FULL_CIRCLE = 720;
begin
while not eof () do begin
readln (time);
hours := strtoint (leftstr (time, 2));
minutes := strtoint (rightstr (time, 2));
angle := (DIFF_PER_MINUTE * (hours * MIN_PER_HOUR + minutes)) mod
FULL_CIRCLE;
if 2 * angle >= FULL_CIRCLE then begin
angle := FULL_CIRCLE - angle;
end;
write (angle div 2);
if angle mod 2 = 1 then begin
write ('.5');
end;
writeln ('');
end
end.
Find the full program on GitHub.
Not much special about the Python solution:
import fileinput
DIFF_PER_MINUTE = 11
MIN_PER_HOUR = 60
FULL_CIRCLE = 720
for line in fileinput . input ():
hours, minutes = line . strip () . split (":")
angle = (DIFF_PER_MINUTE * (int (hours) * MIN_PER_HOUR + int (minutes))) \
% FULL_CIRCLE
if 2 * angle >= FULL_CIRCLE:
angle = FULL_CIRCLE - angle
print (int (angle / 2), end = '')
if angle % 2:
print (".5", end = '')
print ("")
Find the full program on GitHub.
R has a slightly usual assignment operator (<-
), which came to R from APL.
Indexing arrays requires double brackets. Other than that, the R solution
is very similar to the solutions in other languages:
DIFF_PER_MINUTE <- 11
MIN_PER_HOUR <- 60
FULL_CIRCLE <- 720
stdin <- file ('stdin', 'r')
time <- readLines (stdin, n = 1)
parts <- strsplit (time, ":")
hours <- as.numeric (parts [[1]] [[1]])
minutes <- as.numeric (parts [[1]] [[2]])
angle <- (DIFF_PER_MINUTE * (hours * MIN_PER_HOUR + minutes)) %%
FULL_CIRCLE
if (2 * angle >= FULL_CIRCLE) {
angle <- FULL_CIRCLE - angle
}
cat (angle / 2, "\n")
Find the full program on GitHub.
diff_per_minute = 11
min_per_hour = 60
full_circle = 720
ARGF . each_line do
|time|
hours, minutes = time . split (/:/)
angle = (diff_per_minute * (hours . to_i * min_per_hour + minutes . to_i))\
% full_circle
angle = full_circle - angle if 2 * angle >= full_circle
print (angle / 2)
print (".5") if angle % 2 == 1
print ("\n")
end
Find the full program on GitHub.
Tcl suffers from the same issue as Bash: if a value starts with a 0
,
tcl treats it as an octal number, which causes a problem for 08
and 09
. So, we use the same technique we used in Bash: prepend
a 1
to the number, then subtract 100
:
set DIFF_PER_MINUTE 11
set MIN_PER_HOUR 60
set FULL_CIRCLE 720
while {[gets stdin line] >= 0} {
set parts [split $line :]
set hours [expr 1[lindex $parts 0] - 100]
set minutes [expr 1[lindex $parts 1] - 100]
set angle [expr (($DIFF_PER_MINUTE * \
($hours * $MIN_PER_HOUR + $minutes))) % $FULL_CIRCLE]
if {2 * $angle >= $FULL_CIRCLE} {
set angle [expr $FULL_CIRCLE - $angle]
}
puts -nonewline [expr $angle / 2]
if {$angle % 2 == 1} {
puts -nonewline ".5"
}
puts ""
}
Find the full program on GitHub.
Without comments:
> & :1+!#@_ ~$ 543*** &+ 65+ * 65432**** % : 6543*** `#v_v
^ v v
^ v<<<<<<<<<<<<<<<<<<<<<<<<<< /2 : < -\ ****23456 : < v
^ v ^<<<<<<<<<<<<<<<<<<<<
^ v
^ >>> : 56+9* `!#v_ : 554** / "0"+, 554** % > : 55+ / "0"+, > 55+% "0"+, v
^ v ^ ^ v
^ >>>>>>>>>>>>>>>>>>> : 9 `#^_ >>>>>>>>>>>>^ v
^ v
^ v ,,".5" < v
^ v ^ v
^<<<<<<<<<<<<<<<<<<<<<<<<<< , +55 <<<<<<<<<<<<<<<<<<<<<<<<< _^# !%2 <<<
Find the full program on GitHub.