Skip to content

Instantly share code, notes, and snippets.

@jkjuopperi
Created March 22, 2021 21:22
Show Gist options
  • Save jkjuopperi/427bb17af24927019c4045b966e47d62 to your computer and use it in GitHub Desktop.
Save jkjuopperi/427bb17af24927019c4045b966e47d62 to your computer and use it in GitHub Desktop.
(ns puzzle
(:require [clojure.set :refer [union intersection difference]]))
(def initial-world
"The initial puzzle world is a structure with
three slots, :a, :b and :c. These are sets that start
with all possible numbers from 0 to 9."
{:a #{0 1 2 3 4 5 6 7 8 9}
:b #{0 1 2 3 4 5 6 7 8 9}
:c #{0 1 2 3 4 5 6 7 8 9}})
(defn world-possible?
"Are there choices left? If all of the slots have some possible
numbers in them, the world is still viable."
[{a :a b :b c :c}]
(and (not-empty a)
(not-empty b)
(not-empty c)))
(defn hint-1
"One number is correct and well placed.
Make three possible worlds
- A was correct and well placed
- B was correct and well placed
- C was correct and well placed
If e.g. A was correct and well placed, that means:
- Slot A can only contain number A
(intersection of available choices in the world and set containing only number A)
- No slots can contain numbers B and C
"
[world a b c]
[(-> world
(update :a intersection #{a})
(update :b difference #{a b c})
(update :c difference #{a b c}))
(-> world
(update :a difference #{a b c})
(update :b intersection #{b})
(update :c difference #{a b c}))
(-> world
(update :a difference #{a b c})
(update :b difference #{a b c})
(update :c intersection #{c}))])
(defn hint-2
"One number is correct but wrongly placed.
Make 6 worlds."
[world a b c]
[(-> world ;; A is in slot B
(update :a difference #{a b c})
(update :b intersection #{a})
(update :c difference #{a b c}))
(-> world ;; A is in slot C
(update :a difference #{a b c})
(update :b difference #{a b c})
(update :c intersection #{a}))
(-> world ;; B is in slot A
(update :a intersection #{b})
(update :b difference #{a b c})
(update :c difference #{a b c}))
(-> world ;; B is in slot C
(update :a difference #{a b c})
(update :b difference #{a b c})
(update :c intersection #{b}))
(-> world ;; C is in slot A
(update :a intersection #{c})
(update :b difference #{a b c})
(update :c difference #{a b c}))
(-> world ;; C is in slot B
(update :a difference #{a b c})
(update :b intersection #{c})
(update :c difference #{a b c}))])
(defn hint-3
"Two numbers are correct but wrongly placed.
Make 9 worlds."
[world a b c]
[(-> world ;; a -> :b, b -> :a
(update :a intersection #{b})
(update :b intersection #{a})
(update :c difference #{a b c}))
(-> world ;; a -> :b, b -> :c
(update :a difference #{a b c})
(update :b intersection #{a})
(update :c intersection #{b}))
(-> world ;; a -> :b, c -> :a
(update :a intersection #{c})
(update :b intersection #{a})
(update :c difference #{a b c}))
(-> world ;; a -> :c, b -> :a
(update :a intersection #{b})
(update :b difference #{a b c})
(update :c intersection #{a}))
(-> world ;; a -> :c, c -> :a
(update :a intersection #{c})
(update :b difference #{a b c})
(update :c intersection #{a}))
(-> world ;; a -> :c, c -> :b
(update :a difference #{a b c})
(update :b intersection #{c})
(update :c intersection #{a}))
(-> world ;; b -> :a, c -> :b
(update :a intersection #{b})
(update :b intersection #{c})
(update :c difference #{a b c}))
(-> world ;; b -> :c, c -> :a
(update :a intersection #{c})
(update :b difference #{a b c})
(update :c intersection #{b}))
(-> world ;; b -> :c, c -> :b
(update :a difference #{a b c})
(update :b intersection #{c})
(update :c intersection #{b}))])
(defn hint-4
"Nothing is correct.
Make just one world with all the mentioned numbers removed."
[world a b c]
[(-> world
(update :a difference #{a b c})
(update :b difference #{a b c})
(update :c difference #{a b c}))])
(defn hint-5
"One number is correct but wrongly placed.
Make 6 worlds."
[world a b c]
[(-> world ;; Number a is in slot :b
(update :a difference #{a b c})
(update :b intersection #{a})
(update :c difference #{a b c}))
(-> world ;; Number a is in slot :c
(update :a difference #{a b c})
(update :b difference #{a b c})
(update :c intersection #{a}))
(-> world ;; Number b is in slot :a
(update :a intersection #{b})
(update :b difference #{a b c})
(update :c difference #{a b c}))
(-> world ;; Number b is in slot :c
(update :a difference #{a b c})
(update :b difference #{a b c})
(update :c intersection #{b}))
(-> world ;; Number c is in slot :a
(update :a intersection #{c})
(update :b difference #{a b c})
(update :c difference #{a b c}))
(-> world ;; Number c is in slot :b
(update :a difference #{a b c})
(update :b intersection #{c})
(update :c difference #{a b c}))])
(defn apply-hint
"Take a list of worlds, apply a hint function to each of these worlds in succession.
Each call of the hint function may return a bunch of possible worlds.
Just concatenate all worlds in the same list.
Then filter out worlds that have run out of possible options. See world-possible?
"
[worlds hint-fn]
(->> worlds
(mapcat hint-fn)
(filter world-possible?)))
(defn just-do-it
"The main function.
Take the initial world where slots A, B and C are sets with all possible numbers from 0 to 9.
Then apply each hint in succession. apply-hint function will also filter out worlds that have
no longer any numbers that could fit in the slots (have empty sets), so that next hint function
will receive only worlds with some hope of producing a result."
[]
(-> [initial-world] ;; List of one initial world
(apply-hint #(hint-1 % 6 8 2))
(apply-hint #(hint-2 % 6 1 4))
(apply-hint #(hint-3 % 2 0 6))
(apply-hint #(hint-4 % 7 3 8))
(apply-hint #(hint-5 % 7 8 0))))
;; => ({:a #{0}, :b #{4}, :c #{2}})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment