Created
February 20, 2013 03:35
-
-
Save jordangarcia/4992656 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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) #"[ -]" "")))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
quick tip: destructuring is awesome
can be written as:
These are equivalent except for
s
ande
being bound todigit-start
anddigit-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