Skip to content

Instantly share code, notes, and snippets.

@mzhr
Last active July 2, 2022 02:27
Show Gist options
  • Save mzhr/0ff92f789f0bd0ffb8a7c60698d69fa4 to your computer and use it in GitHub Desktop.
Save mzhr/0ff92f789f0bd0ffb8a7c60698d69fa4 to your computer and use it in GitHub Desktop.
Clojure Brainf Interpreter (Codewars challenge https://www.codewars.com/kata/526156943dfe7ce06200063e)
(ns brainf)
(defn exec [instruction params]
(let [{:keys [source postsource data input pointer output]} params
current-data (nth data pointer)]
(case instruction
\> (assoc params :pointer (inc pointer))
\< (assoc params :pointer (dec pointer))
\+ (assoc params :data (concat (take pointer data)
(list (if (= 255 current-data) 0 (inc current-data)))
(nthrest data (inc pointer))))
\- (assoc params :data (concat (take pointer data)
(list (if (= 0 current-data) 255 (dec current-data)))
(nthrest data (inc pointer))))
\. (assoc params :output (str output (char current-data)))
\, (assoc params
:input (if (nil? (first input)) input (rest input))
:data (concat (take pointer data)
(list (if (nil? (first input)) current-data (int (first input))))
(nthrest data (inc pointer))))
\[ (if (not (= 0 current-data)) params
(loop [p params m 0]
(let [{:keys [source postsource data input pointer output]} p
next (assoc p
:source (rest source)
:postsource (conj postsource (first source)))]
(if (and (= \] (first source)) (= m 0)) next
(recur next (cond (= \] (first source)) (dec m)
(= \[ (first source)) (inc m)
:else m))))))
\] (if (= 0 current-data) params
(loop [prev (assoc params
:source (conj source (first postsource))
:postsource (rest postsource))
m 0]
(let [{:keys [source postsource data input pointer output]} prev]
(if (and (= \[ (first postsource)) (= m 0)) prev
(recur(assoc params
:source (conj source (first postsource))
:postsource (rest postsource))
(cond (= \[ (first postsource)) (dec m)
(= \] (first postsource)) (inc m)
:else m)))))))))
(defn execute-string
"Evaluate the Brainff source code in `source` using `input` as a source of
characters for the `,` input command.
Either returns a sequence of output characters, or `nil` if there was
insufficient input."
[source input]
(loop [params {:source source
:postsource '()
:input input
:data (repeat 0)
:pointer 0
:output ""}]
(cond
(nil? (first (params :source)))
(params :output)
(and (= \, (first (params :source))) (= 0 (count (params :input))))
nil
:else
(recur
(exec (first (params :source))
(assoc params
:source (rest (params :source))
:postsource (conj (params :postsource) (first (params :source)))))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment