Saturday, September 24, 2011

Last week's puzzler

I mean this puzzler [2015-07-26: instead try this] from Car Talk -- yes, that Car Talk. The answer is linked from there, but of course rather than figuring it all out by hand I wanted to use a computer to do something about it.

Here's my paraphrase of the puzzle: What is special about the numbers (and the spellings) in this list: 4, 6, 12, 30, 33, 36, 40, 45, 50, 54, 56, 60, 70, 81, 88, 90, 100? The order is not important, and the property we're talking about is met by no other numbers between 1 and 100. I'll put a little space here so if you don't want to know the answer quite yet, you don't need to see it :)
  OK, so I thought, "H'm, why 'four' but not 'five'? Well 'four' and 'five' are both 4 letters long; 4 is a factor of 4 but isn't a factor of 5. 'six' is three letters, 3 is a factor of 6."

So I typed this little list into a file, which I imaginatively called tmp/cartalk-number-puzzler:

one hundred
Now, rather than counting letters by hand, I did this:
$ while read X; do echo $X ${#X}; done < tmp/cartalk-number-puzzler
four 4
six 3
twelve 6
thirty 6
thirty-three 12
thirty-six 10
Let me explain that.
  • while read X; do means "read a line and assign it to $X, then execute the following."
  • echo $X ${#X} means to echo (on the terminal display) the values of $X and the length of $X (which is the translation of ${#X})
  • done is the other end of the do we saw above
  • < tmp/cartalk-number-puzzler means "and read from this file, not from what I'm typing"
Now 12 isn't a factor of 33, and 10 isn't a factor of 36. So I wasn't sure about this whole factor business. But then I noticed that if you count only letters, then the length of "thirty-three" comes to 11, which is a factor of 33. So I tweaked my little loop:
$  while read X; do  Y=${X// /}; Y=${Y//-/}; echo $X ${#Y}; done < tmp/cartalk-number-puzzler 
four 4
six 3
twelve 6
thirty 6
thirty-three 11
thirty-six 9
forty 5
forty-five 9
fifty 5
fifty-four 9
fifty-six 8
sixty 5
seventy 7
eighty-one 9
eighty-eight 11
ninety 6
one hundred 10
The two new things here are... Y=${X// /}, which means "replace all the 'blank' characters from $X by '' (nothing) and put the result into $Y — and Y=${Y//-/}; which takes $Y (i.e., the de-blanked version of $X) and replaces all the hyphens by '', storing the result back into $Y

We then print the length of $Y -- the de-blanked, de-hyphen'd version of $X -- and by inspection I think these all match the hypothesis: 10 goes evenly into 100, 6 goes evenly into 90, 11 goes evenly into 88, etc.

But wait, that's not enough! The puzzler specified that these are the only numbers between 1 and 100 with that property. I'm way too lazy to type 'twenty-one' and 'seventeen' and 'eleven' in, and I thought somebody must have written a routine to do this, so I googled "python numbers to text" (no quotes) and downloaded "Convert Numbers to Words (Python)", which works like a champ. I coded this little thing which uses num2word, like this:

import num2word 
for i in range(1,101):
    tweaked = num2word.to_card(i).replace(' ', '').replace('-', '')
    if i % len(tweaked) == 0:
        print i, tweaked, 'len =', len(tweaked)
What this says is, take all positive integers up to and including 100, and calculate "tweaked" -- which is the de-blanked, de-hyphen'd version of the textual representation (i.e., num2word.to_card(i)( of the number. Then, display a message on the terminal if the length of tweaked is a factor of i. The result was:
4 four len = 4
6 six len = 3
12 twelve len = 6
30 thirty len = 6
33 thirtythree len = 11
36 thirtysix len = 9
40 forty len = 5
45 fortyfive len = 9
50 fifty len = 5
54 fiftyfour len = 9
56 fiftysix len = 8
60 sixty len = 5
70 seventy len = 7
81 eightyone len = 9
88 eightyeight len = 11
90 ninety len = 6
100 onehundred len = 10
which was the list we started with.

"You've done it again—you've wasted another perfectly good hour listening to Car Talk."

No comments: