diff --git a/src/propeller/problems/PSB1/count_odds.cljc b/src/propeller/problems/PSB1/count_odds.cljc
new file mode 100644
index 0000000..4b42605
--- /dev/null
+++ b/src/propeller/problems/PSB1/count_odds.cljc
@@ -0,0 +1,77 @@
+(ns propeller.problems.PSB1.count-odds
+  (:require [psb2.core :as psb2]
+            [propeller.genome :as genome]
+            [propeller.push.interpreter :as interpreter]
+            [propeller.problems.data-creation :as dc]
+            [propeller.utils :as utils]
+            [propeller.push.instructions :refer [get-stack-instructions]]
+            [propeller.push.state :as state]
+            [propeller.tools.math :as math]
+            [propeller.gp :as gp]
+            #?(:cljs [cljs.reader :refer [read-string]])))
+
+
+(def train-and-test-data (psb2/fetch-examples "data" "count-odds" 200 2000))
+(def train-data (:train train-and-test-data))
+(def test-data (:test train-and-test-data))
+
+; Random integer between -100 and 100 (from smallest)
+(defn random-int [] (- (rand-int 201) 100))
+
+(def instructions
+  (utils/not-lazy
+   (concat
+      ;;; stack-specific instructions
+    (get-stack-instructions #{:exec :integer :boolean :vector_integer :print})
+      ;;; input instructions
+    (list :in1)
+      ;;; close
+    (list 'close)
+      ;;; ERCs (constants)
+    (list random-int 0 1 2))))
+
+(defn error-function
+  [argmap data individual]
+  (let [program (genome/plushy->push (:plushy individual) argmap)
+        inputs (map (fn [i] (get i :input1)) data)
+        correct-outputs (map (fn [i] (get i :output1)) data)
+        outputs (map (fn [input]
+                       (state/peek-stack
+                        (interpreter/interpret-program
+                         program
+                         (assoc state/empty-state :input {:in1 input})
+                         (:step-limit argmap))
+                        :integer))
+                     inputs)
+        errors (map (fn [correct-output output]
+                      (if (= output :no-stack-item)
+                        1000000
+                        (math/abs (- correct-output output))))
+                    correct-outputs
+                    outputs)]
+    (assoc individual
+           :behaviors outputs
+           :errors errors
+           :total-error #?(:clj  (apply +' errors)
+                           :cljs (apply + errors)))))
+
+(defn -main
+  "Runs propel-gp, giving it a map of arguments."
+  [& args]
+  (gp/gp
+   (merge
+    {:instructions            instructions
+     :error-function          error-function
+     :training-data           train-data
+     :testing-data            test-data
+     :max-generations         300
+     :population-size         1000
+     :max-initial-plushy-size 250
+     :step-limit              2000
+     :parent-selection        :lexicase
+     :tournament-size         5
+     :umad-rate               0.1
+     :variation               {:umad 1.0 :crossover 0.0}
+     :elitism                 false}
+    (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+  (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB1/grade.cljc b/src/propeller/problems/PSB1/grade.cljc
new file mode 100644
index 0000000..a8961aa
--- /dev/null
+++ b/src/propeller/problems/PSB1/grade.cljc
@@ -0,0 +1,95 @@
+(ns propeller.problems.PSB1.grade
+  (:require
+   [psb2.core :as psb2]
+   [propeller.genome :as genome]
+   [propeller.push.interpreter :as interpreter]
+   [propeller.problems.data-creation :as dc]
+   [propeller.push.state :as state]
+   [propeller.push.instructions :refer [get-stack-instructions]]
+   [propeller.utils :as utils]
+   [propeller.tools.metrics :as metrics]
+   [propeller.gp :as gp]
+   #?(:cljs [cljs.reader :refer [read-string]])))
+
+
+; Based on the grade PSB1 problem, this verion only requires an output of a single character
+;"“Student has a ”, “ grade.”, “A”, “B”, “C”, “D”, “F”, integer ERC"
+
+(def train-and-test-data (psb2/fetch-examples "data" "grade" 200 2000))
+(def train-data (:train train-and-test-data))
+(def test-data (:test train-and-test-data))
+
+(defn map-vals-input
+  "Returns all the input values of a map"
+  [i]
+  (vals (select-keys i [:input1 :input2 :input3 :input4 :input5])))
+
+(defn get-output
+  "returns the outputs of the grade function with JUST the letter grade"
+  [i]
+  (str (nth i 14)))
+
+; Random integer between -100 and 100
+(defn random-int [] (- (rand-int 201) 100))
+
+(def instructions
+  (utils/not-lazy
+   (concat
+      ;; stack-specific instructions
+    (get-stack-instructions #{:boolean :exec :integer :string :print})
+      ;; input instructions
+    (list :in1 :in2 :in3 :in4 :in5)
+    ;;close
+    (list 'close)
+      ;; ERCs (constants)
+    (list "A" "B" "C" "D" "F" random-int))))
+
+(defn error-function
+  [argmap data individual]
+  (let [program (genome/plushy->push (:plushy individual) argmap)
+        inputs (map (fn [i] (map-vals-input i)) data)
+        correct-outputs (map (fn [i] (get-output (get i :output1))) data)
+        outputs (map (fn [input]
+                       (state/peek-stack
+                        (interpreter/interpret-program
+                         program
+                         (assoc state/empty-state :input {:in1 (nth input 0)
+                                                          :in2 (nth input 1)
+                                                          :in3 (nth input 2)
+                                                          :in4 (nth input 3)
+                                                          :in5 (nth input 4)})
+                         (:step-limit argmap))
+                        :print))
+                     inputs)
+        errors (map (fn [correct-output output]
+                      (if (= output :no-stack-item)
+                        1000000.0
+                        (metrics/levenshtein-distance correct-output output)))
+                        correct-outputs
+                        outputs)]
+    (assoc individual
+           :behaviors outputs
+           :errors errors
+           :total-error #?(:clj  (apply +' errors)
+                           :cljs (apply + errors)))))
+
+(defn -main
+  "Runs propel-gp, giving it a map of arguments."
+  [& args]
+  (gp/gp
+   (merge
+    {:instructions            instructions
+     :error-function          error-function
+     :training-data           train-data
+     :testing-data            test-data
+     :max-generations         300
+     :population-size         1000
+     :max-initial-plushy-size 250
+     :step-limit              2000
+     :parent-selection        :lexicase
+     :tournament-size         5
+     :umad-rate               0.1
+     :variation               {:umad 1.0 :crossover 0.0}
+     :elitism                 false}
+    (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+  (#?(:clj shutdown-agents)))
\ No newline at end of file
diff --git a/src/propeller/problems/PSB1/scrabble_score.cljc b/src/propeller/problems/PSB1/scrabble_score.cljc
new file mode 100644
index 0000000..7339e74
--- /dev/null
+++ b/src/propeller/problems/PSB1/scrabble_score.cljc
@@ -0,0 +1,146 @@
+(ns propeller.problems.PSB1.scrabble-score
+  (:require [psb2.core :as psb2]
+            [propeller.genome :as genome]
+            [propeller.push.interpreter :as interpreter]
+            [clojure.string :as string]
+            [propeller.tools.math :as math]
+            [propeller.problems.data-creation :as dc]
+            [propeller.utils :as utils]
+            [propeller.push.instructions :refer [get-stack-instructions]]
+            [propeller.push.state :as state]
+            [propeller.tools.metrics :as metrics]
+            [propeller.gp :as gp]
+            #?(:cljs [cljs.reader :refer [read-string]])))
+
+(def train-and-test-data (psb2/fetch-examples "data" "scrabble-score" 200 2000))
+(def train-data (:train train-and-test-data))
+(def test-data (:test train-and-test-data))
+
+(def scrabble-letter-values
+  (let [scrabble-map {\a 1
+                      \b 3
+                      \c 3
+                      \d 2
+                      \e 1
+                      \f 4
+                      \g 2
+                      \h 4
+                      \i 1
+                      \j 8
+                      \k 5
+                      \l 1
+                      \m 3
+                      \n 1
+                      \o 1
+                      \p 3
+                      \q 10
+                      \r 1
+                      \s 1
+                      \t 1
+                      \u 1
+                      \v 4
+                      \w 4
+                      \x 8
+                      \y 4
+                      \z 10}
+        visible-chars (map char (range 0 127))]
+    (vec (for [c visible-chars]
+           (get scrabble-map (first (string/lower-case c)) 0)))))
+
+;; scrabble-letter-values
+
+;; (def program '(0 :in1 :string_iterate (:integer_from_char [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 3 3 2 1 4 2 4 1 8 5 1 3 1 1 3 10 1 1 1 1 4 4 8 4 10 0 0 0 0 0 0 1 3 3 2 1 4 2 4 1 8 5 1 3 1 1 3 10 1 1 1 1 4 4 8 4 10 0 0 0 0] :vector_integer_nth :integer_add)))
+
+;; (def inputs (map (fn [i] (get i :input1)) test-data))
+;; test-data
+;; (def correct-outputs (map (fn [i] (get i :output1)) test-data))
+
+;; correct-outputs
+;; inputs
+
+;; (def outputs (map (fn [input]
+;;                     (state/peek-stack
+;;                      (interpreter/interpret-program
+;;                       program
+;;                       (assoc state/empty-state :input {:in1 input})
+;;                       200)
+;;                      :integer))
+;;                   inputs))
+
+;; outputs
+;; correct-outputs
+
+;; (def errors (map (fn [correct-output output]
+;;                    (if (= output :no-stack-item)
+;;                      1000000
+;;                      (math/abs (- correct-output output))))
+;;                  correct-outputs
+;;                  outputs))
+
+;; (apply + errors)
+
+;; (defn index-of [item coll]
+;;   (count (take-while (partial not= item) coll)))
+
+;; (index-of 1 errors)
+;; (nth inputs 647)
+;; (nth outputs 647)
+;; (nth correct-outputs 647)
+
+(def instructions
+  (utils/not-lazy
+   (concat
+      ;;; stack-specific instructions
+    (get-stack-instructions #{:exec :integer :boolean :char :vector_integer :string})
+      ;;; input instructions
+    (list :in1)
+      ;;; close
+    (list 'close)
+      ;;; ERCs (constants)
+    (list scrabble-letter-values))))
+
+(defn error-function
+  [argmap data individual]
+  (let [program (genome/plushy->push (:plushy individual) argmap)
+        inputs (map (fn [i] (get i :input1)) data)
+        correct-outputs (map (fn [i] (get i :output1)) data)
+        outputs (map (fn [input]
+                       (state/peek-stack
+                        (interpreter/interpret-program
+                         program
+                         (assoc state/empty-state :input {:in1 input})
+                         (:step-limit argmap))
+                        :integer))
+                     inputs)
+        errors (map (fn [correct-output output]
+                      (if (= output :no-stack-item)
+                        1000000
+                        (math/abs (- correct-output output))))
+                    correct-outputs
+                    outputs)]
+    (assoc individual
+           :behaviors outputs
+           :errors errors
+           :total-error #?(:clj  (apply +' errors)
+                           :cljs (apply + errors)))))
+
+(defn -main
+  "Runs propel-gp, giving it a map of arguments."
+  [& args]
+  (gp/gp
+   (merge
+    {:instructions            instructions
+     :error-function          error-function
+     :training-data           train-data
+     :testing-data            test-data
+     :max-generations         300
+     :population-size         1000
+     :max-initial-plushy-size 250
+     :step-limit              2000
+     :parent-selection        :lexicase
+     :tournament-size         5
+     :umad-rate               0.1
+     :variation               {:umad 1.0 :crossover 0.0}
+     :elitism                 false}
+    (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+  (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/PSB1/small_or_large.cljc b/src/propeller/problems/PSB1/small_or_large.cljc
new file mode 100644
index 0000000..bfc0dce
--- /dev/null
+++ b/src/propeller/problems/PSB1/small_or_large.cljc
@@ -0,0 +1,78 @@
+(ns propeller.problems.PSB1.small-or-large
+  (:require [psb2.core :as psb2]
+            [propeller.genome :as genome]
+            [propeller.push.interpreter :as interpreter]
+            [propeller.problems.data-creation :as dc]
+            [propeller.utils :as utils]
+            [propeller.push.instructions :refer [get-stack-instructions]]
+            [propeller.push.state :as state]
+            [propeller.tools.metrics :as metrics]
+            [propeller.gp :as gp]
+            #?(:cljs [cljs.reader :refer [read-string]])))
+
+
+(def train-and-test-data (psb2/fetch-examples "data" "small-or-large" 200 2000))
+(def train-data (:train train-and-test-data))
+(def test-data (:test train-and-test-data))
+
+; Random integer between -100 and 100
+(defn random-int [] (- (rand-int 201) 100))
+
+(def instructions
+  (utils/not-lazy
+    (concat
+      ;;; stack-specific instructions
+      (get-stack-instructions #{:exec :integer :boolean :string :print})
+      ;;; input instructions
+      (list :in1)
+      ;;; close
+      (list 'close)
+      ;;; ERCs (constants)
+      (list "" "small" "large" random-int))))
+
+(defn error-function
+  [argmap data individual]
+   (let [program (genome/plushy->push (:plushy individual) argmap)
+         inputs (map (fn [i] (get i :input1)) data)
+         correct-outputs (map (fn [i] (get i :output1)) data)
+         outputs (map (fn [input]
+                        (state/peek-stack
+                          (interpreter/interpret-program
+                            program
+                            (assoc state/empty-state :input {:in1 input})
+                            (:step-limit argmap))
+                          :string))
+                      inputs)
+         errors (map (fn [correct-output output]
+                       (if (= output :no-stack-item)
+                         10000
+                         (metrics/levenshtein-distance correct-output output)))
+                     correct-outputs
+                     outputs)]
+     (assoc individual
+       :behaviors outputs
+       :errors errors
+       :total-error #?(:clj  (apply +' errors)
+                       :cljs (apply + errors)))))
+
+
+(defn -main
+  "Runs propel-gp, giving it a map of arguments."
+  [& args]
+  (gp/gp
+    (merge
+      {:instructions            instructions
+       :error-function          error-function
+       :training-data           train-data
+       :testing-data            test-data
+       :max-generations         300
+       :population-size         1000
+       :max-initial-plushy-size 250
+       :step-limit              2000
+       :parent-selection        :lexicase
+       :tournament-size         5
+       :umad-rate               0.1
+       :variation               {:umad 1.0 :crossover 0.0}
+       :elitism                 false}
+      (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+  (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/complex_regression.cljc b/src/propeller/problems/complex_regression.cljc
new file mode 100644
index 0000000..f940f8c
--- /dev/null
+++ b/src/propeller/problems/complex_regression.cljc
@@ -0,0 +1,81 @@
+(ns propeller.problems.complex-regression
+  (:require [propeller.genome :as genome]
+            [propeller.push.interpreter :as interpreter]
+            [propeller.push.state :as state]
+            [propeller.tools.math :as math]
+            [propeller.gp :as gp]
+            #?(:cljs [cljs.reader :refer [read-string]])))
+
+(defn- target-function
+  "Target function: f(x) = (x^3 + 1)^3 + 1"
+  [x]
+  (let [x-new (+ (* x x x) 1)]
+    (+ (* x-new x-new x-new) 1)))
+
+(def train-and-test-data
+  (let [train-inputs (range -4.0 4.0 0.25)
+        test-inputs (range -4.125 4.125 0.25)]
+    {:train (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) train-inputs)
+     :test (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) test-inputs)}))
+
+(def instructions
+  (list :in1
+        :float_add
+        :float_subtract
+        :float_mult
+        :float_quot
+        :float_eq
+        :exec_dup
+        :exec_if
+        'close
+        0
+        1))
+
+(defn error-function
+  "Finds the behaviors and errors of an individual. The error is the absolute
+  deviation between the target output value and the program's selected behavior,
+  or 1000000 if no behavior is produced. The behavior is here defined as the
+  final top item on the FLOAT stack."
+  ([argmap data individual]
+   (let [program (genome/plushy->push (:plushy individual) argmap)
+         inputs (map (fn [x] (first (:input1 x))) data)
+         correct-outputs (map (fn [x] (first (:output1 x))) data)
+         outputs (map (fn [input]
+                        (state/peek-stack
+                         (interpreter/interpret-program
+                          program
+                          (assoc state/empty-state :input {:in1 input})
+                          (:step-limit argmap))
+                         :float))
+                      inputs)
+         errors (map (fn [correct-output output]
+                       (if (= output :no-stack-item)
+                         1000000
+                         (math/abs (- correct-output output))))
+                     correct-outputs
+                     outputs)]
+     (assoc individual
+            :behaviors outputs
+            :errors errors
+            :total-error #?(:clj  (apply +' errors)
+                            :cljs (apply + errors))))))
+
+(defn -main
+  "Runs propel-gp, giving it a map of arguments."
+  [& args]
+  (gp/gp
+   (merge
+    {:instructions             instructions
+     :error-function           error-function
+     :training-data            (:train train-and-test-data)
+     :testing-data             (:test train-and-test-data)
+     :max-generations          5000
+     :population-size          500
+     :max-initial-plushy-size  100
+     :step-limit               200
+     :parent-selection         :lexicase
+     :umad-rate                0.1
+     :variation                {:umad 1.0 :crossover 0.0}
+     :elitism                  false}
+    (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+  (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/float_regression.cljc b/src/propeller/problems/float_regression.cljc
new file mode 100644
index 0000000..516e682
--- /dev/null
+++ b/src/propeller/problems/float_regression.cljc
@@ -0,0 +1,82 @@
+(ns propeller.problems.float-regression
+  (:require [propeller.genome :as genome]
+            [propeller.push.interpreter :as interpreter]
+            [propeller.push.state :as state]
+            [propeller.tools.math :as math]
+            [propeller.gp :as gp]
+            #?(:cljs [cljs.reader :refer [read-string]])))
+
+(defn- target-function
+  "Target function: f(x) = (1+ x^3)^3 + 1"
+  [x]
+  (inc (* (inc (* x x x)) (inc (* x x x)) (inc (* x x x)))))
+
+(def train-and-test-data
+  (let [train-inputs (range -1.5 1.5 0.1)
+        test-inputs (range -1.75 1.75 0.05)]
+    {:train (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) train-inputs)
+     :test (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) test-inputs)}))
+
+(def instructions
+  (list :in1
+        :float_add
+        :float_subtract
+        :float_mult
+        :float_quot
+        :float_eq
+        :exec_dup
+        :exec_if
+        'close
+        0
+        1))
+
+(defn error-function
+  "Finds the behaviors and errors of an individual. The error is the absolute
+  deviation between the target output value and the program's selected behavior,
+  or 1000000 if no behavior is produced. The behavior is here defined as the
+  final top item on the FLOAT stack."
+  ([argmap data individual]
+   (let [program (genome/plushy->push (:plushy individual) argmap)
+         inputs (map (fn [x] (first (:input1 x))) data)
+         correct-outputs (map (fn [x] (first (:output1 x))) data)
+         outputs (map (fn [input]
+                        (state/peek-stack
+                          (interpreter/interpret-program
+                            program
+                            (assoc state/empty-state :input {:in1 input})
+                            (:step-limit argmap))
+                          :float))
+                      inputs)
+         errors (map (fn [correct-output output]
+                       (if (= output :no-stack-item)
+                         1000000
+                         (math/abs (- correct-output output))))
+                     correct-outputs
+                     outputs)]
+     (assoc individual
+       :behaviors outputs
+       :errors errors
+       :total-error #?(:clj  (apply +' errors)
+                       :cljs (apply + errors))))))
+
+(defn -main
+  "Runs propel-gp, giving it a map of arguments."
+  [& args]
+  (gp/gp
+    (merge
+      {:instructions             instructions
+       :error-function           error-function
+       :training-data            (:train train-and-test-data)
+       :testing-data             (:test train-and-test-data)
+       :max-generations          300
+       :population-size          1000
+       :max-initial-plushy-size  100
+       :step-limit               200
+       :parent-selection         :lexicase
+       :tournament-size          5
+       :umad-rate                0.1
+       :solution-error-threshold  0.5
+       :variation                {:umad 1.0 :crossover 0.0}
+       :elitism                  false}
+      (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+  (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/integer_regression.cljc b/src/propeller/problems/integer_regression.cljc
new file mode 100644
index 0000000..ff60213
--- /dev/null
+++ b/src/propeller/problems/integer_regression.cljc
@@ -0,0 +1,81 @@
+(ns propeller.problems.integer-regression
+  (:require [propeller.genome :as genome]
+            [propeller.push.interpreter :as interpreter]
+            [propeller.push.state :as state]
+            [propeller.tools.math :as math]
+            [propeller.gp :as gp]
+            #?(:cljs [cljs.reader :refer [read-string]])))
+
+(defn- target-function
+  "Target function: f(x) = x^3 + 2*x^2 + x + 3"
+  [x]
+  (+ (* x x x) (* 2 x x) x 3))
+
+(def train-and-test-data
+  (let [train-inputs (range -10 11)
+        test-inputs (concat (range -20 -10) (range 11 21))]
+    {:train (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) train-inputs)
+     :test (map (fn [x] {:input1 (vector x) :output1 (vector (target-function x))}) test-inputs)}))
+
+(def instructions
+  (list :in1
+        :integer_add
+        :integer_subtract
+        :integer_mult
+        :integer_quot
+        :integer_eq
+        :exec_dup
+        :exec_if
+        'close
+        0
+        1))
+
+(defn error-function
+  "Finds the behaviors and errors of an individual. The error is the absolute
+  deviation between the target output value and the program's selected behavior,
+  or 1000000 if no behavior is produced. The behavior is here defined as the
+  final top item on the INTEGER stack."
+  ([argmap data individual]
+   (let [program (genome/plushy->push (:plushy individual) argmap)
+         inputs (map (fn [x] (first (:input1 x))) data)
+         correct-outputs (map (fn [x] (first (:output1 x))) data)
+         outputs (map (fn [input]
+                        (state/peek-stack
+                          (interpreter/interpret-program
+                            program
+                            (assoc state/empty-state :input {:in1 input})
+                            (:step-limit argmap))
+                          :integer))
+                      inputs)
+         errors (map (fn [correct-output output]
+                       (if (= output :no-stack-item)
+                         1000000
+                         (math/abs (- correct-output output))))
+                     correct-outputs
+                     outputs)]
+     (assoc individual
+       :behaviors outputs
+       :errors errors
+       :total-error #?(:clj  (apply +' errors)
+                       :cljs (apply + errors))))))
+
+(defn -main
+  "Runs propel-gp, giving it a map of arguments."
+  [& args]
+  (gp/gp
+    (merge
+      {:instructions             instructions
+       :error-function           error-function
+       :training-data            (:train train-and-test-data)
+       :testing-data             (:test train-and-test-data)
+       :max-generations          300
+       :population-size          1000
+       :max-initial-plushy-size  100
+       :step-limit               200
+       :parent-selection         :lexicase
+       :tournament-size          5
+       :umad-rate                0.1
+       :variation                {:umad 1.0 :crossover 0.0}
+       :elitism                  false}
+      (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+  (#?(:clj shutdown-agents)))
diff --git a/src/propeller/problems/simple_classification.cljc b/src/propeller/problems/simple_classification.cljc
new file mode 100644
index 0000000..643591f
--- /dev/null
+++ b/src/propeller/problems/simple_classification.cljc
@@ -0,0 +1,98 @@
+(ns propeller.problems.simple-classification
+  (:require [propeller.genome :as genome]
+            [propeller.push.interpreter :as interpreter]
+            [propeller.push.state :as state]
+            [propeller.gp :as gp]
+            #?(:cljs [cljs.reader :refer [read-string]])))
+
+;; =============================================================================
+;; Simple classification
+;; =============================================================================
+
+;; Set of original propel instructions
+(def instructions
+  (list :in1
+        :integer_add
+        :integer_subtract
+        :integer_mult
+        :integer_quot
+        :integer_mod
+        :integer_eq
+        :boolean_and
+        :boolean_not
+        :boolean_invert_first_then_and
+        :boolean_invert_second_then_and
+        :boolean_from_integer
+        true
+        false
+        'close
+        0
+        1
+        3))
+
+(defn- target-function
+  "If number is divisible by 3 but not 7, leave TRUE on the BOOLEAN stack else leave FALSE on the BOOLEAN stack"
+  [x]
+  (let [div-3 (= 0 (mod x 3))
+        div-7 (= 0 (mod x 7))]
+    (and div-3 (not div-7))))
+
+(def train-and-test-data
+  (let [train-inputs (range 0 100)
+        test-inputs (range 100 300)
+        train-outputs (map target-function train-inputs)
+        test-outputs (map target-function test-inputs)]
+    {:train (map (fn [in out] {:input1 (vector in) :output1 (vector out)}) train-inputs train-outputs)
+     :test (map (fn [in out] {:input1 (vector in) :output1 (vector  out)}) test-inputs test-outputs)}))
+
+(defn error-function
+  "Finds the behaviors and errors of an individual: Error is 0 if the value and
+  the program's selected behavior match, or 1 if they differ, or 1000000 if no
+  behavior is produced. The behavior is here defined as the final top item on
+  the INTEGER stack."
+  [argmap data individual]
+  (let [program (genome/plushy->push (:plushy individual) argmap)
+        inputs (map (fn [x] (first (:input1 x))) data)
+        correct-outputs (map (fn [x] (first (:output1 x))) data)
+        outputs (map (fn [input]
+                       (state/peek-stack
+                         (interpreter/interpret-program
+                           program
+                           (assoc state/empty-state :input {:in1 input})
+                           (:step-limit argmap))
+                         :boolean))
+                     inputs)
+        errors (map (fn [correct-output output]
+                      (if (= output :no-stack-item)
+                        1000000
+                        (if (= correct-output output)
+                          0
+                          1)))
+                    correct-outputs
+                    outputs)]
+    (assoc individual
+      :behaviors outputs
+      :errors errors
+      :total-error #?(:clj  (apply +' errors)
+                      :cljs (apply + errors)))))
+
+(defn -main
+  "Runs propel-gp, giving it a map of arguments."
+  [& args]
+  (gp/gp
+    (merge
+      {:instructions            instructions
+       :error-function          error-function
+       :training-data           (:train train-and-test-data)
+       :testing-data            (:test train-and-test-data)
+       :case-t-size             (count (:train train-and-test-data))
+       :max-generations         500
+       :population-size         500
+       :max-initial-plushy-size 100
+       :step-limit              200
+       :parent-selection        :lexicase
+       :umad-rate               0.1
+       :variation               {:umad 1.0 :crossover 0.0}
+       :elitism                 false}
+      (apply hash-map (map #(if (string? %) (read-string %) %) args))))
+  (#?(:clj shutdown-agents)))