exercism / clojure

Exercism exercises in Clojure.
https://exercism.org/tracks/clojure
MIT License
160 stars 155 forks source link

Building a training set of tags for clojure #590

Closed ErikSchierboom closed 9 months ago

ErikSchierboom commented 10 months ago

Hello lovely maintainers :wave:

We've recently added "tags" to student's solutions. These express the constructs, paradigms and techniques that a solution uses. We are going to be using these tags for lots of things including filtering, pointing a student to alternative approaches, and much more.

In order to do this, we've built out a full AST-based tagger in C#, which has allowed us to do things like detect recursion or bit shifting. We've set things up so other tracks can do the same for their languages, but its a lot of work, and we've determined that actually it may be unnecessary. Instead we think that we can use machine learning to achieve tagging with good enough results. We've fine-tuned a model that can determine the correct tags for C# from the examples with a high success rate. It's also doing reasonably well in an untrained state for other languages. We think that with only a few examples per language, we can potentially get some quite good results, and that we can then refine things further as we go.

I released a new video on the Insiders page that talks through this in more detail.

We're going to be adding a fully-fledged UI in the coming weeks that allow maintainers and mentors to tag solutions and create training sets for the neural networks, but to start with, we're hoping you would be willing to manually tag 20 solutions for this track. In this post we'll add 20 comments, each with a student's solution, and the tags our model has generated. Your mission (should you choose to accept it) is to edit the tags on each issue, removing any incorrect ones, and add any that are missing. In order to build one model that performs well across languages, it's best if you stick as closely as possible to the C# tags as you can. Those are listed here. If you want to add extra tags, that's totally fine, but please don't arbitrarily reword existing tags, even if you don't like what Erik's chosen, as it'll just make it less likely that your language gets the correct tags assigned by the neural network.


To summarise - there are two paths forward for this issue:

  1. You're up for helping: Add a comment saying you're up for helping. Update the tags some time in the next few days. Add a comment when you're done. We'll then add them to our training set and move forward.
  2. You not up for helping: No problem! Just please add a comment letting us know :)

If you tell us you're not able/wanting to help or there's no comment added, we'll automatically crowd-source this in a week or so.

Finally, if you have questions or want to discuss things, it would be best done on the forum, so the knowledge can be shared across all maintainers in all tracks.

Thanks for your help! :blue_heart:


Note: Meta discussion on the forum

ErikSchierboom commented 10 months ago

Exercise: bob

Code

(ns bob)

(defn question?
  "A string terminated with a question mark is a question."
  [s]
  (clojure.string/ends-with? s "?"))

(defn yell?
  "A string whose letters are all caps is a yell."
  [s]
  (let [letters (clojure.string/replace s #"[^a-zA-Z]" "")]
    (and (not= letters "") (= letters (clojure.string/upper-case letters)))))

(defn silence?
  "A string containing only whitespace is silence."
  [s]
  (clojure.string/blank? s))

(defn response-for
  "Returns Bob's response to s."
  [s]
  (cond
    (question? s) (if (yell? s) "Calm down, I know what I'm doing!" "Sure.")
    (yell? s) "Whoa, chill out!"
    (silence? s) "Fine. Be that way!"
    :else "Whatever."))

Tags:

construct:and
construct:boolean
construct:char
construct:clojure-namespaced-keyword
construct:clojure-reader-macro
construct:clojure-string
construct:cond
construct:definition
construct:fn
construct:if
construct:invocation
construct:keyword
construct:let
construct:method
construct:parameter
construct:regex
construct:string
construct:symbol
construct:throw
construct:vector
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:boolean-logic
technique:exceptions
technique:regular-expression
uses:Regex
ErikSchierboom commented 10 months ago

Exercise: anagram

Code

(ns anagram)

(defn anagrams-for [word prospect-list] ;; <- arglist goes here
  (let [lower-word (clojure.string/lower-case word)
        sorted-word (sort lower-word)
        filtered-list (filter #(not= lower-word %) prospect-list)]
    (filter
      #(= sorted-word (sort (clojure.string/lower-case %)))
      filtered-list))
)

Tags:

construct:clojure
construct:defn
construct:filter
construct:function
construct:invocation
construct:let
construct:list
construct:parameter
construct:string
construct:vector
paradigm:functional
paradigm:declarative
uses:clojure.string/lower-case
uses:filter
uses:higher-order-functions
uses:let
ErikSchierboom commented 10 months ago

Exercise: anagram

Code

(ns anagram)

(defn is-anagram? [searched-word searched-word-frequencies current-word]
  (let [prep-current-word (clojure.string/lower-case current-word) ]
    (and (not= current-word searched-word)
         (= (frequencies prep-current-word) searched-word-frequencies))))

(defn anagrams-for [word prospect-list] ;; <- arglist goes here
  (let [searched-word (clojure.string/lower-case word)
        searched-word-frequencies (frequencies searched-word)]
    (filter #(is-anagram? searched-word searched-word-frequencies %) prospect-list)))

Tags:

construct:and
construct:clojure-namespace
construct:comment
construct:defn
construct:filter
construct:function
construct:invocation
construct:let
construct:local-name
construct:parameter
construct:string
construct:underscore
construct:variable
paradigm:functional
paradigm:logical
technique:boolean-logic
technique:higher-order-functions
ErikSchierboom commented 10 months ago

Exercise: anagram

Code

(ns anagram
   (:require [clojure.string :as str]))

(defn fixit [s] 
  (str/join (sort (str/lower-case s))))

(defn anagrams-for [word prospect-list] 
   (->> prospect-list
        (filter #(and (not= (str/lower-case word)(str/lower-case %)) 
                      (= (fixit word) (fixit %)))))) 

Tags:

construct:boolean
construct:clojure
construct:defn
construct:function
construct:higher-order-function
construct:invocation
construct:keyword
construct:list
construct:local
construct:namespace
construct:parameter
construct:require
construct:string
construct:varargs
paradigm:functional
paradigm:imperative
paradigm:logical
paradigm:object-oriented
paradigm:reflective
technique:boolean-logic
technique:higher-order-functions
ErikSchierboom commented 10 months ago

Exercise: grade-school

Code

(ns grade-school)

(defn grade
  "Return a vector of students' names in a school grade"
  [school grade]
  {:pre [(map? school)
         (int? grade)]}
  (or (school grade) [])
)

(defn add
  "Add a student's name to their school class"
  [school name grade]
  {:pre [(map? school)
         (string? name)
         (int? grade)]}
  (let [old-students (school grade)
        new-students (apply vector (set (conj old-students name)))]
    (assoc school grade new-students)))

(defn sorted
  "Return a school sorted by grade"
  [school]
  {:pre [(map? school)]}
  (into (sorted-map) school))

Tags:

construct:apply
construct:assoc
construct:boolean
construct:conj
construct:defn
construct:doc-string
construct:implicit-parameters
construct:int
construct:int?
construct:invocation
construct:keyword
construct:let
construct:map
construct:map?
construct:name
construct:or
construct:parameter
construct:set
construct:set?
construct:string
construct:vector
construct:visibility-modifiers
paradigm:functional
paradigm:reflective
technique:boolean-logic
technique:higher-order-functions
uses:SortedMap
uses:SortedSet
ErikSchierboom commented 10 months ago

Exercise: complex-numbers

Code

(ns complex-numbers
  (:require [clojure.math.numeric-tower :as math]))

(defn real [[a b]]
  a)

(defn imaginary [[a b]]
  b)

(defn abs [[a b]]
  (float (math/sqrt (+ (* a a) (* b b)))))

(defn conjugate [[a b]]
  [a (- b)])

(defn add [[a b] [c d]]
  [(+ a c) (+ b d)])

(defn sub [[a b] [c d]]
  [(- a c) (- b d)])

(defn mul [[a b] [c d]]
  [(- (* a c) (* b d)) (+ (* a d) (* b c))])

(defn div [num1 num2]
  (let [[new-a new-b] (mul num1 (conjugate num2))
        [c d] num2
        num2-abs-squared (+ (* c c) (* d d))]
    [(float (/ new-a num2-abs-squared))
     (float (/ new-b num2-abs-squared))]))
    ;; [(/ new-a num2-abs-squared)
    ;;   (/ new-b num2-abs-squared)]))

Tags:

construct:as
construct:comment
construct:definition
construct:divide
construct:double
construct:float
construct:floating-point-number
construct:invocation
construct:let
construct:local-name
construct:method
construct:multiply
construct:namespace
construct:number
construct:parameter
construct:require
construct:vector
paradigm:functional
paradigm:imperative
paradigm:object-oriented
technique:basic-arithmetic
uses:vector
ErikSchierboom commented 10 months ago

Exercise: flatten-array

Code

(ns flatten-array)

(defn flatten [arr]
  (loop [from arr
         to []]
    (if (empty? from)
      to
      (let [x (first from)
            xs (rest from)]
        (cond
          (nil? x) (recur xs to)
          (coll? x) (recur (concat x xs) to)
          :default (recur xs (conj to x)))))))

Tags:

construct:clojure-assignment
construct:clojure-char
construct:clojure-cond
construct:clojure-construct
construct:clojure-defn
construct:clojure-if
construct:clojure-invocation
construct:clojure-keyword
construct:clojure-let
construct:clojure-loop
construct:clojure-parameter
construct:clojure-recur
construct:clojure-string
construct:clojure-symbol
construct:clojure-throw
construct:clojure-vector
construct:clojure-when
construct:let
construct:loop
construct:parameter
construct:throw
construct:vector
paradigm:imperative
paradigm:functional
technique:exceptions
technique:looping
ErikSchierboom commented 10 months ago

Exercise: flatten-array

Code

(ns flatten-array
  (:refer-clojure :exclude [flatten]))

(defn flatten
  "return a vector of a collection, flattened and with nils removed"
  [arr]
  {:pre [(coll? arr)]}
  (->> arr
       (clojure.core/flatten)
       (filter identity)
       (vec)))

Tags:

construct:clojure.core/->>
construct:clojure.core/defn
construct:clojure.core/doc
construct:clojure.core/implicit-args
construct:clojure.core/keyword
construct:clojure.core/ns
construct:clojure.core/vector
construct:clojure.core/nil
construct:clojure.core/parameter-spec
construct:clojure.core/reader-conditional
construct:clojure.core/set
construct:clojure.core/special-symbol
construct:clojure.core/symbol
construct:clojure.core/throw
construct:clojure.core/vector
construct:clojure.core/visibility
construct:clojure.lang.PersistentVector
construct:invocation
construct:throw
construct:vector
paradigm:functional
paradigm:imperative
paradigm:metaprogramming
paradigm:throwing-exceptions
technique:exceptions
ErikSchierboom commented 10 months ago

Exercise: gigasecond

Code

(ns gigasecond
  (:require [clj-time.core :as t]))

(defn flip [f]
  (fn [& xs]
    (apply f (reverse xs))))

(def plus (flip t/plus))
(def gigaseconds (t/seconds 1e9))

(defn from [y m d] 
   (->> (t/date-time y m d) 
        (plus gigaseconds)
        ((juxt t/year t/month t/day))))

Tags:

construct:apply
construct:date-time
construct:defn
construct:double
construct:invocation
construct:juxt
construct:method
construct:multiply
construct:namespace
construct:number
construct:parameter
construct:require
construct:varargs
paradigm:functional
paradigm:higher-order-functions
uses:clj-time.core
uses:clj-time.date-time
uses:clj-time.local-date
uses:clj-time.local-time
uses:clj-time.month
uses:clj-time.year
ErikSchierboom commented 10 months ago

Exercise: gigasecond

Code

(ns gigasecond)
(require '[clj-time.core :as t])

(defn exp 
  "x^n "
  [x n]
  (reduce * (repeat n x)))

(defn from 
  [year month day]
  "Find the year month and day one gigasecond
   from the date given as a parameter

   parameters: 
   year: integer
   month: integer
   date: integer"
  (let [gigasecond (exp 10 9)
        days->sec  (* 24 60 60)
        days       (/ gigasecond days->sec)
        current-date (t/date-time year month day)
        new-date (t/plus current-date (t/days days))]
    (vector (t/year new-date) (t/month new-date) (t/day new-date)))
)

Tags:

construct:clj-time.core/date-time
construct:construct-overflow
construct:construct-reader-macro
construct:construct-let
construct:construct-namespace
construct:construct-reduce
construct:construct-require
construct:construct-vector
construct:construct-visibility-modifiers
construct:invocation
construct:let
construct:multiply
construct:named-argument
construct:parameter
construct:repeating
construct:shadowing
construct:vector
paradigm:functional
paradigm:imperative
paradigm:metaprogramming
paradigm:multiparadigm
technique:higher-order-functions
uses:clj-time.core
uses:clj-time.core/date-time
uses:clj-time.core/day
uses:clj-time.core/month
uses:clj-time.core/year
ErikSchierboom commented 10 months ago

Exercise: trinary

Code

(ns trinary)
(defn to-decimal
   ([n] (to-decimal n 0))
   ([[f & r] c]
       (if (or (nil? f) (nil? (#{\1 \0 \2} f)))
           c
           (to-decimal r (+ ( * c 3) (Integer/parseInt (str f)))))))

Tags:

construct:boolean
construct:char
construct:function
construct:if
construct:invocation
construct:method
construct:multiply
construct:namespace
construct:nil
construct:number
construct:parameter
construct:set
construct:string
construct:throw
construct:variadic-function
paradigm:functional
paradigm:object-oriented
technique:exceptions
uses:HashSet
ErikSchierboom commented 10 months ago

Exercise: spiral-matrix

Code

(ns spiral-matrix)

(defn square [n]
    (vec (map vec (repeat n (repeat n 0)))))

(defn inrange [[row col] a n]
    (and (< -1 row n) (< -1 col n) (zero? (get-in a [row col]))))

(defn turn90 [[dr dc]]
   [dc (- dr)])

(defn move [[row col] [dr dc]] 
   [(+ row dr) (+ col dc)])

(defn spr [n] 
    (loop [arr (square n) n n loc [0 0] dir [0 1] start 1]
        (if (pos? (get-in arr loc))
           arr
           (let [arr (assoc-in arr loc start)
                 new-loc (move loc dir)]
                 (if (inrange new-loc arr n)
                     (recur arr n new-loc dir (inc start))
                     (let [dir (turn90 dir) 
                           loc (move loc dir)] 
                         (recur arr n loc dir (inc start))))))))

(defn spiral [n]
   (cond
      (zero? n) []
      (= 1 n) [[1]] 
      :else  (spr n)))

Tags:

construct:and
construct:assoc-in
construct:binding
construct:char
construct:clojure
construct:cond
construct:constructor
construct:defn
construct:if
construct:inc
construct:indexing
construct:invocation
construct:let
construct:loop
construct:map
construct:nested
construct:parameter
construct:recur
construct:repeat
construct:vector
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:metaprogramming
technique:looping
uses:Vector
ErikSchierboom commented 10 months ago

Exercise: raindrops

Code

(ns raindrops)

(defn convert [n]
    (let [
            s (. String join ""
                (for [f {"i" 3 "a" 5 "o" 7}]
                    (case (mod n (f 1))
                        0 (. String join (f 0) ["Pl""ng"])
                        "")))
        ]
            (case s
                "" (format "%d" n)
                s)))

Tags:

construct:case
construct:char
construct:class
construct:clojure
construct:defn
construct:dot
construct:for
construct:implicit-conversion
construct:indexing
construct:invocation
construct:keyword-argument
construct:let
construct:method
construct:modulus
construct:ns
construct:number
construct:parameter
construct:set
construct:string
construct:vector
paradigm:functional
paradigm:object-oriented
technique:looping
uses:HashSet
uses:String
uses:Vector
ErikSchierboom commented 10 months ago

Exercise: raindrops

Code

(ns raindrops)

(defn- divides-evenly?
  [x y]
  (= 0 (mod x y)))

(defn convert
  [n]
  (if-let [s (not-empty (filter identity
                                (for [[k v] (seq {3 "Pling", 5 "Plang", 7 "Plong"})]
                                  (if (divides-evenly? n k)
                                    v))))]
    (apply str s)
    (str n)))

Tags:

construct:boolean
construct:apply
construct:char
construct:clojure
construct:defn
construct:filter
construct:for-loop
construct:function
construct:if
construct:if-let
construct:invocation
construct:keyword
construct:let
construct:local-name
construct:map
construct:modulus
construct:number
construct:parameter
construct:pattern-matching
construct:string
construct:underscore
construct:visibility-modifiers
paradigm:functional
paradigm:imperative
paradigm:declarative
technique:boolean-logic
technique:higher-order-functions
technique:looping
ErikSchierboom commented 10 months ago

Exercise: binary-search-tree

Code

(ns binary-search-tree)

(defn value
  [node]
  (:value node))

(defn singleton
  [v]
  {:value v
   :left nil
   :right nil})

(defn left
  [node]
  (:left node))

(defn right
  [node]
  (:right node))

(defn insert
  [v tree]
  (if tree
    (condp #(%1 (compare v %2)) (value tree)
      pos? (assoc tree :right (insert v (right tree)))
      (assoc tree :left (insert v (left tree))))
    (singleton v)))

(defn to-list
  [tree]
  (if tree
    (into [] (concat (to-list (left tree)) [(value tree)] (to-list (right tree))))
    []))

(defn from-list
  [coll]
  (when (seq coll)
    (loop [[x & more] coll
           tree nil]
      (if more
        (recur more (insert x tree))
        (insert x tree)))))

Tags:

construct:assoc
construct:binary-search-tree
construct:condp
construct:constructor
construct:definition
construct:fn
construct:if
construct:invocation
construct:loop
construct:parameter
construct:recursion
construct:string
construct:vector
paradigm:functional
paradigm:object-oriented
technique:bit-manipulation
technique:bit-shifting
technique:bitwise-operators
technique:higher-order-functions
technique:looping
uses:BinarySearchTree
ErikSchierboom commented 10 months ago

Exercise: all-your-base

Code

(ns all-your-base)

(defn from-base [base digits]
  (if-not (or (< base 2)
              (some neg? digits)
              (some #(>= % base) digits))
    (->> (reverse digits)
         (map * (iterate #(* % base) 1))
         (reduce +))))

(defn to-base [base number]
  (cond
    (or (< base 2) (nil? number)) nil
    (zero? number) '(0)
    :else (->> (iterate #(quot % base) number)
               (take-while pos?)
               (map #(mod % base))
               reverse)))

(defn convert [from digits to]
  (cond
    (or (< from 2) (< to 2)) nil
    (empty? digits) '()
    :else (->> digits
               (from-base from)
               (to-base to))))

Tags:

construct:boolean
construct:char
construct:clojure-symbol
construct:cond
construct:definition
construct:fn
construct:if-not
construct:invocation
construct:iterate
construct:lambda
construct:list
construct:map
construct:number
construct:or
construct:parameter
construct:quoted
construct:reduce
construct:reverse
construct:string
construct:take-while
construct:varargs
construct:vector
construct:zero?
paradigm:functional
paradigm:reflective
technique:higher-order-functions
technique:laziness
uses:reduce
ErikSchierboom commented 10 months ago

Exercise: minesweeper

Code

(ns minesweeper
  (:require [clojure.string :as str]
             [clojure.set :as set]))

;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Some helper functions.
;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Join a collection of strings into a single string
;; interposing a newline character.
(defn- join-lines [lines]
  (let [sep (System/getProperty "line.separator")]
    (str/join sep lines)))

;; Convert an integer to a character (5 -> \5)
(defn int->char [n] (char (+ (int \0) n)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Operations on the internal board representation
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Convert a string board into a matrix of cells.
;; Empty cells are nil; cells with mines are true.
(defn- string->board [s]
  (->> s
       str/split-lines
       (map #(map {\space nil \* true} %))
       (map #(into [] %))
       (into [])))

;; Get the height of the board
(defn- rows [board] (count board))

;; Get the width of the board
(defn- cols [board] (count (board 0)))

;; Finds the cells in the board with mines.
(defn- mine-cells [board]
  (set (for [i (range (rows board))
                 j (range (cols board))
                 :when ((board i) j)]
             [i j])))

;; Computes the cells that neighbor a given cell address.
;; These cells may not actually be on the board for the game.
;; That's ok. We're only checking which of them have mines,
;; so "out of bounds" cells will fall out.
(defn- cell-neighbors [cell]
  (let [[i j] cell]
    (set (for [dx [-1 0 1]
               dy [-1 0 1]
               :when (not (= 0 dx dy))]
           [(+ i dx) (+ j dy)]))))

;; Get the "drawn" representation of a cell.
;; If the cell has a mine, it's a *
;; If there are no neighboring mines, it's blank.
;; Otherwise it shows the number of neighboring mines.
(defn- draw-cell [cell mine-locations]
  (if (mine-locations cell) \*
      (let [neighbors (cell-neighbors cell)
            n-mines (count (set/intersection mine-locations neighbors))]
        (if (zero? n-mines) \space
            (int->char n-mines)))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Public board-drawing function
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn draw
  "Draw an exposed minesweeper board, given a string that
  represents the board with mine locations."
  [s]
  (let [board (string->board s)
        mine-locns (mine-cells board)
        drawn-board (for [i (range (rows board))]
                      (for [j (range (cols board))]
                        (draw-cell [i j] mine-locns)))]
    (join-lines (map #(apply str %) drawn-board))))

Tags:

construct:apply
construct:char
construct:count
construct:definition
construct:for
construct:if
construct:implicit-conversion
construct:int
construct:int->char
construct:integral-number
construct:invocation
construct:iterator
construct:keyword
construct:let
construct:list
construct:local-name
construct:map
construct:number
construct:parameter
construct:set
construct:string
construct:vector
paradigm:functional
paradigm:reflective
technique:higher-order-functions
uses:set
uses:string
uses:vector
ErikSchierboom commented 10 months ago

Exercise: protein-translation

Code

(ns protein-translation)

(def translate-codon
  (->> ["AUG    Methionine" 
        "UUU, UUC   Phenylalanine"
        "UUA, UUG   Leucine"
        "UCU, UCC, UCA, UCG Serine"
        "UAU, UAC   Tyrosine"
        "UGU, UGC   Cysteine"
        "UGG    Tryptophan"
        "UAA, UAG, UGA  STOP"]
       (map #(clojure.string/split % #"(?i)[^a-z]+"))
       (map (fn [lst] (map #(list % (last lst)) (butlast lst))))
       (apply concat)
       (reduce #(assoc %1 (first %2) (second %2)) {})))

(defn translate-rna [rna]
  (->> rna
       (partition 3)
       (map (partial apply str))
       (reduce #(let [protein (translate-codon %2)]
                  (if (= protein "STOP") (reduced %1) (conj %1 protein)))
               [])))

Tags:

construct:apply
construct:assoc
construct:clojure-regex
construct:conj
construct:construct
construct:definition
construct:fn
construct:function
construct:if
construct:invocation
construct:keyword
construct:let
construct:list
construct:map
construct:partial-function
construct:reduce
construct:string
construct:vector
paradigm:functional
paradigm:reflective
technique:higher-order-functions
technique:regular-expression
uses:clojure.string
uses:reduced
ErikSchierboom commented 10 months ago

Exercise: poker

Code

(ns poker
  (:require [clojure.string :as str]))

(defn- str->rank
  [s]
  (case s
    "J" 11
    "Q" 12
    "K" 13
    "A" 14                   ; ace is normally high
    (Integer/parseInt s)))

(defn- str->card
  [s]
  {:rank (-> s drop-last str/join str->rank)
   :suit (-> s last str)})

(defn- parse-hand
  [s]
  (->> s
       (#(str/split % #" "))
       (map str->card)
       (sort-by :rank >)))

(defn- straight?
  [hand &
   {:keys [ace-low?]
    :or {ace-low? false}}]
  (->> (:ranks hand)
       (partition 2 1)
       (map (partial apply -))
       (#(if ace-low?                   ; ace can be both high and low
           (= '(9 1 1 1) %)
           (every? #{1} %)))))

(defn- flush?
  [hand]
  (->> (:suits hand)
       (count)
       (= 1)))

(defn- straight-flush?
  [hand]
  (and (straight? hand) (flush? hand)))

(defn- sort-key
  [hand]
  (let [ranks (mapv :rank hand)
        suits (distinct (map :suit hand))
        grouped (->> ranks
                     (group-by identity)
                     (mapv second)
                     (sort-by count >)
                     (into []))
        distrib (mapv count grouped)
        decorated {:cards hand
                   :ranks ranks
                   :suits suits}]
    [(if (straight-flush? decorated) (first ranks) 0)
     (if (= [4 1] distrib) grouped [])     ; four of a kind
     (if (= [3 2] distrib) grouped [])     ; full house
     (if (flush? decorated) ranks [])
     (if (straight? decorated)          ; try ace high first
       (first ranks)
       (if (straight? decorated :ace-low? true) 5 0)) ; then try ace low
     (if (= [3 1 1] distrib) grouped [])   ; three of a kind
     (if (= [2 2 1] distrib) grouped [])   ; two pair
     (if (= [2 1 1 1] distrib) grouped []) ; pair
     ranks]))                              ; high card

(defn best-hands
  [hands]
  (->> hands
       (group-by (comp sort-key parse-hand))
       (sort)
       (last)
       (second)))

Tags:

construct:and
construct:apply
construct:as->
construct:boolean
construct:case
construct:comment
construct:count
construct:defn
construct:fn
construct:if
construct:if-some
construct:implicit-conversion
construct:invocation
construct:keyword
construct:let
construct:list
construct:map
construct:mapv
construct:named-argument
construct:namespace
construct:number
construct:optional-arguments
construct:parameter
construct:partial-function
construct:partition
construct:set
construct:sort
construct:string
construct:subtract
construct:vector
paradigm:functional
paradigm:object-oriented
technique:boolean-logic
technique:higher-order-functions
uses:SortedSet
uses:map
uses:set
uses:vector
ErikSchierboom commented 10 months ago

Exercise: armstrong-numbers

Code

(ns armstrong-numbers
  (require [clojure.math.numeric-tower :as n]))

(declare c-s-d)
(declare iter-split-num)

(defn armstrong? [x]
  (= x (reduce + 0
               (map #(n/expt % (c-s-d x))
                        (iter-split-num x)))))

(defn c-s-d [num]
  (count (iter-split-num num)))

(defn iter-split-num [n]
       (->> n
             (iterate #(quot % 10))
             (map #(rem % 10))
             (take-while #(> % 0))))

Tags:

construct:as
construct:clojure
construct:declare
construct:defn
construct:implicit-conversion
construct:invocation
construct:iterate
construct:lambda
construct:list
construct:map
construct:method
construct:namespace
construct:number
construct:parameter
construct:reduce
construct:require
construct:take-while
construct:underscore
construct:variable-arity
paradigm:functional
paradigm:reflective
technique:higher-order-functions
technique:laziness
technique:looping
ErikSchierboom commented 9 months ago

This is an automated comment

Hello :wave: Next week we're going to start using the tagging work people are doing on these. If you've already completed the work, thank you! If you've not, but intend to this week, that's great! If you're not going to get round to doing it, and you've not yet posted a comment letting us know, could you please do so, so that we can find other people to do it. Thanks!