From f05985361b6a35b67b879839213541823d74d4d8 Mon Sep 17 00:00:00 2001 From: Leon Rische Date: Mon, 23 Nov 2020 11:37:17 +0100 Subject: Use macro for defining properties & getters --- org-fc-algo-sm2.el | 159 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 107 insertions(+), 52 deletions(-) diff --git a/org-fc-algo-sm2.el b/org-fc-algo-sm2.el index 75fce9a..827541c 100644 --- a/org-fc-algo-sm2.el +++ b/org-fc-algo-sm2.el @@ -23,70 +23,125 @@ ;; ;;; Code: -;;;; Parameters - -(defcustom org-fc-algo-sm2-changes - '((again . -0.3) - (hard . -0.15) - (good . 0.0) - (easy . 0.15)) - "Changes to a cards ease depending on its rating." - :type 'list - :group 'org-fc) - -(defcustom org-fc-algo-sm2-fixed-intervals - '(0.0 0.01 1.0 6.0) - "Hard-coded intervals for the first few card boxes. +(defmacro org-fc-property (symbol standard doc &rest args) + (let (defcustom-args property reader) + (while args + (let ((keyword (pop args))) + (unless (symbolp keyword) + (error "Junk in args %S" args)) + (unless args + (error "Keyword %s is missing an argument" keyword)) + (let ((value (pop args))) + (case keyword + (:property (setq property value)) + (:reader (setq reader value)) + (t + (push value defcustom-args) + (push keyword defcustom-args)))))) + (unless property + (error "Missing keyword :property")) + (let ((property-symbol (intern (concat (symbol-name symbol) "-property")))) + `(progn + (defcustom + ,symbol + ,standard + ,doc + ,@defcustom-args) + (defcustom + ,property-symbol + ,property + ,(format "Headline property for `%s'" symbol) + :type 'string + :group ,(plist-get defcustom-args :group)) + (defun ,symbol () + ,(format "Getter for `%s'" symbol) + (if-let ((value (org-entry-get (point) ,property-symbol t))) + ;; TODO: Switch on possible types + (read value) + ;; ,(case (plist-get defcustom-args :type) + ;; ('string 'value) + ;; ('float '(string-to-number value)) + ;; ('list '(read value)) + ;; (t (error "Unsupported property type %s" + ;; (plist-get defcustom-args :type) + + ,symbol)))))) + +;;;; Properties + +(org-fc-property org-fc-algo-sm2-ease-min 1.3 + "Lower bound for a cards ease." + :type 'float + :group 'org-fc + :property "FC_SM2_EASE_MIN") + +(org-fc-property org-fc-algo-sm2-ease-max 5.0 + "Upper bound for a cards ease." + :type 'float + :group 'org-fc + :property "FC_SM2_EASE_MAX") + +(org-fc-property org-fc-algo-sm2-ease-initial 2.5 + "Initial ease." + :type 'float + :group 'org-fc + :property "FC_SM2_EASE_INITIAL") + +(org-fc-property org-fc-algo-sm2-fuzz-min 0.9 + "Lower bound for random interval fuzz factor." + :type 'float + :group 'org-fc + :property "FC_SM2_FUZZ_MIN") + +(org-fc-property org-fc-algo-sm2-fuzz-max 1.1 + "Upper bound for random interval fuzz factor." + :type 'float + :group 'org-fc + :property "FC_SM2_FUZZ_MAX") + +(org-fc-property org-fc-algo-sm2-changes + '((again . -0.3) + (hard . -0.15) + (good . 0.0) + (easy . 0.15)) + "Changes to a cards ease depending on its rating." + :type 'list + :group 'org-fc + :property "FC_SM2_CHANGES") + +(org-fc-property org-fc-algo-sm2-intervals + '(0.0 0.01 1.0 6.0) + "Hard-coded intervals for the first few card boxes. Values are in days." - :type 'list - :group 'org-fc) - -(defcustom org-fc-algo-sm2-ease-min 1.3 "Lower bound for a cards ease." - :type 'float - :group 'org-fc) - -(defcustom org-fc-algo-sm2-ease-initial 2.5 "Initial ease." - :type 'float - :group 'org-fc) - -(defcustom org-fc-algo-sm2-ease-max 5.0 "Upper bound for a cards ease." - :type 'float - :group 'org-fc) - -(defcustom org-fc-algo-sm2-fuzz-min 0.9 - "Lower bound for random interval fuzz factor." - :type 'float - :group 'org-fc) - -(defcustom org-fc-algo-sm2-fuzz-max 1.1 - "Upper bound for random interval fuzz factor." - :type 'float - :group 'org-fc) + :type 'list + :group 'org-fc + :property "FC_SM2_INTERVALS") ;;;; Helper Functions (defun org-fc-algo-sm2-fuzz (interval) "Apply fuzz to INTERVAL. -INTERVAL is by a random factor between `org-fc-sm2-fuzz-min' and -`org-fc-sm2-fuzz-max'" - (* - interval - (+ org-fc-sm2-fuzz-min - (cl-random (- org-fc-sm2-fuzz-max org-fc-sm2-fuzz-min))))) +INTERVAL is by a random factor between `org-fc-algo-sm2-fuzz-min' and +`org-fc-algo-sm2-fuzz-max'" + (let ((min (org-fc-algo-sm2-fuzz-min)) + (max (org-fc-algo-sm2-fuzz-max))) + (* interval (+ min (cl-random (- max min)))))) ;;;; Main Algorithm (defun org-fc-algo-sm2-next-parameters (ease box interval rating) "Calculate the next parameters of a card, based on the review RATING. EASE, BOX and INTERVAL are the current parameters of the card." - (let* ((next-ease + (let* ((intervals (org-fc-algo-sm2-intervals)) + (changes (org-fc-algo-sm2-changes)) + (next-ease (if (< box 2) ease (min (max - (+ ease (alist-get rating org-fc-sm2-changes)) - org-fc-sm2-ease-min) - org-fc-sm2-ease-max))) + (+ ease (alist-get rating changes)) + (org-fc-algo-sm2-ease-min)) + (org-fc-algo-sm2-ease-max)))) (next-box (cond ;; If a card is rated easy, skip the learning phase @@ -96,15 +151,15 @@ EASE, BOX and INTERVAL are the current parameters of the card." ;; Otherwise, move forward one box (t (1+ box)))) (next-interval - (cond ((< next-box (length org-fc-sm2-fixed-intervals)) - (nth next-box org-fc-sm2-fixed-intervals)) + (cond ((< next-box (length intervals)) + (nth next-box intervals)) ((and (eq org-fc-algorithm 'sm2-v2) (eq rating 'hard)) (* 1.2 interval)) - (t (org-fc-sm2-fuzz (* next-ease interval)))))) + (t (org-fc-algo-sm2-fuzz (* next-ease interval)))))) (list next-ease next-box next-interval))) (defun org-fc-algo-sm2-initial-review-data (position) "Initial SM2 review data for POSITION." - (list position org-fc-sm2-ease-initial 0 0 + (list position (org-fc-algo-sm2-ease-initial) 0 0 (org-fc-timestamp-now))) ;;; Footer -- cgit v1.2.3