Skip to content

Instantly share code, notes, and snippets.

@bos
Created August 8, 2011 23:35
Show Gist options
  • Save bos/1133048 to your computer and use it in GitHub Desktop.
Save bos/1133048 to your computer and use it in GitHub Desktop.
C++ and Haskell versions of code
// Brute force solver for the Word Number problem
#include <iostream>
#include <string>
int length_ones[10] = {0,3,3,5,4,4,3,5,5,4}; // "", one, two, three, ...
int length_tens[10] = {0,3,6,6,5,5,5,7,6,6}; // "", ten, twenty, ...
int length_teens[10] = {3,6,6,8,8,7,7,9,8,8}; // ten, eleven, twelve, ...
const char * ones[] = {"", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
const char * tens[] = {"", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
const char * teens[] = {"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteeen", "nineteen"};
std::string wordify(long n)
{
if(n < 10) return ones[n];
else if(n < 20) return teens[n-10];
else if(n < 100) return std::string(tens[n/10]) + ones[n%10];
else if(n < 1000) return std::string(ones[n/100]) + "hundred" + wordify(n%100);
else if(n < 1000000) return wordify(n/1000) + "thousand" + wordify(n%1000);
else return wordify(n/1000000) + "million" + wordify(n%1000000);
}
static int word_length(long n)
{
if(n < 10) return length_ones[n];
else if(n < 20) return length_teens[n-10];
else if(n < 100) return length_tens[n/10] + length_ones[n%10];
else if(n < 1000) return length_ones[n/100] + 7 + word_length(n%100); // 7 for "hundred"
else if(n < 1000000) return word_length(n/1000) + 8 + word_length(n%1000);
else return word_length(n/1000000) + 7 + word_length(n%1000000);
}
int main(int argc, char **argv)
{
long sumNumbers = 0;
long sumLength = 0;
long i;
long target;
if (argc > 1)
target = atol(argv[1]);
else
target = 51000000000;
for(i = 1; i < 999999999; i++)
{
sumNumbers += i;
long newSumLength = word_length(i) + sumLength;
if(newSumLength >= target)
break;
sumLength = newSumLength;
}
std::cout << "Sum: " << sumNumbers << std::endl;
std::cout << "The letter is " << wordify(i)[target - sumLength - 1] << std::endl;
return 0;
}
{-# OPTIONS_GHC -O2 #-}
{-# LANGUAGE BangPatterns, MagicHash, OverloadedStrings, UnboxedTuples #-}
module Main (main) where
import Data.Monoid (mappend, mempty)
import GHC.Base (Int(..), chr, quotInt#, remInt#)
import Prelude hiding ((!!))
import System.Environment (getArgs)
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Unsafe as B
import qualified Data.Vector as V
import qualified Data.Vector.Generic as G
import qualified Data.Vector.Unboxed as U
wordVec = V.fromList . B.words
ones = V.cons mempty $ wordVec "one two three four five six seven eight nine"
tens = V.cons mempty $ wordVec "ten twenty thirty forty fifty sixty seventy \
\ eighty ninety"
teens = wordVec "ten eleven twelve thirteen fourteen fifteen sixteen seventeen \
\ eighteen nineteen"
lengthVec :: V.Vector B.ByteString -> U.Vector Int
lengthVec = U.convert . V.map B.length
-- For notational convenience.
a !! b = G.unsafeIndex a b
-- The default definitions of quot and rem check for div-by-zero,
-- whereas we don't care.
(I# a) // (I# b) = I# (a `quotInt#` b)
(I# a) % (I# b) = I# (a `remInt#` b)
wordify i = go i where
go n
| n < 10 = ones !! n
| n < 20 = teens !! (n-10)
| n < 100 = (tens !! (n // 10)) `mappend` (ones !! (n % 10))
| n < 1000 = (ones !! (n // 100)) `mappend` "hundred" `mappend` go (n % 100)
| n < 1000000 = go (n // 1000) `mappend` "thousand" `mappend` go (n % 1000)
| otherwise = go (n // 1000000) `mappend` "million" `mappend` go (n % 1000000)
wordLength i = go i
where
go n
| n < 10 = lengthOnes !! n
| n < 20 = lengthTeens !! (n-10)
| n < 100 = (lengthTens !! (n // 10)) + (lengthOnes !! (n % 10))
| n < 1000 = (lengthOnes !! (n // 100)) + 7 + go (n % 100)
| n < 1000000 = go (n // 1000) + 8 + go (n % 1000)
| otherwise = go (n // 1000000) + 7 + go (n % 1000000)
!lengthOnes = lengthVec ones
!lengthTens = lengthVec tens
!lengthTeens = lengthVec teens
main = do
args <- getArgs
let target = case args of
[a] -> read a
_ -> 51000000000
let go i sumLength !sumNumbers
| i >= 999999999 = (i, sumLength, sumNumbers)
| sumLength' >= target = (i, sumLength, sumNumbers')
| otherwise = go (i+1) sumLength' sumNumbers'
where sumLength' = wordLength i + sumLength
sumNumbers' = sumNumbers + i
let (i, sumLength, sumNumbers) = go 1 0 0
putStrLn $ "Sum: " ++ show sumNumbers
let w = wordify i `B.unsafeIndex` (target - sumLength - 1)
putStrLn $ "The letter is " ++ (show . chr . fromIntegral $ w)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment