Created
March 22, 2021 21:22
-
-
Save jkjuopperi/427bb17af24927019c4045b966e47d62 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
(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