Commit c56a122c authored by Bruno Burke's avatar Bruno Burke 😁

add basic check (with fixed points) for text-correction, also check if corrections are still valid

parent 94c23c52
Pipeline #26310 passed with stages
in 2 minutes and 40 seconds
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
:list :list
:simple-text :simple-text
:sorting :sorting
} #_(get-types-set)) } #_(get-types-set))
(s/def :exercise/answers (s/coll-of ::answer :kind vector? :min-count 1 :distinct true)) (s/def :exercise/answers (s/coll-of ::answer :kind vector? :min-count 1 :distinct true))
(ns lernmeister.components.exercise-types.text-correction.check (ns lernmeister.components.exercise-types.text-correction.check
(:require [lernmeister.components.exercise-types.check :as e-check])) (:require [lernmeister.components.exercise-types.check :as e-check]
[lernmeister.components.exercise-types.text-correction.common :refer [split-text]]
[clojure.string :refer [join]]))
(defn sc-get-points [answer-options answer]
(reduce +
(map (fn [ao]
(if (= (:id ao) answer)
(:selected-points ao)
(:unselected-points ao)))
(defn single-choice-check [exercise answer callback] (defn apply-corrections [text corrections]
(let [answer-options (get-in exercise [:core :answers]) (join
points (sc-get-points answer-options answer)] (map-indexed
(fn [index text-fragment]
(let [fragment-id (str index "-" text-fragment)]
(if-let [correction (get corrections fragment-id)]
(split-text text))))
(defn text-correction-check [exercise answer callback]
(let [text (get-in exercise [:core :correction-text])
reference-corrections (into {}
(map (fn [[id correction]]
(vector id (:correct-word correction)))
(get-in exercise [:core :corrections])))
user-corrections (into {}
(map (fn [[id correction]]
(vector id (:correct-word correction)))
reference-text (apply-corrections text reference-corrections)
user-text (apply-corrections text user-corrections)
points (if (= reference-text user-text)
(println reference-corrections)
(println reference-text)
(println user-corrections)
(println user-text)
(callback) (callback)
{:answer-id answer {:corrections answer
:correct (pos? points) :correct (pos? points)
:points points :points points
:points-max (apply max :points-max 5}))
(map #(sc-get-points answer-options (:id %))
(defmethod e-check/check-answer :text-correction [exercise answer callback] (defmethod e-check/check-answer :text-correction [exercise answer callback]
(single-choice-check exercise answer callback)) (text-correction-check exercise answer callback))
(ns lernmeister.components.exercise-types.text-correction.common
(:require [clojure.string :refer [split]]))
(defn split-text [text]
(-> text
;;(split #"(\ |\. |\,)")
(split #"(\b[\wäÄöÖüÜß]+|\W)")
(filter not-empty)
(defn valid-correction? [text correction]
(let [fragments (split-text text)]
(>= (count fragments) (:index correction))
(= (nth fragments (:index correction))
(:word correction)))))
...@@ -16,6 +16,6 @@ ...@@ -16,6 +16,6 @@
:additional-forms #?(:cljs edit-view/additional-forms :clj nil)} :additional-forms #?(:cljs edit-view/additional-forms :clj nil)}
:prepare prepare/prepare :prepare prepare/prepare
:renderer #?(:cljs show-view/exercise-renderer :clj nil) :renderer #?(:cljs show-view/exercise-renderer :clj nil)
:checker check/single-choice-check :checker check/text-correction-check
:spec ::tc-spec/single-choice}) :spec ::tc-spec/text-correction})
...@@ -4,25 +4,22 @@ ...@@ -4,25 +4,22 @@
:clj :clj
(:require [clojure.spec.alpha :as s]))) (:require [clojure.spec.alpha :as s])))
(s/def :text-correction/unselected-points number?) (s/def :correction/word string?)
(s/def :text-correction/selected-points number?) (s/def :correction/index number?)
(s/def :text-correction/answer (s/keys :req-un [:answer/id (s/def :correction/correct-word string?)
:answer/text (s/def :text-correction/correction-text string?)
:text-correction/selected-points (s/def :text-correction/correction (s/keys :req-un [:correction/word
:text-correction/unselected-points])) :correction/index
(s/def :text-correction/answers (s/and :correction/correct-word]))
(s/coll-of :text-correction/answer (s/def :text-correction/corrections (s/and
:kind vector? (s/map-of string?
:min-count 1 :text-correction/correction)))
:distinct true)
#(= 1 (count (filter (comp pos? :selected-points) %)))))
(s/def :text-correction/type #{:text-correction}) (s/def :text-correction/type #{:text-correction})
(s/def :text-correction/core (s/and (s/keys :req-un [:text-correction/answers (s/def :text-correction/core (s/and (s/keys :req-un [:text-correction/correction-text
:text-correction/type] :text-correction/corrections
:opt-un [:exercise/shuffled :text-correction/type])))
#(= 1 (count (filter (comp pos? :selected-points) (:answers %))))))
(s/def ::text-correction (s/keys :req-un [:text-correction/core])) (s/def ::text-correction (s/keys :req-un [:text-correction/core]))
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
(:require [reagent.core :as reagent] (:require [reagent.core :as reagent]
[lernmeister.components.ui :as ui] [lernmeister.components.ui :as ui]
[lernmeister.components.exercise-types.edit :as e-edit] [lernmeister.components.exercise-types.edit :as e-edit]
[clojure.string :refer [split]]) [lernmeister.components.exercise-types.text-correction.common :refer [split-text valid-correction?]])
(:use [lernmeister.components.jshelper :only [get-unique-id try-number-parse]] (:use [lernmeister.components.jshelper :only [get-unique-id try-number-parse]]
[lernmeister.components.helper :only [vec-remove]])) [lernmeister.components.helper :only [vec-remove]]))
...@@ -48,24 +48,24 @@ ...@@ -48,24 +48,24 @@
#(swap! all-options vec-remove index)} [:i.material-icons "remove"]]]])) #(swap! all-options vec-remove index)} [:i.material-icons "remove"]]]]))
(defn selectable-text [text & {:keys []}] (defn selectable-text [text & {:keys []}]
(let [component-id (gensym "selectable-text")]
(fn [text & {:keys [on-select]}] (fn [text & {:keys [on-select]}]
[:<> [:<>
[:div [:div
(map-indexed (map-indexed
(fn [index text-fragment] (fn [index text-fragment]
(let [fragment-id (str index "-" text-fragment)] (let [fragment-id (str index "-" text-fragment)]
^{:key (str component-id "-" fragment-id)}
[:span.text-fragment [:span.text-fragment
{:id fragment-id {:id fragment-id
:on-click #(on-select fragment-id text-fragment index)} :on-click #(on-select fragment-id text-fragment index)}
text-fragment text-fragment
])) ]))
(-> text (split-text text)
(split #"(\ |\. |\,)")
) )
]] ]]
) )
) ))
(defn new-exercise-form [core] (defn new-exercise-form [core]
(let [edit-text (reagent/atom nil)] (let [edit-text (reagent/atom nil)]
...@@ -105,11 +105,16 @@ ...@@ -105,11 +105,16 @@
[:th {:width "10%"} ""] [:th {:width "10%"} ""]
]] ]]
[:tbody [:tbody
(for [[id c] (:corrections @core)] (doall
(for [[id c] (sort-by :index (:corrections @core))]
^{:key (str "tcorrection_" id)} ^{:key (str "tcorrection_" id)}
[:tr [:tr
[:td (:word c)] [:td (:word c)]
[:td (str (:index c))] [:td
(if (valid-correction? (:correction-text @core) c)
(str (:index c))
[:span [:i.material-icons.left "error"] "Korrektur nicht mehr gültig"])
[:td [:input {:type :text [:td [:input {:type :text
:on-change #(swap! core :on-change #(swap! core
update-in [:corrections id] update-in [:corrections id]
...@@ -119,7 +124,7 @@ ...@@ -119,7 +124,7 @@
[:td [:a.btn.btn.flat [:td [:a.btn.btn.flat
{:on-click #(swap! core update :corrections dissoc id)} {:on-click #(swap! core update :corrections dissoc id)}
[:i.material-icons "delete"]]]] [:i.material-icons "delete"]]]]
) ))
]] ]]
])}))) ])})))
...@@ -6,11 +6,13 @@ ...@@ -6,11 +6,13 @@
[ :as ce-ex] [ :as ce-ex]
[lernmeister.components.content-elements.exercise.task-description [lernmeister.components.content-elements.exercise.task-description
:refer [default-task-description]] :refer [default-task-description]]
[lernmeister.components.exercise-types.text-correction.common :refer [split-text]]
[clojure.string :refer [split]])) [clojure.string :refer [split]]))
(defn correctable-text [text & {:keys []}] (defn correctable-text [text & {:keys []}]
(let [edit? (reagent/atom nil) (let [edit? (reagent/atom nil)
edit-text (reagent/atom nil)] edit-text (reagent/atom nil)
component-id (gensym "correctable-text")]
(fn [text & {:keys [on-select corrections (fn [text & {:keys [on-select corrections
on-delete]}] on-delete]}]
[:<> [:<>
...@@ -22,23 +24,24 @@ ...@@ -22,23 +24,24 @@
correction (get corrections fragment-id) correction (get corrections fragment-id)
edit-fragment? (= @edit? fragment-id)] edit-fragment? (= @edit? fragment-id)]
(if-not edit-fragment? (if-not edit-fragment?
^{:key (str fragment-id "-" edit-fragment?)} ^{:key (str component-id "-" fragment-id "-" edit-fragment?)}
[:span.text-fragment [:span.text-fragment
{:id fragment-id {:id fragment-id
:class (when correction :class (when correction
"corrected") "corrected")
:on-click #(do :on-click #(do
(reset! edit? fragment-id) (reset! edit? fragment-id)
(reset! edit-text (or correction (reset! edit-text (or (:correct-word correction)
text-fragment)))} text-fragment)))}
(or correction text-fragment) (or (:correct-word correction)
] ]
^{:key (str fragment-id "-" edit-fragment?)} ^{:key (str component-id "-" fragment-id "-" edit-fragment?)}
[:div.input-field.inline {:style {:margin "0px"}} [:div.input-field.inline {:style {:margin "0px"}}
[:input.browser-default {:type :text [:input.browser-default {:type :text
:value @edit-text :value @edit-text
:on-change #(reset! edit-text (-> % .-target .-value)) :on-change #(reset! edit-text (-> % .-target .-value))
}] :auto-focus true}]
[:a.btn.btn-flat [:a.btn.btn-flat
{:on-click #(do {:on-click #(do
(on-delete fragment-id) (on-delete fragment-id)
...@@ -53,10 +56,8 @@ ...@@ -53,10 +56,8 @@
[ "save"]] [ "save"]]
] ]
))) )))
(-> text (split-text text))
(split #"(\ |\. |\,)")
) )
]] ]]
) )
...@@ -78,7 +79,7 @@ ...@@ -78,7 +79,7 @@
[default-task-description (:task-description exercise)] [default-task-description (:task-description exercise)]
[correctable-text (:correction-text exercise) [correctable-text (:correction-text exercise)
:corrections answer :corrections answer
:on-select #(on-change (assoc answer %1 %2)) :on-select #(on-change (assoc answer %1 {:correct-word %2}))
:on-delete #(on-change (dissoc answer %1))] :on-delete #(on-change (dissoc answer %1))]
(when result (when result
[:span.secondary-content [:b (str (:points result) "P")]])]])) [:span.secondary-content [:b (str (:points result) "P")]])]]))
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment