Last active
December 14, 2023 13:52
-
-
Save werenall/bba5438c3e78a1cca63d4d2ab14561b7 to your computer and use it in GitHub Desktop.
Secret santa
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
(defn- rand-π | |
[π π-pool exclusions] | |
(let [potential-π (-> π-pool | |
(disj π ) | |
(set/difference (get exclusions π )))] | |
(first (shuffle potential-π)))) | |
(defn frivolously-draw-secret-santa | |
"Tries to randomize π s hoping that with power of Christmas everything will just work. | |
Will give up after some retrials." | |
([names] | |
(frivolously-draw-secret-santa names {})) | |
([names exclusions] | |
(frivolously-draw-secret-santa names exclusions 1)) | |
([names exclusions attempt] | |
{:pre [(s/valid? ::names names) | |
(s/valid? ::exclusions exclusions) | |
(s/valid? ::attempt attempt)]} | |
(let [result (reduce | |
(fn [acc π ] | |
(let [π (rand-π π (get acc :π-pool) exclusions)] | |
(-> acc | |
(update :π-pool disj π) | |
(update :π s assoc π π)))) | |
{:π-pool names | |
:π s {}} | |
names) | |
π s (get result :π s)] | |
(if (some #(nil? (val %)) π s) | |
(do | |
(println "Some π drew themselves. Retrying...") | |
(if (> attempt 10) | |
(frivolously-draw-secret-santa names exclusions (inc attempt)) | |
(throw (Exception. "Couldn't find a solution in 10 retrials. Giving up.")))) | |
π s)))) |
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
(defn- gen-santa-tree | |
[names exclusions] | |
(let [start {:π ->π {} | |
:available-π names}] | |
(tree-seq | |
(fn [x] | |
(and (get x :π ->π) | |
(get x :available-π))) | |
(fn [{:keys [available-π π ->π] :as node}] | |
(let [available-π (set/difference names (set (keys π ->π)))] | |
(let [new-children | |
(reduce (fn [acc π ] | |
(let [available-π (set/difference | |
(disj available-π π ) | |
(get exclusions π )) | |
children-for-π (map (fn [π] | |
(-> node | |
(update :π ->π assoc π π) | |
(update :available-π disj π))) | |
available-π)] | |
(concat acc children-for-π ))) | |
[] | |
available-π )] | |
new-children))) | |
start))) | |
(defn seriously-draw-secret-santa | |
"Christmas is serious business. Builds a tree of possible solutions and randomly chooses a valid one." | |
([names] | |
(seriously-draw-secret-santa names {})) | |
([names exclusions] | |
{:pre [(s/valid? ::names names) | |
(s/valid? ::exclusions exclusions)]} | |
(let [possible-solutions (->> | |
(gen-santa-tree names exclusions) | |
(filter #(empty? (:available-π %))))] | |
(if (seq possible-solutions) | |
(-> possible-solutions | |
rand-nth | |
(get :π ->π)) | |
(throw (Exception. "Solution doesn't exist! Check your exclusions")))))) |
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
(s/def ::names (s/and set? | |
(s/coll-of string? :min-count 2))) | |
(s/def ::exclusions (s/map-of string? | |
(s/and set? | |
(s/coll-of string?)))) | |
(s/def ::attempt int?) |
Author
werenall
commented
Dec 14, 2023
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment