Sunday, March 31, 2013

Programming Puzzle: The Clock Angle Problem



I came across an interesting programming puzzle the other day that I hadn’t seen before. It’s called the Clock Angle Problem. In a nutshell: Given a time of day, what is the smallest angle between the hands on an analog clock showing that time? What about the angle for the current time, whatever that time is? While there is an analytic solution, the problem provides a tidy little puzzle for programmers to solve programmatically.

So I did the obvious thing: coded up a solution and posted it to Github. The trick is to convert hours and seconds to the same units so you can find the difference. You can compute the difference in degrees (in this sample the values are also precomputed). You can also normalize their values first.

Let’s take this question a step further and ask: How would we unit test all of this? (again, test code is on Github) If we have a method for finding the angle given the current time, any unit test require separation of obtaining and parsing the current time from the actual clock angle algorithm. Once that’s done, a parameterized unit test fits the bill nicely for the algorithm and we can spot check some known values.

We can write another test for parsing the hour and minute from a Date. The trickiest part to test is obtaining the current Date, since time-based unit tests require a little special handling. We need to encapsulate the production of the current Date (say, in a DateProvider class, or in an overridable factory method on the Clock) in such a way that we can override it in the test to provide a constant Date for unit testing. Then the one-liner that provides the current Date can easily be unit tested: test that it is the same as a new Date() constructed in the unit test (within a certain tolerance, say 100ms).

We can still do more with this question. What if the hour and minute hands ticked for every millisecond and we wanted millisecond-level accuracy? Would rounding errors be a concern, and if so, how would we mitigate that? If the calculation was really expensive, how could we implement caching? (Hint: Not WeakHashMap) I’m not answering these questions here, but they are left as an exercise for the reader (or for myself for a future blog post).

No comments:

Post a Comment