Bobbi Towers / Jun 02 2019

Solving equations

Solve the equation.

0.5s
Clojure
(require '[clojure.string :as str])

(defn round [n]
  (if (float? n)
    (float (/ (Math/round (* n 100)) 100)) n))

(defn parse-term [s]
  (if (Character/isDigit (first s))
    (if (str/includes? s ".")
      (Float/parseFloat s)
      (Integer/parseInt s)) (symbol s)))

(defn term1 [s op]
  (parse-term (str/trim (first (str/split s op)))))
(defn term2 [s op]
  (parse-term (str/trim (last (str/split s op)))))

(defn num? [s]
  (if-let [s (seq s)]
    (let [s (if (= (first s) \-) (next s) s)
          s (drop-while #(Character/isDigit %) s)
          s (if (= (first s) \.) (next s) s)
          s (drop-while #(Character/isDigit %) s)]
      (empty? s))))

(defn div [s]
  (let [left (first (str/split s #"/"))
        right (last (str/split s #"/"))]
    (cond
      (and (num? left) (num? right))
      (/ (term1 s #"/") (term2 s #"/"))
      (str/includes? left "-")
      [(symbol (first (str/split left #"\-")))
       (- (/ (parse-term (last (str/split left #"\-")))
             (term2 s #"/")))]
      (str/includes? right "-")
      [(symbol (last (str/split right #"\-")))
       (/ (term1 s #"/")
          (parse-term (first (str/split right #"\-"))))]
      (str/includes? right "+")
      [(/ (parse-term left)
        (parse-term (first (str/split right #"\+"))))
       (symbol (last (str/split right #"\+")))]
      (str/includes? left "+")
      [(symbol (first (str/split left #"\+")))
       (/ (parse-term (last (str/split left #"\+")))
          (term2 s #"/"))]
      :else {:numer left :denom right})))

(defn parse-exp [s]
  (cond
    (str/includes? s "+") [(parse-exp (first (str/split s #"\+")))
                           (parse-exp (last (str/split s #"\+")))]
    (re-matches #"-*(\d+\.?\d*|\d*\.?\d+)[a-zA-Z]" s)
    {:variable (re-find #"[a-zA-Z]" s)
     :multiplier (parse-term (first (re-find #"(-*\d+\.?\d*|\d*\.?\d+)" s)))}
    (str/includes? s "*") (* (term1 s #"\*") (term2 s #"\*"))
    (str/includes? s "/") (div s)
    (str/includes? s "-")
    (if (symbol? (term2 s #"\-"))
      [(term1 s #"\-") (symbol (str "-" (term2 s #"\-")))]
      [(term1 s #"\-")
       (if (number? (term2 s #"\-"))
         (- (term2 s #"\-")) (term2 s #"\-"))])
    :else (parse-term (str/trim s))))

(defn parse-eq [s]
  (let [left  (str/trim (first (str/split s #"=")))
        right (str/trim (last (str/split s #"=")))]
    {:left (parse-exp left) :right (parse-exp right)}))

(defn solve [s]
  (let [left (:left (parse-eq s))
        right (:right (parse-eq s))]
    (cond
      (:numer left)
      (str (:numer left) " = "
           (round (* (parse-term (:denom left)) right)))
      (:numer right)
      (str (:numer right) " = "
           (round (* (parse-term (:denom right)) left)))
      (:multiplier left)
      (str (:variable left) " = "
           (round (/ right (:multiplier left))))
      (:multiplier right)
      (str (:variable right) " = "
           (round (/ left (:multiplier right))))
      (number? right)
      (if (number? (last left))
        (str (first left) " = "
             (round (- right (last left))))
        (if (= "-" (str (first (str (last left)))))
          (str (str/replace (last left) "-" "") " = "
               (round (- (- right (first left)))))
          (str (last left) " = "
               (round (- right (first left))))))
      (number? left)
      (if (number? (last right))
        (str (first right) " = "
             (round (- left (last right))))
        (if (= "-" (str (first (str (last right)))))
          (str (str/replace (last right) "-" "") " = "
               (round (- (- left (first right)))))
          (str (last right) " = "
               (round (- left (first right)))))))))

(solve "2/3=z/15")
"z = 10"
(defn parse-positives [s]
  (re-seq #"\d*[a-zA-Z]|\++\d*[a-zA-Z]*" s))

(defn parse-negatives [s]
  (re-seq #"\-[a-zA-Z\d]+[a-zA-Z]*" s))

(defn parse-variables [s]
  (let [term (first (re-matches #"[\+-]*(\d+\.?\d*|\d*\.?\d+)*[a-zA-Z]" s))]
    (if (re-matches #"[\+-]*(\d+\.?\d*|\d*\.?\d+)*[a-zA-Z]" s)
      {:variable (re-find #"[a-zA-Z]+" term)
   :multiplier (if (re-find #"[\+-]*\d+" term)
                 (re-find #"[\+-]*\d+" term)
                 (if (re-find #"-" term)
                   -1 1))}
      s)))

(defn parse-terms [s]
  (map parse-variables
       (into (parse-negatives s)
             (parse-positives s))))

(parse-terms "b+7+3b-7+5+8-5")
List(7) ("+8", "+5", Map, "+7", Map, "-7", "-5")