Skip to content

Instantly share code, notes, and snippets.

@jordangarcia
Created February 20, 2013 03:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jordangarcia/4992656 to your computer and use it in GitHub Desktop.
Save jordangarcia/4992656 to your computer and use it in GitHub Desktop.
(ns euler.p17)
;If the numbers 1 to 5 are written out in words: one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total.
;If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used?
;
;NOTE: Do not count spaces or hyphens. For example, 342 (three hundred and forty-two) contains 23 letters and 115 (one hundred and fifteen) contains 20 letters. The use of "and" when writing out numbers is in compliance with British usage.
(require '[clojure.string :as string])
(defn ret [rem s] {:num rem :s s})
(def hundreds {:base 100 :digit-start 2 :digit-end 3 :string "hundred"})
(def thousands {:base 1000 :digit-start 3 :digit-end 6 :string "thousand"})
(def millions {:base 1000000 :digit-start 6 :digit-end 9 :string "million"})
(defn solve-1-99 [input]
(let [dict (apply sorted-map [
1 "one"
2 "two"
3 "three"
4 "four"
5 "five"
6 "six"
7 "seven"
8 "eight"
9 "nine"
10 "ten"
11 "eleven"
12 "twelve"
13 "thirteen"
14 "fourteen"
15 "fifteen"
16 "sixteen"
17 "seventeen"
18 "eighteen"
19 "nineteen"
20 "twenty"
30 "thirty"
40 "forty"
50 "fifty"
60 "sixty"
70 "seventy"
80 "eighty"
90 "ninety"
])]
(loop [try (:num input) s (:s input) pdict dict]
(if (zero? try)
(ret try s)
(let [trykey (peek (vec (keys pdict)))
diff (- try trykey)
hyphen (if (and
(< 10 (:num input))
(zero? diff)
(< try 10))
"-" "")]
(if (<= 0 diff 20)
(recur
(- try trykey)
(str s hyphen (pdict trykey))
(dissoc pdict trykey))
(recur try s (dissoc pdict trykey))
))))))
(defn extract-digits [num [s e]]
(let [st (.toString num)]
(read-string (string/reverse (subs (string/reverse st) s (min e (count st)))))))
(defn solve-1-999 [input]
(let [base 100
s 2
e 3
string "hundred"
num (:num input)]
(if (< num base)
(solve-1-99 input)
(let [multi (extract-digits num [s e])
solved (solve-1-99 (ret multi ""))
remain (- num (* base multi))
andstr (if (< 0 remain 100) "and " "")
returnstr (str (:s input) (:s solved) " " string " " andstr)]
(solve-1-999 (ret remain returnstr))))))
(defn solve-any [input info]
(let [base (:base info)
s (:digit-start info)
e (:digit-end info)
string (:string info)
num (:num input)]
(if (< num base)
input
(let [multi (extract-digits num [s e])
solved (solve-1-999 (ret multi ""))
remain (- num (* base multi))
andstr (if (< 0 remain 100) "and " "")
returnstr (str (:s input) (:s solved) " " string " " andstr)]
(ret remain returnstr)))))
;main
(defn num-str [num]
((->
(solve-any (ret num "") millions)
(solve-any thousands)
(solve-any hundreds)
(solve-1-99)) :s))
(reduce + (map count (for [i (range 1 1001)] (string/replace (num-str i) #"[ -]" ""))))
@loganlinn
Copy link

quick tip: destructuring is awesome

(defn solve-any [input info]
  (let [base (:base info)
        s (:digit-start info)
        e (:digit-end info)
        string (:string info)
        num (:num input)]
    ; ...
  ))

can be written as:

(defn solve-any
 [input {:keys [base digit-start digit-end string num]}]
  ; ...
 )  

These are equivalent except for s and e being bound to digit-start and digit-end

Here's a good overview: http://blog.jayfields.com/2010/07/clojure-destructuring.html
There's also a good chapter in Joy of Clojure

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment