[Home] [Puzzles & Projects] [Delphi Techniques] [Math Topics] [Library] [Utilities]
Here's a beginner's program that was adapted from an ACM Programming Contest. Given integers representing hour and minute of a time of day, calculate the angle between the hour and minute hands when looking at a normal analog clock.
(If you're not interested in the why or how, you can skip to the bottom of the page to download source and/or executable for this program)
Background & Techniques
ACM Programming Contests provide an almost unlimited source of problems. Each contest contains a couple of programs that can be coded by a talented college Freshman in an hour. This is one.
I decided to time myself - the non-visual version took 30 minutes. With the extra time I added a visual clock display - which took an extra 28 minutes. You won't find many comments in the code so I'll try to provide a thorough explanation here.
First the "computing the angles" part. The angle of the minute hand should be "# of degrees for each minute" X "# of minutes". Since 60 minutes represents 360 degrees, each minute represents 360/60 or 6 degrees. (So 30 minutes becomes 6*30 = 180 degrees, etc.). The hour hand is similar with one exception - the hour hand includes hours and and fractions of an hour (reflected by minutes) in its angle. So the hourtime is "hours + minutes/60". ( Hourtime for 6:30, for example, is 6+30/60 or 6.5). Since the hour hand revolves 1/12 of a revolution or 30 degrees for each hour, the hour hand angle is 30 X hour time. If the time is 6:30, the hour hand angle is 30 X 6.5 = 195 degrees. Finally, the angle difference between the hands is 195-180=15 degrees.
As you browse the program you'll note that, under the pressure of time, the code is not quite this neat. I tended to write the code step by step as I worked out the solution. (How we solve problems is an big interest of mine but it's very difficult to solve a problem and think about how it's being solved at the same time.)
On to the second half of the problem - displaying the clock image. I "wasted" perhaps 5 minutes deciding which component to use. First a TShape circle was dropped on the form as a clock face, but then realized that it has no Canvas property on which to draw hands etc. I considered drawing the clock face using the form's canvas, but rejected that idea. A TImage was finally chosen using a TBitmap's canvas to draw on.
The drawing was implemented as a procedure ( DrawTime) with the two hand angles as parameters. I decided to make the minute hand length equal to 3/4 of the face radius and the hour hand equal to half the radius. Looking at real clocks now I see that they should be much longer, another sacrifice to time pressure. To draw the hands, we need a couple of lines at particular angles. Time for a trigonometry review. Pretty simple thanks to my old Indian chief friend - chief SOH CAH TOA. (In case you haven't met him, Sine=Opposite side/Hypotenuse, Cosine=Adjacent side/Hypotenuse and Tangent=Opposite/Adjacent; --- picture an Indian chief soaking his toe). In our case sin(a)=Y/HandLength and cos(a)=X//HandLength. Or, multiplying everything by HandLength, Y=sin(a)*HandLength, X=cos(a)*HandLength. Note that these angles are calculated the traditional way, relative to horizontal. For our clock face we need to subtract 90 degrees to make them relative to vertical. On hindsight, I see that the same 90 degree shift could be accomplished by interchanging the sin and cos functions.
Everything else is detail. Sin and Cos functions require angles in radians so input angles are multiplied by Pi/180. There is a DegToRad function which does this, but again, I didn't have time to look it up. The 12 dots around the clock face were added as a bonus in the last 5 minutes of my one hour time limit.
All-in-all, I didn't find "speed programming" nearly as enjoyable as taking more time and doing it well. The program has about 100 lines of code but nearly half are generated for the many labels, edits, etc. on the form. The angle calculation part took about 20 lines of code and the DrawTime procedure about 40 lines.
Addendum October 20, 2004: A viewer recently wrote asking for the solution to a puzzle that was bugging him - "How many times are a clock's hour and minute hands at right angles to each other in a 24 hour day?" Here's a link to my email answer. I also animated the clock angle program today to visually answer the question. This addition moves the program from "Beginners" to "Intermediate" category, but still not too complex if you take time to study the code. As always, feel free to use the feedback link below if you have questions or comments.
Addendum June 23, 2006: The email mentioned above derives the equations for calculating when the hands are 90° apart: m = (60h+180) / 11 (for minute hand leading hour hand by 90°) and m = (60h-180) / 11 (for minute hand trailing hour hand by 90°). Another viewer wrote recently, confused by the results. For example, when she tried hour 9, she got 65.45 for the minutes time rather than the 0 she expected. Two factors contribute to This anomalous result:
To clarify things, here is the complete table for each hour with minutes for both trailing and leading. I have subtracted 60 minutes when the equation results were greater than 60:
Notice that, for the hour hand horizontal (3 or 9 o'clock), the time duplicates the preceding entry in the table. So there are only 11 (or 22 counting before and after) unique values in 12 hours!
September 18, 2011: We're revisiting the program today with Version 2 which allows the option of pausing the clock each time the minute hand is at right angles to the hour hand. Thanks to Middle-school teacher Judy in Australia for requesting the feature to help her math students think about the problem The exercise forced me to re-think the algorithm because, while it was easy to count hands crossing the 90 degree boundaries, stopping there and displaying the exact crossing time was not so easy. In the process I developed this step by step explanation which seems easier to understand and implement than the equations previously developed:
Running/Exploring the Program
Suggestions for Further Explorations
It wouldn't take much code to add a second hand, and a timer to pop each second to produce a real time analog clock. Easy to do -- so now you can see why tons of versions already exist - let's just move on to the next challenge.
Copyright © 2000-2014, Gary Darby
All rights reserved.