Finding a wonderland number
I came across a simple puzzle this evening, on Wonderland Clojure Katas. My brain is half dead from starting work extra early and slogging through the day, but I wanted to include a tiny bit of Clojure recreation this evening, before the day was out.
Pretty much at random, I picked the wonderland-number puzzle where you have to find number with particular properties. In a way, the puzzle is similar to the ones you can find on Project Euler.
The problem statement is simple. It's about finding a Cyclic number, thus:
- it has six digits
- if you multiply it by 2,3,4,5, or 6, the resulting number has all the same digits in at as the original number. The only difference is the position that they are in
As I'm tired, it was quite nice to be able to apply the philosophy of building up from small blocks to reach the solution. So, here goes.
Step 1 - Getting the digits of a number
We're going to be comparing digits of a number, so let's have a function that will return a sequence of digits for a given number:
(defn digits [n] (map #(- (int %) (int \0)) (str n)))
The str
function calls .toString
on its argument, here turning a number into a string, and therefore, more importantly, a sequence that we can map
over.
The anonymous function we're using in the map simply converts the char value of each of the string characters to their numeric equivalents. (I do find converting a string representing a digit to its numeric value equivalent a little clunky in Clojure, having a background in scripting languages that make that more seamless. Perhaps I'm missing something. But I digress.)
Let's try it out:
scratchpad.core=> (digits 12401)
(1 2 4 0 1)
Step 2 - A unique set of digits
We actually want a unique set of digits, so we can better compare them:
(def digit-set (comp set digits))
Simply composing the function set
with our new digits
function does the trick.
Let's try it out:
scratchpad.core=> (digit-set 12401)
#{0 1 2 4}
Step 3 - Multiple results
So now we want to generate the list of results of multiplying the number under test with 2, 3, 4, 5 and 6. We want those results as digit sets. Here goes:
(defn mult-result [n] (map #(digit-set (* n %)) (range 2 7)))
All we're doing is folding (with map
) an anonymous function over the range
of "multiplier" numbers 2 through 6 inclusive. And this anonymous function multiplies the number under test with the particular multiplier being folded over, and produces a digit set from the result.
Let's try it out:
scratchpad.core=> (mult-result 123456)
(#{1 2 4 6 9} #{0 3 6 7 8} #{2 3 4 8 9} #{0 1 2 6 7 8} #{0 3 4 6 7})
Step 4 - Checking the digits are the same
The last thing we have to do is check whether the digits are the same in each of the multiplier cases.
(defn same-digits? [n] (apply = (mult-result n)))
Using apply
with a function allows that function to be used with the contents of the sequence supplied, rather than with the sequence itself. So the =
function operates on the multiple arguments that are the elements of the sequence produced by (mult-result n)
. The function name ends with a question mark in the tradition for Clojure predicate functions that return true or false.
Let's try it out:
scratchpad.core=> (same-digits? 123456)
false
Step 5 - Profit
Now we have all we need, and can use the same-digits?
function as a predicate in calling filter
on the six digit numbers:
scratchpad.core=> (first (filter same-digits? (range 100000 1000000)))
142857
Result!
So there are undoubtedly better ways of approaching this puzzle, but I wanted to illustrate the bottom-up approach of computing that Clojure, and functional programming in general lends itself rather well to. And on the occasions when you're tired and can only think in small chunks, it's ideal :-)