├── .gitignore ├── README.md ├── data ├── oscar_audience_rating.csv └── oscar_critical_rating.csv ├── docker-compose.yml ├── project.clj ├── src-answers └── clojure_katas │ ├── arranged_prob.clj │ ├── count_coin_change.clj │ ├── exponential.clj │ ├── fixed_point.clj │ ├── greatest_common_divisor.clj │ ├── integral.clj │ ├── levenshtein.clj │ ├── max_prime_factor.clj │ ├── nth_fibonacci.clj │ ├── optional │ └── bayesian.clj │ ├── pascal_triangle.clj │ ├── procedural_sum.clj │ ├── reverse_binary.clj │ ├── roman_to_arabic.clj │ ├── sine_angle.clj │ └── square_root.clj ├── src └── clojure_katas │ ├── arranged_prob.clj │ ├── core.clj │ ├── count_coin_change.clj │ ├── exponential.clj │ ├── fixed_point.clj │ ├── greatest_common_divisor.clj │ ├── integral.clj │ ├── levenshtein.clj │ ├── max_prime_factor.clj │ ├── nth_fibonacci.clj │ ├── optional │ └── bayesian.clj │ ├── pascal_triangle.clj │ ├── procedural_sum.clj │ ├── reverse_binary.clj │ ├── roman_to_arabic.clj │ ├── sine_angle.clj │ └── square_root.clj └── test └── clojure_katas ├── arranged_prob_test.clj ├── count_coin_change_test.clj ├── exponential_test.clj ├── fixed_point_test.clj ├── greatest_common_divisor_test.clj ├── integral_test.clj ├── levenshtein_test.clj ├── max_prime_factor_test.clj ├── nth_fibonacci_test.clj ├── optional └── bayesian_test.clj ├── pascal_triangle_test.clj ├── procedural_sum_test.clj ├── reverse_binary_test.clj ├── roman_to_arabic_test.clj ├── sine_angle_test.clj ├── square_root_test.clj └── test_runner.clj /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /lib 3 | /classes 4 | /checkouts 5 | pom.xml 6 | *.jar 7 | *.class 8 | .lein-deps-sum 9 | .lein-failures 10 | .lein-plugins 11 | .lein-repl-history 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Clojure Katas 2 | 3 | This project contains a set of problems to help you get your hands dirty 4 | with Clojure. I hope we can add more problems and treat this as an 5 | ongoing project. 6 | 7 | ## Get started 8 | The project is set up so that you can solve problems one by one. All the 9 | problem skeletons are set up [here](https://github.com/marshallshen/clojure-katas/tree/master/src/clojure_katas), which is the place you can put 10 | your solutions. 11 | 12 | ### Set up your environment 13 | This project runs within [Docker Compose](https://docs.docker.com/compose/), no need to set up additional dependencies! 14 | 15 | ### Run Clojure Katas 16 | 17 | To verify your answer, you can run: 18 | 19 | 20 | $ docker-compose up test 21 | 22 | We also implemented solution manual, to run katas with their solutions; 23 | 24 | 25 | $ docker-compose up answer 26 | 27 | 28 | ## How to practice 29 | ----------------------------- 30 | Say *arranged-prob* is not implemented under `/src/clojure_katas/sine_angle.clj`: 31 | 32 | $ docker-compose up test 33 | Performing task 'run' with profile(s): 'test' 34 | Current kata to tackle: clojure-katas.sine-angle/sine 35 | false 36 | 37 | After *arranged-prob* is implemented, it moves to the next problem: 38 | 39 | Performing task 'run' with profile(s): 'test' 40 | 41 | Testing clojure-katas.sine-angle-test 42 | 43 | Ran 1 tests containing 2 assertions. 44 | 0 failures, 0 errors. 45 | Current kata to tackle: clojure-katas.arranged-prob/prob 46 | false 47 | 48 | ### Example: create a new kata 49 | ------------------------------------------------- 50 | Create `/src-answers/clojure-katas/arranged_prob.clj` for solution. 51 | 52 | ```clojure 53 | (defn prob 54 | "p: total population, 55 | m: total number of sub-category, 56 | n: number of consecutive draws" 57 | [p, m, n] 58 | (if (>= 0 n) 1 59 | (* (double (/ m p)) (prob (- p 1) (- m 1) (- n 1))))) 60 | ``` 61 | Create `/src/clojure-katas/arranged_prob.clj` for problem challenge. 62 | 63 | When using `core/defproblem`, you are **required** to put comments to 64 | describe the problem. 65 | 66 | ```clojure 67 | (ns clojure-katas.arranged-prob 68 | (:require [clojure-katas.core :as core])) 69 | 70 | (core/defproblem prob 71 | "required documentation goes here" 72 | [p, m, n]) 73 | ``` 74 | 75 | Creates test under `/test/clojure-katas/arranged_prob_test.clj` 76 | 77 | ```clojure 78 | (deftest arranged-prob-test 79 | (testing "conditional probability" 80 | (is (= (float 0.12311558) (float (prob 200 100 3)))))) 81 | ``` 82 | 83 | Add *clojure-katas.arranged-prob-test* inside the problemsets defined in [test_runner](https://github.com/marshallshen/clojure-katas/blob/master/test/clojure_katas/test_runner.clj) 84 | 85 | ```clojure 86 | (def problems 87 | '[clojure-katas.sine-angle-test 88 | clojure-katas.arranged-prob-test)) 89 | ``` 90 | 91 | Run through solution to make sure it works: 92 | 93 | $ docker-compose up answer 94 | 95 | ## Look for contributors 96 | We want to keep this project ongoing, if you are interested in helping 97 | out, feel free to: 98 | 99 | 1. Open an issue (I will try to be as responsive as possible! :-)). 100 | 2. Submit a Pull Request (bugfix, or submit a new problem!) 101 | 102 | If you have any questions, feel free to messaage me on Github or Twitter: @marshallshen 103 | 104 | Many thanks to [the contributors](https://github.com/marshallshen/clojure-katas/graphs/contributors), you made this project awesome! 105 | 106 | -------------------------------------------------------------------------------- /data/oscar_audience_rating.csv: -------------------------------------------------------------------------------- 1 | name,rating 2 | Argo,93 3 | Lincoln,85 4 | Silver Linings Playbook,88 5 | Life Of Pi,87 6 | Les Miserables,82 7 | Zero Dark Thirty,82 8 | Django Unchained,94 9 | Beasts Of The Southern Wil,78 10 | Amour,83 -------------------------------------------------------------------------------- /data/oscar_critical_rating.csv: -------------------------------------------------------------------------------- 1 | name,rating 2 | Argo,86 3 | Lincoln,86 4 | Silver Linings Playbook,81 5 | Life Of Pi,79 6 | Les Miserables,63 7 | Zero Dark Thirty,95 8 | Django Unchained,81 9 | Beasts Of The Southern Wil,86 10 | Amour,94 -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | test: 4 | image: clojure:latest 5 | volumes: 6 | - .:/usr/src/clojure-katas 7 | working_dir: /usr/src/clojure-katas 8 | command: bash -c "lein katas-run" 9 | answer: 10 | image: clojure 11 | volumes: 12 | - .:/usr/src/clojure-katas 13 | working_dir: /usr/src/clojure-katas 14 | command: bash -c "lein katas-answers" 15 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject clojure-katas "0.1.0-SNAPSHOT" 2 | :description "A collection exercises solved in Clojure" 3 | :url "http://clojurekatas.org" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[org.clojure/clojure "1.10.0"] 7 | [org.clojure/math.numeric-tower "0.0.4"] 8 | [incanter "1.5.1"]] 9 | :main clojure-katas.core 10 | :profiles {:answers {:source-paths ["src-answers"]}} 11 | :aliases {"katas-run" ["with-profile" "test" "run" "-m" "clojure-katas.test-runner/run-tests"] 12 | "katas-answers" ["with-profile" "test,answers" "run" "-m" "clojure-katas.test-runner/run-tests"]}) 13 | -------------------------------------------------------------------------------- /src-answers/clojure_katas/arranged_prob.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.arranged-prob) 2 | 3 | (defn prob 4 | "p: total population, 5 | m: total number of sub-category, 6 | n: number of consecutive draws" 7 | [p, m, n] 8 | (if (>= 0 n) 1 9 | (* (double (/ m p)) (prob (dec p) (dec m) (dec n))))) -------------------------------------------------------------------------------- /src-answers/clojure_katas/count_coin_change.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.count-coin-change) 2 | 3 | (def coins [1 5 10 25 50]) 4 | 5 | (defn count-coin-change-tree 6 | "Solution 1 build tree recursion 7 | # of ways to change amount a using n kinds of coins = 8 | # of ways to change amount a using all but first kind of coin + 9 | # of ways to change amount a - d, where d is the denomination of the first kind of coin" 10 | [amount, index-of-coin-change] 11 | (loop [amount amount 12 | index index-of-coin-change] 13 | (cond 14 | (zero? amount) 1 15 | (or (neg? amount) (neg? index)) 0 16 | :else (+ (count-coin-change-tree amount (dec index)) 17 | (count-coin-change-tree (- amount (nth coins index)) index))))) -------------------------------------------------------------------------------- /src-answers/clojure_katas/exponential.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.exponential) 2 | 3 | (defn expt-linear 4 | "b^n = b*b^(n-1) 5 | b^0 = 1" 6 | [base index] 7 | {:pre [(not (and (neg? base)(neg? (dec index))))]} 8 | (if (zero? index) 9 | 1N 10 | (* base (expt-linear base (dec index))))) 11 | 12 | (defn expt-fast 13 | "b^n = (b^(n/2))^2 if n is even 14 | b^n = b*b^(n-1) if n is odd" 15 | [base index] 16 | {:pre [(not (and (neg? base)(neg? (dec index))))]} 17 | (let [b base 18 | n index 19 | square (fn [x] (* x x))] 20 | (cond 21 | (zero? index) 22 | 1N 23 | (even? index) 24 | (square (expt-fast b (/ n 2))) 25 | :else 26 | (* b (expt-fast b (dec n)))))) -------------------------------------------------------------------------------- /src-answers/clojure_katas/fixed_point.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.fixed-point 2 | (:require [clojure-katas.core :as core] 3 | [clojure.math.numeric-tower :as math])) 4 | 5 | (defn fixed-point 6 | [f x] 7 | (let [tol 0.0001 8 | close-enough? (fn [v1 v2] ( < (Math/abs (- v1 v2)) tol))] 9 | (loop [v1 x 10 | v2 (f x)] 11 | (if (close-enough? v1 v2) 12 | v2 13 | (recur v2 (f v2)))))) 14 | -------------------------------------------------------------------------------- /src-answers/clojure_katas/greatest_common_divisor.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.greatest-common-divisor) 2 | 3 | (defn gcd 4 | "Euclid algorithm: 5 | GCD(204, 40) = GCD(6, 40) 6 | = GCD(6, 4) 7 | = GCD(4, 2) 8 | = GCD(2, 0)" 9 | [x y] 10 | (if (zero? y) 11 | x 12 | (gcd y (rem x y)))) -------------------------------------------------------------------------------- /src-answers/clojure_katas/integral.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.integral) 2 | 3 | (defn integral 4 | [f a b n] 5 | {:pre [(even? n)(< a b)]} 6 | (let [delta (double (/ (- b a) n))] 7 | (* (double (/ delta 3)) 8 | (+ (f a) 9 | (f b) 10 | (reduce + (map (fn [x] (* 4 x)) (map f (range (+ a delta) (- b delta) (* 2 delta))))) 11 | (reduce + (map (fn [x] (* 2 x)) (map f (range (+ a (* 2 delta))(- b (* 2 delta))(* 2 delta))))))))) -------------------------------------------------------------------------------- /src-answers/clojure_katas/levenshtein.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.levenshtein) 2 | 3 | (defn levenshtein [str1 str2] 4 | (let [len1 (count str1) 5 | len2 (count str2)] 6 | (cond (zero? len1) len2 7 | (zero? len2) len1 8 | :else 9 | (let [cost (if (= (first str1) (first str2)) 0 1)] 10 | (min (inc (levenshtein (rest str1) str2)) 11 | (inc (levenshtein str1 (rest str2))) 12 | (+ cost 13 | (levenshtein (rest str1) (rest str2)))))))) 14 | 15 | -------------------------------------------------------------------------------- /src-answers/clojure_katas/max_prime_factor.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.max-prime-factor) 2 | 3 | ; largest prime factor 4 | ; Euler 3 5 | ; The prime factors of 13195 are 5, 7, 13 and 29. 6 | ; What is the largest prime factor of the number 600851475143 ? 7 | 8 | 9 | ; Pseudo alg 10 | ; Given a number [num], and a ref to save largest prime [div] 11 | ; init div = 2 12 | ; 13 | ; Base cases: 14 | ; if number = div, return number 15 | ; if div > (number)^(1/2), return number (cover square case such as 4) 16 | ; Iterative case: 17 | ; if number can be divided by div, then decrement number by the factor of div, loop 18 | ; if number cannot be divided by div, then increment div by 1, loop 19 | 20 | (defn max-prime-factor 21 | [number] 22 | (loop [number number 23 | div 2] 24 | (cond 25 | (> div (int (Math/sqrt number))) number 26 | (= number div) number 27 | (= 0 (rem number div)) (recur (/ number div) div) 28 | :else (recur number (inc div))))) 29 | 30 | -------------------------------------------------------------------------------- /src-answers/clojure_katas/nth_fibonacci.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.nth-fibonacci) 2 | 3 | (defn nth-fib-tree 4 | "run time: O(2^n), calling itself at each recursion" 5 | [n] 6 | (cond 7 | (neg? n) 0 8 | (zero? n) 1 9 | (= n 1) 1 10 | :else (+ (nth-fib-tree (dec n)) (nth-fib-tree (- n 2))))) 11 | 12 | (defn fib-iter 13 | "x: first start num, 14 | y: second start num, 15 | n: nth iterative, stopping num" 16 | [x y n] 17 | (cond 18 | (neg? n) 0 19 | (zero? n) x 20 | :else (fib-iter (+ x y) x (dec n)))) 21 | 22 | (defn nth-fib-iter 23 | "run time: O(n) iterate n times" 24 | [n] 25 | (fib-iter 1 0 n)) -------------------------------------------------------------------------------- /src-answers/clojure_katas/optional/bayesian.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.bayesian 2 | (:use incanter.core incanter.stats 3 | incanter.io incanter.bayes incanter.charts)) 4 | 5 | (def critical-rating 6 | ($ :rating (read-dataset "./data/oscar_critical_rating.csv" 7 | :header true))) 8 | (def audience-rating 9 | ($ :rating (read-dataset "./data/oscar_audience_rating.csv" 10 | :header true))) 11 | ; assume data 12 | (defn lincoln 13 | [data] 14 | (sel data :cols 1)) 15 | 16 | (defn silver-lining-playbook 17 | [data] 18 | (sel data :cols 2)) 19 | 20 | (defn prior-vec 21 | "Assume prior distribution as uniform distribution. 22 | We assume that each file has equal chance of winning. 23 | Prior vector is a vector with each value 100" 24 | [num-of-vars] 25 | (repeat num-of-vars 100)) 26 | 27 | (defn initial-distr 28 | "multinomial distribution is a generalization of the binomial distribution, 29 | For n independent trails each of which leads to a success for exactly one 30 | of k categories, with each category having a given fixed success probability. 31 | Assign 9 initial values for 9 best picture nominees" 32 | [num-of-vars] 33 | (sample-multinomial-params 1000 (prior-vec num-of-vars))) 34 | 35 | (defn posterior-distr 36 | "Dirichlet distribution is a family of continuous multivariate probability 37 | distributions parameterized by a vector of positive real numbers 38 | the method is quite naive without other factors, it's used for demo, 39 | not necessarily the best modeling :P 40 | 41 | INPUT: vector of expected means for each var from prior distribution, 42 | vector of expected means for each var from likelihood" 43 | [prior-vec, likelihood-vec] 44 | (sample-dirichlet 1000 (plus likelihood-vec prior-vec))) 45 | -------------------------------------------------------------------------------- /src-answers/clojure_katas/pascal_triangle.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.pascal-triangle) 2 | 3 | (defn compute 4 | "Use tree recursion to solve pascal triangle, 5 | it builds up a tree of vars and uneccesarily 6 | builds up a stack in memory, highly ineffective" 7 | [row col] 8 | {:pre [(>= row 0)(>= col 0)]} 9 | (if (or (zero? col) 10 | (= col row)) 11 | 1N 12 | (let [row' (dec row)] 13 | (+ (compute row' (dec col)) 14 | (compute row' col))))) 15 | 16 | (defn compute-alt 17 | "Use iterative recursion to solve pascal triangle, 18 | computes out the triangle as we go, 19 | if row found -> return row[col] 20 | else computes the vals of the current row 21 | stop building 22 | and return the current iterating value for requested 23 | position." 24 | [row col] 25 | (loop [the-row [1N] 26 | at-row 0] 27 | (let [lookup #(if (contains? the-row %)(the-row %) 0)] 28 | (if (= at-row row) 29 | (nth the-row col) 30 | (recur 31 | (mapv (fn [at-col] 32 | (+ (lookup (dec at-col)) 33 | (lookup at-col))) 34 | (range (inc (count the-row)))) 35 | (inc at-row)))))) 36 | 37 | -------------------------------------------------------------------------------- /src-answers/clojure_katas/procedural_sum.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.procedural-sum) 2 | 3 | (defn sum 4 | [f x y] 5 | (reduce + (mapv f (range x (inc y))))) 6 | 7 | (defn sum-integers 8 | [x y] 9 | (sum (fn [x] x) x y)) 10 | 11 | (defn sum-cubes 12 | [x y] 13 | (let [cubes #(* % % %)] 14 | (sum cubes x y))) 15 | 16 | -------------------------------------------------------------------------------- /src-answers/clojure_katas/reverse_binary.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.reverse-binary) 2 | 3 | (defn decimal->binary 4 | [x] 5 | (Integer/toString x 2)) 6 | 7 | (defn binary->decimal 8 | [x] 9 | (Integer/parseInt x 2)) 10 | 11 | (defn reverse-binary 12 | [x] 13 | (-> x 14 | (decimal->binary) 15 | (clojure.string/reverse) 16 | (binary->decimal))) -------------------------------------------------------------------------------- /src-answers/clojure_katas/roman_to_arabic.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.roman-to-arabic) 2 | 3 | (def roman-to-arabic-map 4 | {"I" 1 "V" 5 "X" 10 "L" 50 "C" 100 "D" 500 "M" 1000 5 | "IV" 4 "IX" 9 "XL" 40 "XC" 90 "CM" 900}) 6 | 7 | ; reverse the map keys 8 | (def arabic-to-roman-map 9 | (apply hash-map (mapcat reverse roman-to-arabic-map))) 10 | 11 | ; pseudocode roman->arabic 12 | ; note: the algorithm is based on the data structure of the map 13 | ; we have 1) basic one char inside the map 14 | ; 2) combination of two roman chars 15 | ; 16 | ; Input: a roman char sequence roman-chars = [c1, c2, c3,.. cn] 17 | ; Ouput: a decimal sequence result 18 | ; 19 | ; var result = 0 20 | ; var roman-chars = [c1, c2, c3,... cn] 21 | ; # define a recursion point 22 | ; var nums = arabic value map to current holder [c1, c2] 23 | ; 24 | ; 25 | ; for roman-chars 26 | ; # assign dynamic value holders 27 | ; c1 = first character of roman-chars (from left to right) 28 | ; c2 = second character of roman-chars 29 | ; rest-roman-chars = rest of roman-chars after chopping first 2 characters 30 | ; 31 | ; if rest-roman-chars has less than 2 chars # overall base case 32 | ; if roman-char has only 1 char # sub base case 33 | ; result = result + arabic_value_for_char(roman-char) 34 | ; recur the outer controll loop 35 | ; else # no char left 36 | ; return result 37 | ; NO recur 38 | ; else 39 | ; result = result + (num of string(c1, c2)) 40 | ; recur the outer controll loop 41 | ; end 42 | 43 | (defn roman->arabic 44 | [roman] 45 | (loop [[c1 c2 & rest-roman-chars] roman 46 | arabic 0] 47 | (if-let [num (and c2 (get roman-to-arabic-map (str c1 c2)))] 48 | (recur rest-roman-chars (+ arabic num)) 49 | (if-let [num (get roman-to-arabic-map (str c1))] 50 | (recur (apply str c2 rest-roman-chars)(+ arabic num)) 51 | arabic)))) 52 | 53 | ; Pseudocode arabic to roman 54 | ; Input: an arabic number X, a map of arabic to roman maps, sorted from maximum to minimum 55 | ; Output: a sequence of roman chars 56 | ; 57 | ; assign var roman-sequence = [] 58 | ; 59 | ; for ci in [c1, c2, ... cn] of arabic to roman maps, ordered from max to min 60 | ; if X (left to assign) = 0 # base case 61 | ; return roman-sequence 62 | ; else 63 | ; if X - ci >= 0 64 | ; append ci to the tail of roman-sequence 65 | ; X = X - arabic_val_of(ci) 66 | ; recur 67 | ; else 68 | ; recur 69 | 70 | (defn arabic->roman 71 | [arabic] 72 | (loop [ [num & rest-num :as nums] (reverse (sort (keys arabic-to-roman-map))) 73 | roman "" 74 | arabic arabic] 75 | (if num 76 | (if (>= arabic num) 77 | (recur nums (str roman (get arabic-to-roman-map num))(- arabic num)) 78 | (recur rest-num roman arabic)) 79 | roman))) 80 | -------------------------------------------------------------------------------- /src-answers/clojure_katas/sine_angle.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.sine-angle) 2 | 3 | ; The sine of an angle (specified in radians) can be computed 4 | ; by making use of the approximation sin x x if x is sufficiently small, 5 | ; and the trigonometric identity: 6 | ; sin(r) = 3sin(r/3) -. 4sin^3(r/3) 7 | 8 | (defn sine 9 | [angle] 10 | (if (<= (Math/abs angle) 0.1) 11 | angle 12 | (let [ cube (fn [x](* x (* x x))) 13 | p (fn [x] (- (* 3 x) (* 4 (cube x))))] 14 | (p (sine (/ angle 3.0)))))) -------------------------------------------------------------------------------- /src-answers/clojure_katas/square_root.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.square-root) 2 | 3 | ; Goal: In numerical analysis, Newton's method is a method 4 | ; for finding successively better approximations to the roots 5 | ; of a real-valued function 6 | ; 7 | ; formula 8 | ; goal: x: f(x) = 0 9 | ; x_{1} = x_{0} - f(x_{0}) / f'(x_{0}) 10 | ; x_{n+1} = x_{n} - f(x_{n}) / f'(x_{n}) 11 | 12 | (defn square 13 | [x] 14 | (* x x)) 15 | 16 | (defn average 17 | [x y] 18 | (/ (+ x y) 2)) 19 | 20 | (defn abs 21 | [x] 22 | (if (< x 0) 23 | (- x ) 24 | x)) 25 | 26 | (defn good-enough? 27 | [x guess tol] 28 | (<= (abs (- (square guess) x)) tol)) 29 | 30 | (defn next-guess-for-sqrt 31 | "Constructing next guess based on Netwon formula for square root" 32 | [x guess] 33 | (average guess (/ x guess))) 34 | 35 | (defn sqrt 36 | [x init tol] 37 | (loop [x x 38 | guess init 39 | tol tol] 40 | (if (not (good-enough? x guess tol)) 41 | (recur x (next-guess-for-sqrt x guess) tol) 42 | guess))) -------------------------------------------------------------------------------- /src/clojure_katas/arranged_prob.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.arranged-prob 2 | (:require [clojure-katas.core :as core])) 3 | 4 | ; Original problem source: http://projecteuler.net/problem=100 5 | (core/defproblem prob 6 | "p: total number of chips, 7 | m: total number of blue chips, 8 | n: number of consecutive draws 9 | output: the probability of n consecutive draws of blue chips out of a bucket that has p chips, 10 | m out of p chips are blue 11 | 12 | example: 13 | If a box contains twenty-one coloured discs, composed of 15 blue discs and 6 red discs, 14 | and 2 discs were taken at random, it can be seen that the probability of taking 2 blue discs, P(BB) = (15/21)×(14/20) = 1/2." 15 | [p, m, n]) -------------------------------------------------------------------------------- /src/clojure_katas/core.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.core 2 | "Helpers for writing problems.") 3 | 4 | (defmacro defproblem 5 | [name docstring arglist & body] 6 | {:pre [(string? docstring) (vector? arglist)]} 7 | (if (empty? body) 8 | (throw (ex-info "Unimplemented problem" 9 | {:symbol (symbol (str (.getName *ns*)) 10 | (str name))})) 11 | `(defn ~name ~docstring ~arglist ~@body))) -------------------------------------------------------------------------------- /src/clojure_katas/count_coin_change.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.count-coin-change 2 | (:require [clojure-katas.core :as core])) 3 | 4 | (def coins [1 5 10 25 50]) 5 | 6 | (core/defproblem count-coin-change-tree 7 | " 8 | Reference: SICP 9 | How many different ways can we make change of $1.00, given half-dollars, quarters, nickels, and pennies? 10 | More generally, can we write a procedure to compute the number of ways to change any given amount of money? 11 | 12 | Solution 1 build tree recursion 13 | # of ways to change amount a using n kinds of coins = 14 | # of ways to change amount a using all but first kind of coin + 15 | # of ways to change amount a - d, where d is the denomination of the first kind of coin" 16 | [amount, index-of-coin-change-array]) -------------------------------------------------------------------------------- /src/clojure_katas/exponential.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.exponential 2 | (:require [clojure-katas.core :as core])) 3 | 4 | (core/defproblem expt-linear 5 | "b^n = b*b^(n-1) 6 | b^0 = 1" 7 | [base index]) 8 | 9 | (core/defproblem expt-fast 10 | "b^n = (b^(n/2))^2 if n is even 11 | b^n = b*b^(n-1) if n is odd" 12 | [base index]) 13 | -------------------------------------------------------------------------------- /src/clojure_katas/fixed_point.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.fixed-point 2 | (:require [clojure-katas.core :as core] 3 | [clojure.math.numeric-tower :as math])) 4 | 5 | (core/defproblem fixed-point 6 | "A number x is called a fixed point of a function f 7 | if x satisfies the equation f(x) = x. 8 | 9 | For some functions f we can locate a fixed point 10 | by beginning with an initial guess and applying f repeatedly, 11 | 12 | Algorithm: 13 | (define tolerance 0.0001) 14 | (define (fixed-point f first-guess) 15 | (define (close-enough? v1 v2) 16 | (< (abs (- v1 v2)) tolerance)) 17 | (define (try guess) 18 | (let ((next (f guess))) 19 | (if (close-enough? guess next) 20 | next 21 | (try next)))) 22 | (try first-guess)) 23 | 24 | For practice, let assume tolorance level is 0.0001" 25 | [f x]) -------------------------------------------------------------------------------- /src/clojure_katas/greatest_common_divisor.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.greatest-common-divisor) 2 | 3 | (defn gcd 4 | "Euclid algorithm: 5 | GCD(204, 40) = GCD(6, 40) 6 | = GCD(6, 4) 7 | = GCD(4, 2) 8 | = GCD(2, 0)" 9 | [x y] 10 | (if (zero? y) 11 | x 12 | (gcd y (rem x y)))) -------------------------------------------------------------------------------- /src/clojure_katas/integral.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.integral 2 | (:require [clojure-katas.core :as core])) 3 | 4 | (core/defproblem integral 5 | "compute integral using Simpson's Rule, 6 | the integral of a function f between a and b is approximated as: 7 | h/3*[y_0 + 4y_1 + 2y_2 + 4y_3 + 2y_4 + ... + 2y_{n-2} + 4y_{n-1} + y_n], 8 | where h = (b - a)/n, for some even integer n, and y_{k} = f(a+kh)" 9 | [f a b n]) -------------------------------------------------------------------------------- /src/clojure_katas/levenshtein.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.levenshtein 2 | (:require [clojure-katas.core :as core])) 3 | 4 | (core/defproblem levenshtein 5 | "Compute the amount of difference between two sequences, 6 | also known as edit distance. For example, the edit distance 7 | between kitten and sitten is 1 because we can simply replace 8 | k with s; the edit distance between hi and hit is 1 because 9 | we can remove t at the end of t" 10 | [str1 str2]) 11 | -------------------------------------------------------------------------------- /src/clojure_katas/max_prime_factor.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.max-prime-factor 2 | (:require [clojure-katas.core :as core])) 3 | 4 | (core/defproblem max-prime-factor 5 | " 6 | Base case: 7 | if number = div, return number 8 | if div > (number)^(1/2), return number (cover square case such as 4) 9 | Iterative case: 10 | if number can be divided by div, then decrement number by the factor of div, loop 11 | if number cannot be divided by div, then increment div by 1, loop" 12 | [number]) 13 | 14 | -------------------------------------------------------------------------------- /src/clojure_katas/nth_fibonacci.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.nth-fibonacci 2 | (:require [clojure-katas.core :as core])) 3 | 4 | (core/defproblem nth-fib-tree 5 | "run time: O(2^n), calling itself at each recursion 6 | if n = 0 or n = 1: return 1 7 | else fib(n) = fib(n-1) + fib(n-2)" 8 | [n]) 9 | 10 | (core/defproblem nth-fib-iter 11 | "run time: O(n) iterate n times 12 | x: first start num, 13 | y: second start num, 14 | n: nth iterative, stopping num 15 | each iter: 16 | y <- x + y 17 | x <- y" 18 | [n]) -------------------------------------------------------------------------------- /src/clojure_katas/optional/bayesian.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.bayesian 2 | (:use incanter.core incanter.stats 3 | incanter.io incanter.bayes incanter.charts) 4 | (:require [clojure-katas.core :as core])) 5 | 6 | (def critical-rating 7 | ($ :rating (read-dataset "./data/oscar_critical_rating.csv" 8 | :header true))) 9 | (def audience-rating 10 | ($ :rating (read-dataset "./data/oscar_audience_rating.csv" 11 | :header true))) 12 | ; assume data 13 | (defn lincoln 14 | [data] 15 | (sel data :cols 1)) 16 | 17 | (defn silver-lining-playbook 18 | [data] 19 | (sel data :cols 2)) 20 | 21 | (defn prior-vec 22 | "Assume prior distribution as uniform distribution. 23 | We assume that each file has equal chance of winning. 24 | Prior vector is a vector with each value 100" 25 | [num-of-vars] 26 | (repeat num-of-vars 100)) 27 | 28 | (core/defproblem initial-distr 29 | "multinomial distribution is a generalization of the binomial distribution, 30 | For n independent trails each of which leads to a success for exactly one 31 | of k categories, with each category having a given fixed success probability. 32 | Assign 9 initial values for 9 best picture nominees" 33 | [num-of-vars]) 34 | 35 | (core/defproblem posterior-distr 36 | "Dirichlet distribution is a family of continuous multivariate probability 37 | distributions parameterized by a vector of positive real numbers 38 | the method is quite naive without other factors, it's used for demo, 39 | not necessarily the best modeling :P 40 | 41 | INPUT: vector of expected means for each var from prior distribution, 42 | vector of expected means for each var from likelihood" 43 | [prior-vec, likelihood-vec]) -------------------------------------------------------------------------------- /src/clojure_katas/pascal_triangle.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.pascal-triangle 2 | (:require [clojure-katas.core :as core])) 3 | 4 | (core/defproblem compute 5 | "Use tree recursion to solve pascal triangle, 6 | it builds up a tree of vars and uneccesarily 7 | builds up a stack in memory, highly ineffective" 8 | [row col]) 9 | 10 | (core/defproblem compute-alt 11 | "Use iterative recursion to solve pascal triangle, 12 | computes out the triangle as we go, 13 | if row found -> return row[col] 14 | else computes the vals of the current row 15 | stop building 16 | and return the current iterating value for requested 17 | position." 18 | [row col]) 19 | 20 | -------------------------------------------------------------------------------- /src/clojure_katas/procedural_sum.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.procedural-sum 2 | (:require [clojure-katas.core :as core])) 3 | 4 | (core/defproblem sum-integers 5 | "x: start integer 6 | y: end integer 7 | output: return sum of integer from x to y 8 | 9 | example: (sum-integers 1, 4) > 1 + 2 + 3 + 4 = 10" 10 | [x y]) 11 | 12 | (core/defproblem sum-cubes 13 | "x: start integer 14 | y: end integer 15 | output: return sum of the cube of each integer from x to y 16 | 17 | example: (sum-cubes 1, 4) > 1 + 8 + 27 + 64 = 100" 18 | [x y]) 19 | -------------------------------------------------------------------------------- /src/clojure_katas/reverse_binary.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.reverse-binary 2 | (:require [clojure-katas.core :as core])) 3 | 4 | (core/defproblem compute 5 | "Credit: Spotify Puzzle: http://labs.spotify.com/puzzles/ 6 | Your task will be to write a program for reversing numbers in binary. 7 | For instance, the binary representation of 13 is 1101, 8 | and reversing it gives 1011, which corresponds to number 11. 9 | 10 | The input contains a single line with an integer N, 1 ≤ N ≤ 1000000000. 11 | The output one line with one integer, the number we get by reversing the binary representation of N. 12 | 13 | Sample input 1: 13 14 | Sample output 1: 11 15 | Sample input 2: 47 16 | Sample output 2: 61 17 | " 18 | [num]) 19 | 20 | -------------------------------------------------------------------------------- /src/clojure_katas/roman_to_arabic.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.roman-to-arabic 2 | (:require [clojure-katas.core :as core])) 3 | 4 | (def roman-to-arabic-map 5 | {"I" 1 "V" 5 "X" 10 "L" 50 "C" 100 "D" 500 "M" 1000 6 | "IV" 4 "IX" 9 "XL" 40 "XC" 90 "CM" 900}) 7 | 8 | ; reverse the map keys 9 | (def arabic-to-roman-map 10 | (apply hash-map (mapcat reverse roman-to-arabic-map))) 11 | 12 | (core/defproblem roman->arabic 13 | [roman] 14 | "pseudocode roman->arabic 15 | note: the algorithm is based on the data structure of the map 16 | we have 1) basic one char inside the map 17 | 2) combination of two roman chars 18 | 19 | Input: a roman char sequence roman-chars = [c1, c2, c3,.. cn] 20 | Ouput: a decimal sequence result 21 | 22 | var result = 0 23 | var roman-chars = [c1, c2, c3,... cn] 24 | # define a recursion point 25 | var nums = arabic value map to current holder [c1, c2] 26 | 27 | 28 | for roman-chars 29 | # assign dynamic value holders 30 | c1 = first character of roman-chars (from left to right) 31 | c2 = second character of roman-chars 32 | rest-roman-chars = rest of roman-chars after chopping first 2 characters 33 | 34 | if rest-roman-chars has less than 2 chars # overall base case 35 | if roman-char has only 1 char # sub base case 36 | result = result + arabic_value_for_char(roman-char) 37 | recur the outer controll loop 38 | else # no char left 39 | return result 40 | NO recur 41 | else 42 | result = result + (num of string(c1, c2)) 43 | recur the outer controll loop 44 | end") 45 | 46 | (core/defproblem arabic->roman 47 | [arabic] 48 | "Pseudocode arabic to roman 49 | Input: an arabic number X, a map of arabic to roman maps, sorted from maximum to minimum 50 | Output: a sequence of roman chars 51 | 52 | assign var roman-sequence = [] 53 | 54 | for ci in [c1, c2, ... cn] of arabic to roman maps, ordered from max to min 55 | if X (left to assign) = 0 # base case 56 | return roman-sequence 57 | else 58 | if X - ci >= 0 59 | append ci to the tail of roman-sequence 60 | X = X - arabic_val_of(ci) 61 | recur 62 | else 63 | recur") 64 | -------------------------------------------------------------------------------- /src/clojure_katas/sine_angle.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.sine-angle 2 | (:require [clojure-katas.core :as core])) 3 | 4 | (core/defproblem sine 5 | "The sine of an angle (specified in radians) can be computed 6 | by making use of the approximation sin x x if x is sufficiently small, 7 | and the trigonometric identity: 8 | sin(r) = 3sin(r/3) -. 4sin^3(r/3)" 9 | [angle]) -------------------------------------------------------------------------------- /src/clojure_katas/square_root.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.square-root 2 | (:require [clojure-katas.core :as core])) 3 | 4 | (core/defproblem sqrt 5 | "x: value to be estimated, 6 | init: intial value, 7 | tol: tolerance level 8 | Goal: In numerical analysis, Newton's method is a method 9 | for finding successively better approximations to the roots 10 | of a real-valued function 11 | 12 | formula 13 | goal: x: f(x) = 0 14 | x_{1} = x_{0} - f(x_{0}) / f'(x_{0}) 15 | x_{n+1} = x_{n} - f(x_{n}) / f'(x_{n})" 16 | [x init tol]) 17 | -------------------------------------------------------------------------------- /test/clojure_katas/arranged_prob_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.arranged-prob-test 2 | (:use clojure.test 3 | clojure-katas.arranged-prob)) 4 | 5 | ; original source: Euler problem 100 6 | 7 | (deftest arranged-prob-test 8 | (testing "conditional probability" 9 | ; 100 total chips, 50 blue chips 10 | ; what is the probability of drawing 2 blue chips in a row? 11 | (is (= (float 0.24747474) (float (prob 100 50 2)))) 12 | ; 200 total chips, 10 blue chips 13 | ; what is the probability of drawing 3 blue chips in a row? 14 | (is (= (float 0.12311558) (float (prob 200 100 3)))))) 15 | -------------------------------------------------------------------------------- /test/clojure_katas/count_coin_change_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.count-coin-change-test 2 | (:use clojure.test 3 | clojure-katas.count-coin-change)) 4 | 5 | (deftest coin-to-change-test 6 | (testing "coins are well defined" 7 | (is (= coins [1 5 10 25 50])))) 8 | 9 | (deftest count-coin-change-test 10 | (testing "return number of ways to make changes for a given amount" 11 | (is (= 292 (count-coin-change-tree 100 4))))) -------------------------------------------------------------------------------- /test/clojure_katas/exponential_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.exponential-test 2 | (:use clojure.test 3 | clojure-katas.exponential)) 4 | 5 | (deftest multi-expt-correct 6 | (testing "different algorithm should give same result" 7 | (is (= 8 (expt-linear 2 3))) 8 | (is (= 8 (expt-fast 2 3))))) -------------------------------------------------------------------------------- /test/clojure_katas/fixed_point_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.fixed-point-test 2 | (:use clojure.test 3 | clojure-katas.fixed-point) 4 | (:require [clojure.math.numeric-tower :as math])) 5 | 6 | (deftest fixed-point-test 7 | (testing "approximate val using fixed-point" 8 | (is (= 1.0000846162726942 (fixed-point math/sqrt 4.0))) 9 | (is (= 1.00009823711941 (fixed-point math/sqrt 5.0))))) 10 | -------------------------------------------------------------------------------- /test/clojure_katas/greatest_common_divisor_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.greatest-common-divisor-test 2 | (:use clojure.test 3 | clojure-katas.greatest-common-divisor)) 4 | 5 | (deftest greatest-common-divisor-test 6 | (testing "return GCD of a pair" 7 | (is (= 5 (gcd 75 10))) 8 | (is (= 3 (gcd 9 438))))) 9 | -------------------------------------------------------------------------------- /test/clojure_katas/integral_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.integral-test 2 | (:use clojure.test 3 | clojure-katas.integral)) 4 | 5 | (deftest integral-test 6 | (testing "approximate integral of a function" 7 | (is (= 0.23078806666666699 (integral (fn [x] (* x x x)) 0 1 100))) 8 | (is (= 0.24800798800666718 (integral (fn [x] (* x x x)) 0 1 1000))))) -------------------------------------------------------------------------------- /test/clojure_katas/levenshtein_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.levenshtein-test 2 | (:use clojure.test 3 | clojure-katas.levenshtein)) 4 | 5 | (deftest levenshtein-test 6 | (testing "return edit distance between two strings" 7 | (is (= 3 (levenshtein "kitten" "sitt"))))) 8 | 9 | -------------------------------------------------------------------------------- /test/clojure_katas/max_prime_factor_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.max-prime-factor-test 2 | (:use clojure.test 3 | clojure-katas.max-prime-factor)) 4 | 5 | (deftest max-prime-factor-test 6 | (testing "return the maximum prime factor for an integer" 7 | (is (= 13 (max-prime-factor 78))) 8 | (is (= 5 (max-prime-factor 10))) 9 | (is (= 29 (max-prime-factor 13195))) 10 | (is (= 6857 (max-prime-factor 600851475143))))) -------------------------------------------------------------------------------- /test/clojure_katas/nth_fibonacci_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.nth-fibonacci-test 2 | (:use clojure.test 3 | clojure-katas.nth-fibonacci)) 4 | 5 | (deftest nth-fibonacci-tree-test 6 | (testing "return nth fibonacci number, using tree recursion" 7 | (is (= 0 (nth-fib-tree -100))) 8 | (is (= 1 (nth-fib-tree 0))) 9 | (is (= 1 (nth-fib-tree 1))) 10 | (is (= 2 (nth-fib-tree 2))) 11 | (is (= 3 (nth-fib-tree 3))) 12 | (is (= 5 (nth-fib-tree 4))) 13 | (is (= 8 (nth-fib-tree 5))))) 14 | 15 | (deftest nth-fibonacci-iter-test 16 | (testing "return nth fibonacci number, using iterative recursion" 17 | (is (= 0 (nth-fib-iter -100))) 18 | (is (= 1 (nth-fib-iter 0))) 19 | (is (= 1 (nth-fib-iter 1))) 20 | (is (= 2 (nth-fib-iter 2))) 21 | (is (= 3 (nth-fib-iter 3))) 22 | (is (= 5 (nth-fib-iter 4))) 23 | (is (= 8 (nth-fib-iter 5))))) 24 | -------------------------------------------------------------------------------- /test/clojure_katas/optional/bayesian_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.bayesian-test 2 | (:use clojure.test 3 | clojure-katas.bayesian 4 | incanter.core incanter.stats 5 | incanter.io incanter.bayes)) 6 | 7 | (def simple-dataset 8 | (to-dataset [{:a 1 :b 2} {:a 1 :b 2}])) 9 | 10 | (deftest incanter-basics 11 | (testing "basic uage of incanter using simple dataset" 12 | (is (= [:a :b] (col-names simple-dataset))) 13 | (is (= [3 3] ($map #(+ %1 %2) [:a :b] simple-dataset))))) 14 | 15 | ; test reading dataset 16 | ; implenmentation detail in src/clojure_katas/bayesian.clj 17 | (deftest incanter-read-dataset 18 | (testing "reading data using incanter" 19 | (is (= [86 86 81 79 63 95 81 86 94] critical-rating)) 20 | (is (= [93 85 88 87 82 82 94 78 83] audience-rating)))) 21 | 22 | ; in initial distribution, each movie is equally likely 23 | ; to win best picture because we assume no knowledge about 24 | ; the distribution. 25 | ; therefore, each file should have E(x) ~= 0.11 26 | (deftest test-initial-distr 27 | (testing "make sure we start with uniform distribution" 28 | (is (< 0.10 (mean (lincoln (initial-distr 9))))) 29 | (is (> 0.12 (mean (lincoln (initial-distr 9))))) 30 | (is (< 0.10 (mean (silver-lining-playbook (initial-distr 9))))) 31 | (is (> 1.12 (mean (silver-lining-playbook (initial-distr 9))))))) 32 | 33 | (deftest posterior-after-critical 34 | (testing "probability for candidate change after critical rating" 35 | (is (>= 0.1 (first (quantile (lincoln (posterior-distr (prior-vec 9) critical-rating)) :probs [0.025 0.975])))) 36 | (is (<= 0.12 (last (quantile (lincoln (posterior-distr (prior-vec 9) critical-rating)) :probs [0.025 0.975])))) 37 | (is (>= 0.1 (first (quantile (silver-lining-playbook (posterior-distr (prior-vec 9) critical-rating)) :probs [0.025 0.975])))) 38 | (is (<= 0.12 (last (quantile (silver-lining-playbook (posterior-distr (prior-vec 9) critical-rating)) :probs [0.025 0.975])))))) 39 | 40 | -------------------------------------------------------------------------------- /test/clojure_katas/pascal_triangle_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.pascal-triangle-test 2 | (:use clojure.test 3 | clojure-katas.pascal-triangle)) 4 | 5 | (deftest pascal-triangle-test 6 | (testing "return elem of a pascal triangle" 7 | (is (= 1 (compute 0 0))) 8 | (is (= 15504N (compute 20 5))))) 9 | 10 | (deftest pascal-triangle-test-alt 11 | (testing "return elem after building the triangle" 12 | (is (= 1 (compute-alt 0 0))) 13 | (is (= 15504N (compute-alt 20 5))))) -------------------------------------------------------------------------------- /test/clojure_katas/procedural_sum_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.procedural-sum-test 2 | (:use clojure.test 3 | clojure-katas.procedural-sum)) 4 | 5 | (deftest sum-integers-test 6 | (testing "sum between two integers" 7 | (is (= 10 (sum-integers 1 4))))) 8 | 9 | (deftest sum-cubes-test 10 | (testing "sum cubes between two integers" 11 | (is (= 3025 (sum-cubes 1 10))))) -------------------------------------------------------------------------------- /test/clojure_katas/reverse_binary_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.reverse-binary-test 2 | (:use clojure.test 3 | clojure-katas.reverse-binary)) 4 | 5 | ; original source: Spotify Puzzles 6 | ;http://labs.spotify.com/puzzles/ 7 | (deftest reverse-binary-test 8 | (testing "reverse binary" 9 | (is (= 11 (compute 13)) 10 | (is (= 61 (compute 47)))))) 11 | -------------------------------------------------------------------------------- /test/clojure_katas/roman_to_arabic_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.roman-to-arabic-test 2 | (:use clojure.test 3 | clojure-katas.roman-to-arabic)) 4 | 5 | (deftest roman-to-arabic-basics 6 | (testing "roman to arabic basics" 7 | (is (= 1 (roman->arabic "I"))) 8 | (is (= 5 (roman->arabic "V"))))) 9 | 10 | (deftest roman-to-arabic-advanced 11 | (testing "roman to arabic addtions" 12 | (is (= 2 (roman->arabic "II"))) 13 | (is (= 7 (roman->arabic "VII"))) 14 | (is (= 31 (roman->arabic "XXXI"))) 15 | (is (= 900 (roman->arabic "CM"))) 16 | (is (= 1979 (roman->arabic "MCMLXXIX"))))) 17 | 18 | (deftest arabic-to-roman-basics 19 | (testing "arabic to roman basics" 20 | (is (= "I" (arabic->roman 1))) 21 | (is (= "V" (arabic->roman 5))) 22 | (is (= "X" (arabic->roman 10))))) 23 | 24 | (deftest arabic-to-roman-advanced 25 | (testing "arabic to roman advanced" 26 | (is (= "II" (arabic->roman 2))) 27 | (is (= "VII" (arabic->roman 7))) 28 | (is (= "XXXI" (arabic->roman 31))) 29 | (is (= "CM" (arabic->roman 900))) 30 | (is (= "MCMLXXIX" (arabic->roman 1979))))) -------------------------------------------------------------------------------- /test/clojure_katas/sine_angle_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.sine-angle-test 2 | (:use clojure.test 3 | clojure-katas.sine-angle)) 4 | 5 | (deftest sine-angle-test 6 | (testing "approximate sine of an angle close enough" 7 | (is (= 0.1 (sine 0.1))) 8 | (is (= -0.39980345741334 (sine 12.15))))) -------------------------------------------------------------------------------- /test/clojure_katas/square_root_test.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.square-root-test 2 | (:use clojure.test 3 | clojure-katas.square-root)) 4 | 5 | (deftest square-root-test 6 | (testing "approximate square root with 0.001 tolerance" 7 | (is (<= 3.16 (sqrt 10.0 3.0 0.001))) 8 | (is (>= 3.17 (sqrt 10.0 3.0 0.001))))) -------------------------------------------------------------------------------- /test/clojure_katas/test_runner.clj: -------------------------------------------------------------------------------- 1 | (ns clojure-katas.test-runner 2 | (:require [clojure.test :as t])) 3 | 4 | (def problems 5 | '[clojure-katas.sine-angle-test 6 | clojure-katas.arranged-prob-test 7 | clojure-katas.exponential-test 8 | clojure-katas.nth-fibonacci-test 9 | clojure-katas.greatest-common-divisor-test 10 | clojure-katas.reverse-binary-test 11 | clojure-katas.max-prime-factor-test 12 | clojure-katas.pascal-triangle-test 13 | clojure-katas.count-coin-change-test 14 | clojure-katas.procedural-sum-test 15 | clojure-katas.square-root-test 16 | clojure-katas.integral-test 17 | clojure-katas.fixed-point-test 18 | clojure-katas.roman-to-arabic-test 19 | clojure-katas.levenshtein-test]) 20 | 21 | (defn run-tests 22 | [] 23 | (try 24 | (loop [nses problems] 25 | (when-let [[ns & more] nses] 26 | (and (try 27 | (require ns) 28 | true ; continue 29 | (catch Exception e 30 | (let [mapped-ex (Throwable->map e)] 31 | (if (and 32 | (= "Unimplemented problem" (:cause mapped-ex)) 33 | (contains? (:data mapped-ex) :symbol)) 34 | (let [sym (-> mapped-ex :data :symbol)] 35 | (println "Current kata to tackle: " sym) 36 | false ; don't continue 37 | ) 38 | (throw e))))) 39 | (let [{:keys [error fail]} (t/run-tests ns)] 40 | (= 0 error fail)) 41 | (recur more)))))) 42 | --------------------------------------------------------------------------------