branch: externals/org-mathsheet commit d4415d4e637d73f8a62f589895d6be52ff84b48e Author: Ian Martins <ia...@jhu.edu> Commit: Ian Martins <ia...@jhu.edu>
can generate worksheets using new templates --- mathsheet.org | 214 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 121 insertions(+), 93 deletions(-) diff --git a/mathsheet.org b/mathsheet.org index 2f08aec235..854493acfe 100644 --- a/mathsheet.org +++ b/mathsheet.org @@ -1,16 +1,42 @@ * goal -the goal is to generate a math practice sheet. +The goal is to generate a math practice sheet made up of dynamic problems that are defined in flexible templates. -similar to https://www.math-aids.com +Similar to https://www.math-aids.com. * script ** vars +This sets the name at the top of the page as well as the number of +problems on the worksheet. + #+property: header-args+ :var student="Noble" problem-count=26 -** problem sets +** problem set examples +This section contains some example templates. Each table defines a +worksheet. Each time the worksheet is created the problems are +generated randomly. + +The table contains the following columns: +- weight :: the relative number of this type of problem to include on + the worksheet. +- order :: problems are ordered on the sheet in ascending order. two + problems with the same order will be intermingled. +- template :: this is the template used to generate problems of this + type. Templates are described in more detail below. +- descr :: just notes, not used in worksheet generation. + +Templates are problems but the numbers are replaced with placeholders +in square brackets. +- [0..10] :: any number from 0 to 10 +- [a=...] :: assign the variable a to the number chosen for this field +- [1,3,5] :: choose 1 or 3 or 5 +- [10/(2-1)] :: evaluate the expression +- [-2..$a] :: any number from -2 to the value assigned to a in another + placeholder +- [0..[$a/2]] :: placeholders can be embedded within placeholders + *** add and subtract #+name: firstset -| weight | order | problem | descr | +| weight | order | template | descr | |--------+-------+-------------------------------+------------------------| | 3 | 1 | [1..10] + [0..10] | simple | | 2 | 2 | [1..10] + [8..15] | second number bigger | @@ -73,12 +99,11 @@ new field to the list when we close the current field. (space (* [space])) (open (region "[") `(l r -- (progn - (setq - open-fields (push (list - (intern (concat "_" (number-to-string field-index))) - nil (copy-marker l) nil nil) - open-fields) - field-index (1+ field-index)) + (push (list + (intern (concat "_" (number-to-string field-index))) + nil (copy-marker l) nil nil) + open-fields) + field-index (1+ field-index) "."))) (assignment (region (substring letter)) "=" `(l v r -- (progn @@ -88,20 +113,14 @@ new field to the list when we close the current field. "."))) (var "$" (substring letter) `(v -- (progn - (setcar - (nthcdr 1 (car open-fields)) - (push (intern v) (nth 1 (car open-fields)))) + (push (intern v) (cadar open-fields)) "."))) (close (region "]") `(l r -- (progn - (setcar (nthcdr 3 (car open-fields)) (copy-marker l t)) + (setcar (cdddar open-fields) (copy-marker l t)) (when (> (length open-fields) 1) - (setcar - (nthcdr 1 (nth 1 open-fields)) - (push (caar open-fields) (nth 1 (nth 1 open-fields))))) - (setq - closed-fields - (push (pop open-fields) closed-fields)) + (push (caar open-fields) (cadadr open-fields))) + (push (pop open-fields) closed-fields) "."))) (letter [a-z]) (digit [0-9]) @@ -122,41 +141,41 @@ reduces. #+name: reduce-field #+begin_src elisp - (defun ianxm/reduce-field () - (interactive) - (with-peg-rules - ((field "[" space (or range sequence assignment expression value) space "]") - (expression (list value space operation space value (* space operation space value)) - `(vals -- (string-to-number - (calc-eval - (mapconcat - (lambda (x) (if (numberp x) (number-to-string x) x)) - vals - " "))))) - (operation (substring (or "+" "-" "*" "/"))) - (assignment var-lhs space "=" space (or range sequence) - `(v r -- (progn - (setq var-list (push (cons (intern v) r) var-list)) - r))) - (range value ".." value - `(min max -- (+ (random (- max min)) min))) - (sequence (list value "," value (* "," value)) - `(vals -- (seq-random-elt vals))) - (value (or (substring (opt "-") (+ digit)) var-rhs parenthetical) - `(v -- (if (stringp v) (string-to-number v) v))) - (parenthetical "(" expression ")" - (action (message "paren"))) - (var-lhs (substring letter)) ; var for assignment - (var-rhs "$" (substring letter) ; var for use - `(v -- (let ((val (alist-get (intern v) var-list))) - (or val (error "var %s not set" v))))) - (space (* [space])) - (letter [a-z]) - (digit [0-9])) - - (peg-run (peg field) - (lambda (x) (message "failed %s" x)) - (lambda (x) (funcall x))))) + (defun ianxm/reduce-field () + (interactive) + (with-peg-rules + ((field "[" space (or range sequence assignment expression value) space "]") + (expression (list value space operation space value (* space operation space value)) + `(vals -- (string-to-number + (calc-eval + (mapconcat + (lambda (x) (if (numberp x) (number-to-string x) x)) + vals + " "))))) + (operation (substring (or "+" "-" "*" "/"))) + (assignment var-lhs space "=" space (or range sequence) + `(v r -- (progn + (push (cons (intern v) r) var-list) + r))) + (range value ".." value + `(min max -- (+ (random (- max min)) min))) + (sequence (list value "," value (* "," value)) + `(vals -- (seq-random-elt vals))) + (value (or (substring (opt "-") (+ digit)) var-rhs parenthetical) + `(v -- (if (stringp v) (string-to-number v) v))) + (parenthetical "(" expression ")" + (action (message "paren"))) + (var-lhs (substring letter)) ; var for assignment + (var-rhs "$" (substring letter) ; var for use + `(v -- (let ((val (alist-get (intern v) var-list))) + (or val (error "var %s not set" v))))) + (space (* [space])) + (letter [a-z]) + (digit [0-9])) + + (peg-run (peg field) + (lambda (x) (message "failed %s" x)) + (lambda (x) (funcall x))))) #+end_src *** replace field @@ -166,8 +185,8 @@ replace a field with the value returned from processing it. #+name: replace-field #+begin_src elisp (defun ianxm/replace-field (node) - (let ((start (nth 2 node)) - (end (1+ (nth 3 node))) + (let ((start (caddr node)) + (end (1+ (cadddr node))) val) (goto-char start) (when (looking-at "\\[") @@ -188,14 +207,14 @@ check dependencies then visit the node (1 (error "cycle detected")) ; cycle (2) ; skip (_ ; process - (setcar (nthcdr 4 node) 1) ; started - (let ((deps (nth 1 node))) + (setcar (cddddr node) 1) ; started + (let ((deps (cadr node))) (dolist (dep deps) (ianxm/dfs-visit (assq dep fields) fields))) (ianxm/replace-field node) ; visit - (setcar (nthcdr 4 node) 2)))) ; mark done + (setcar (cddddr node) 2)))) ; mark done #+end_src *** fill fields in problem @@ -316,12 +335,19 @@ tangles everything needed to convert a template to a problem (- problem-count (length problems))) (t (max (round (* (/ weight total-weight) problem-count) ) 1))))) - ;; add problems to list - (dotimes (jj needed) - (let* ((problem (ianxm/fill-problem (nth 2 item))) - (answer (calc-eval problem)) - (order (nth 1 item))) - (setq problems (push (list order problem answer) problems)))))) + + ;; add just problems to list? + ;; dedup each one + ;; add until "needed" are kept + (let ((added 0) + problem-set + problem) + (while (< added needed) + (setq problem (ianxm/fill-problem (caddr item))) + (when (not (member problem problem-set)) + (push problem problem-set) + (push (list problem (calc-eval problem) (cadr item)) problems) + (setq added (1+ added))))))) ;; shuffle (dotimes (ii (- (length problems) 1)) @@ -330,10 +356,10 @@ tangles everything needed to convert a template to a problem (elt problems jj) (elt problems ii)))) ;; sort by order - (sort problems (lambda (a b) (< (car a) (car b)))) + (sort problems (lambda (a b) (< (caddr a) (caddr b)))) - ;; remove the "order" column and return - (mapcar (lambda (x) (seq-drop x 1)) problems))) + ;; return + problems)) #+end_src test with this @@ -346,30 +372,32 @@ test with this #+end_src #+RESULTS: problem-set -| 9 + 9 | 18 | -| 1 + 4 | 5 | -| 8 + 2 | 10 | -| 3 + 7 | 10 | -| 6 + 4 | 10 | -| 1 + 1 | 2 | -| 7 + 4 | 11 | -| 5 + 5 | 10 | -| 4 + 1 | 5 | -| 9 + 13 | 22 | -| 2 + 14 | 16 | -| 4 + 10 | 14 | -| 9 + 11 | 20 | -| 4 + 12 | 16 | -| 3 + 12 | 15 | -| 3 + 4 + 3 | 10 | -| 2 + 6 + 1 | 9 | -| 7 + 5 + 1 | 13 | -| 8 - 7 | 1 | -| 8 + 1 - 3 | 6 | -| 4 - 0 | 4 | -| 6 + 3 - 3 | 6 | -| 3 - 0 | 3 | -| 8 + 7 - 5 | 10 | +| 9 + 9 | 18 | 1 | +| 4 + 3 | 7 | 1 | +| 6 + 9 | 15 | 1 | +| 5 + 4 | 9 | 1 | +| 1 + 4 | 5 | 1 | +| 3 + 7 | 10 | 1 | +| 4 + 7 | 11 | 1 | +| 8 + 3 | 11 | 1 | +| 2 + 0 | 2 | 1 | +| 5 + 5 | 10 | 1 | +| 9 + 3 | 12 | 1 | +| 8 + 10 | 18 | 2 | +| 6 + 10 | 16 | 2 | +| 6 - 4 | 2 | 2 | +| 7 + 10 | 17 | 2 | +| 4 + 13 | 17 | 2 | +| 6 + 14 | 20 | 2 | +| 7 - 3 | 4 | 2 | +| 8 - 6 | 2 | 2 | +| 2 + 11 | 13 | 2 | +| 9 + 1 + 4 | 14 | 3 | +| 3 + 1 + 4 | 8 | 3 | +| 1 + 1 + 4 | 6 | 3 | +| 2 + 7 - 1 | 8 | 4 | +| 9 + 1 - 1 | 9 | 4 | +| 9 + 1 - 4 | 6 | 4 | ** lay out problems and answers this generates a problem set.