Anagram

Other "Anagram" solutions.
(ns anagram
  (:require [clojure.string :refer [lower-case]]))

(defn is-anagram? [word1 word2]
  (let [w1 (lower-case word1)
        w2 (lower-case word2)
        different-words? (not= w1 w2)
        anagrams? (= (sort w1) (sort w2))]
    (and
     different-words?
     anagrams?)))

(defn anagrams-for [word prospect-list]
  (filter #(is-anagram? word %) prospect-list))

Armstrong Numbers

Other "Armstrong Numbers" solutions.
(ns armstrong-numbers)

(defn digits [num]
  (map #(Character/digit % 10) (str num)))

(defn expt [x n]
  (reduce * (repeat n x)))

(defn armstrong? [n]
  (= n
    (reduce +
      (map
        (fn [x] (expt x (count (str n))))
        (digits n)))))

Beer Song

Other "Beer Song" solutions.
(ns beer-song
  (:require [clojure.string :as str]))

(defn- generalised-verse [num]
  (format
   "%s bottles of beer on the wall, %s bottles of beer.\nTake one down and pass it around, %s bottles of beer on the wall.\n"
   num
   num
   (dec num)))

(defn verse
  "Returns the nth verse of the song."
  ([num]
   (case num
     0 "No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n"
     1 "1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n"
     2 "2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n"
     (generalised-verse num))))

(defn sing
  "Given a start and an optional end, returns all verses in this interval. If
  end is not given, the whole song from start is sung."
  ([start] (sing start 0))
  ([start end] (str/join "\n"
                         (->>
                          (range start (dec end) -1)
                          (map verse)))))

Binary Search

Other "Binary Search" solutions.
(ns binary-search)

(defn middle [coll]
  (quot (count coll) 2))

(defn search-for [item coll]
  (let [idx (middle coll)
        middle-value (nth coll idx)
        not-found-error (Exception. "not found")]
    (cond
      (= item middle-value) idx
      (= 1 (count coll)) (throw not-found-error)
      (< item middle-value) (search-for item (take idx coll))
      :else (+ idx (search-for item (drop idx coll))))))

Bob

Other "Bob" solutions.
(ns bob
  (:require [clojure.string :refer [blank? ends-with? trim]]))

(defn is-question [s]
  (ends-with? s "?"))

(defn is-yelling [s]
  (let [alphas (filter #(Character/isLetter %) s)]
    (and
     (not-empty alphas)
     (every?
      #(Character/isUpperCase %)
      alphas))))

(defn response-for
  [input]
  (let [s (trim input)]
    (cond
      (blank? s) "Fine. Be that way!"
      (and (is-yelling s) (is-question s)) "Calm down, I know what I'm doing!"
      (is-question s) "Sure."
      (is-yelling s) "Whoa, chill out!"
      :else "Whatever.")))

Cars Assemble

Other "Cars Assemble" solutions.
(ns cars-assemble)

(def cars-per-hr 221)

(defn production-rate
  "Returns the assembly line's production rate per hour,
   taking into account its success rate"
  [speed]
  (let [success-rate (cond (= speed 10) 0.77
                           (= speed 9) 0.8
                           (>= speed 5) 0.9
                           :else 1.0)
        base-rate (* speed cars-per-hr)]
    (* base-rate success-rate)))

(defn working-items
  "Calculates how many working cars are produced per minute"
  [speed]
  (let [minute-rate (/ (production-rate speed) 60)]
    (int minute-rate)))

Collatz Conjecture

Other "Collatz Conjecture" solutions.
(ns collatz-conjecture)

(defn- next-collatz-num [num]
  (if
   (even? num)
    (/ num 2)
    (+ 1 (* num 3))))

(defn- collatz-support [step-count num]
  (cond
    (= num 1) step-count
    :else (let [next-num (next-collatz-num num)]
            (collatz-support (+ 1 step-count) next-num))))

(defn collatz [num]
  {:pre [(< 0 num)]}
  (collatz-support 0 num))

Hello World

Other "Hello World" solutions.
(ns hello-world)

(defn hello [] "Hello, World!")

Isbn Verifier

Other "Isbn Verifier" solutions.
(ns isbn-verifier
  (:require [clojure.string :as str]))

(defn sanitize-isbn [isbn]
  (let [lowered (str/lower-case isbn)
        sanitized (remove #(= \- %)
                          (butlast lowered))]
    (concat sanitized [(last lowered)])))

(defn parse-isbn [sanitized]
  (map (fn [c] (if (= \x c)
                 10
                 (Character/digit c 10))) sanitized))

(defn verify-isbn [parsed-isbn]
  (let [len (count parsed-isbn)
        formula-result (->> (range 0 len)
                            (map
                             (fn [i] (nth parsed-isbn i) * (- len i)))
                            (reduce +))]
    (= 0 (mod formula-result 11))))

(defn isbn? [isbn]
  (let [sanitized (sanitize-isbn isbn)
        valid-length? (= 10 (count sanitized))
        valid-structure? (every? #(Character/isDigit %) (take 9 sanitized))
        valid-check-digit? (let [check-digit (last sanitized)]
                             (or (= \x check-digit) (Character/isDigit check-digit)))
        valid-input? (and valid-length? valid-structure? valid-check-digit?)
        parsed (parse-isbn sanitized)]
    (and valid-input? (verify-isbn parsed))))


(isbn? "3-598-21507-X")

Lucians Luscious Lasagna

Other "Lucians Luscious Lasagna" solutions.
;; 👋🏽 Hi there! Welcome to the Clojure Track.
;; The online test-runner is powered by babashka and the Small Clojure Interpreter (SCI).
;; Almost all language features are supported, with the exception of low-level constructs
;; like `deftype`, and certain Java classes. For more info, see:
;; https://github.com/babashka/babashka#differences-with-clojure

(ns lucians-luscious-lasagna)

(def expected-time 40)

(defn remaining-time
  "Takes the actual time in minutes the lasagna has been in the oven,
   and returns how many minutes the lasagna still has to remain in the oven."
  [actual-time]
  (- expected-time actual-time))

(defn prep-time
  "Takes the number of layers added to the lasagna,
   and returns how many minutes you spent preparing the lasagna"
  [num-layers]
  (* 2 num-layers))

(defn total-time
  "Takes the number of layers of lasagna and the actual time in minutes it has been in the oven.
   Returns how many minutes in total you've worked on cooking the lasagna"
  [num-layers actual-time]
  (+ (prep-time num-layers) actual-time))

Pov

Other "Pov" solutions.
(ns pov)

(defn of [node tree]
  tree)

(defn path-from-to [])

Raindrops

Other "Raindrops" solutions.
(ns raindrops)

(defn- substitute-factors-with [n substitutions]
  (let [factors (sort (keys substitutions))
        converted (map
                   (fn [factor]
                     (if (= 0 (mod n factor))
                       (get substitutions factor)
                       ""))
                   factors)
        s (apply str converted)]
    (if (empty? s)
      (str n)
      s)))

(defn convert [n]
  (substitute-factors-with n {3 "Pling"
                              5 "Plang"
                              7 "Plong"}))

Reverse String

Other "Reverse String" solutions.
(ns reverse-string)

(defn reverse-string [s]
  (let [reversed-chars (into () s)] ;; https://clojuredocs.org/clojure.core/into
  (apply str reversed-chars)))

Rna Transcription

Other "Rna Transcription" solutions.
;; Given a DNA strand, return its RNA complement (per RNA transcription) .

;; Both DNA and RNA strands are a sequence of nucleotides.

;; The four nucleotides found in DNA are adenine (A), cytosine (C), guanine (G) and thymine (T).
;; The four nucleotides found in RNA are adenine (A), cytosine (C), guanine (G) and uracil (U).
(ns rna-transcription)

(defn to-rna [dna]
  (let [dna-to-rna (fn [n] (condp = n
                             \G \C
                             \C \G
                             \T \A
                             \A \U
                             (assert false (format "%s is not a valid nucleotide" n))))]
    (apply str (map dna-to-rna dna))))

Roman Numerals

Other "Roman Numerals" solutions.
(ns roman-numerals)

(def romans [[1000 "M"]
             [900 "CM"]
             [500 "D"]
             [400 "CD"]
             [100 "C"]
             [90 "XC"]
             [50 "L"]
             [40 "XL"]
             [10 "X"]
             [9 "IX"]
             [5 "V"]
             [4 "IV"]
             [1 "I"]])

(defn numerals [n]
  (loop [result []
         remaining n
         [[n roman] & rst] romans]
    (if (zero? remaining)
      (apply str result)
      (if (>= remaining n)
        (recur (conj result roman) (- remaining n) romans)
        (recur result remaining rst)))))

Run Length Encoding

Other "Run Length Encoding" solutions.
(ns run-length-encoding)

(defn run-length-encode
  "encodes a string with run-length-encoding"
  [plain-text]
  (apply str (map (fn [chars]
                    (if (= (count chars) 1)
                      (apply str chars)
                      (str (count chars) (first chars))))
                  (partition-by identity plain-text))))

(defn run-length-decode
  "decodes a run-length-encoded string"
  [cipher-text]
  (let [grouped (partition-by #(Character/isDigit %) cipher-text)
        digit-char-pairs (partition 2 grouped)
        encoded? (< 2 (count digit-char-pairs))
        decode (apply str
                      (map (fn [[digits [c & cs]]]
                             (let [n (Integer/parseInt (apply str digits))]
                               (apply str
                                      (flatten (cons (repeat n c) cs)))))
                           digit-char-pairs))]
    (if encoded?
      decode
      cipher-text)))

Say

Other "Say" solutions.
(ns say
  (:require [clojure.string :refer [join]]))

(def translations {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"})

(def magnitudes
  [[1000000000 "billion"]
   [1000000    "million"]
   [1000       "thousand"]
   [100        "hundred"]])

(defn- next-magnitude
  [num]
  (first
   (drop-while
    (fn [[val _]] (> val num))
    magnitudes)))

(defn- say-compound-word
  [num]
  (let [small (rem num 10)
        big (- num small)
        components (filter not-empty (map translations [big small]))]
    (join "-" components)))

(defn- say
  [num]
  (cond
    (contains? translations num) (translations num)
    (< num 100) (say-compound-word num)
    :else (let [[magnitude magnitude-word] (next-magnitude num)
                quantity (long (/ num magnitude))
                remainder (rem num magnitude)
                components [(say quantity) magnitude-word (say remainder)]
                filtered-components (filter
                                     not-empty
                                     components)]
            (join " " filtered-components))))


;;; EXPORTS


;;; Translate a number in the range 0-999999999999 to english
(defn number
  [num]
  {:pre  [(>= num 0)
          (< num 999999999999)]}
  (if (= num 0)
    "zero"
    (say num)))

Series

Other "Series" solutions.
(ns series)

(defn slices [s slice-length]
  (let [sliceable (> slice-length 0)
        sliced (map
                #(apply str %)
                (partition slice-length 1 s))]
    (if sliceable sliced [""])))

Two Fer

Other "Two Fer" solutions.
(ns two-fer)

(defn two-fer
  ([] (two-fer "you"))
  ([name] (format "One for %s, one for me." (or name "you"))))

Word Count

Other "Word Count" solutions.
(ns word-count
  (:require [clojure.string :refer [split lower-case]]))

(defn word-count [s]
  (let [words (split (lower-case s) #" ")
        grouped-words (group-by identity words)]
    (zipmap
     (keys grouped-words)
     (map count (vals grouped-words)))))