branch: externals/org-mathsheet
commit 0038935262b0b34a52fd8cc27b2bb925dbb43607
Author: Ian Martins <ia...@jhu.edu>
Commit: Ian Martins <ia...@jhu.edu>

    initial
---
 mathsheet.org | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 159 insertions(+)

diff --git a/mathsheet.org b/mathsheet.org
new file mode 100644
index 0000000000..f290b37773
--- /dev/null
+++ b/mathsheet.org
@@ -0,0 +1,159 @@
+* goal
+the goal is to generate a math practice sheet.
+* script
+** vars
+#+property: header-args+ :var student="Noble" problem-count=24
+
+** problem sets
+*** add and subtract
+TODO support "var c in [b 5]"
+
+#+name: first-set
+#+begin_example
+var a in [1 10]
+var b in [0 10]
+var c in [1 5]
+var d in [0 15]
+problem weight 3 order 1 "a + b"
+problem weight 2 order 1 "a + d"
+problem weight 1 order 2 "a + b + c"
+problem weight 1 order 3 "a + c - b"
+#+end_example
+
+** generate problem set from template
+
+#+name: problem-set
+#+begin_src elisp :noweb yes :var template=first-set
+  (let (prob ret)
+    (dotimes (index problem-count ret)
+      (setq prob
+            <<one-problem>>)
+      (setq ret (push (list (car prob) (cdr prob)) ret ))))
+#+end_src
+
+
+#+name: one-problem
+#+begin_src elisp :var template=first-set
+  (let (vars probs prob weight order answ)
+    ;; parse input
+    (dolist (line (split-string template "\n"))
+      (pcase (read (concat "(" line ")"))
+        (`(var ,name in [,min ,max])
+         ;; assign vars
+         (push (cons name (+ (random (- max min -1)) min)) vars))
+        ((and
+          (pred (lambda (x) (eq 'problem (car x))))
+          `(problem weight ,weight order ,order ,prob))
+         ;; save problems
+         (push (cons prob weight)
+               probs))))
+    ;; choose problem given weights
+    (let ((tot (reduce
+                (lambda (tot prob) (+ tot (cdr prob)))
+                probs
+                :initial-value 0))
+          indx chosen-prob)
+      (setq indx (random tot)
+            chosen-prob (reduce
+                         (lambda (rem prob)
+                           (cond
+                            ((not (numberp rem)) rem)
+                            ((> rem 0) (setq rem (- rem (cdr prob))) (if (> 
rem 0) rem (car prob)))
+                            (t (car prob))))
+                         probs
+                         :initial-value indx))
+      ;; do replacements
+      (dolist (var vars)
+        (setq chosen-prob (replace-regexp-in-string
+                           (symbol-name (car var))
+                           (number-to-string (cdr var))
+                           chosen-prob)))
+      ;; calculate answer
+      (setq answ (calc-eval chosen-prob))
+
+      (cons chosen-prob answ)))
+#+end_src
+
+#+RESULTS: one-problem
+: (7 + 8 . 15)
+
+** lay out problems and answers
+this generates a problem set.
+
+#+name: layout-problems-answers
+#+begin_src elisp :results silent :noweb yes :var problem-set=problem-set 
problemsp='t
+      (with-temp-buffer
+          (dolist (row problem-set)
+            (if problemsp
+                (insert (format"\\CircledItem %s = 
\\rule[-.2\\baselineskip]{2cm}{0.4pt}\n\n"
+                               (car row)))
+              (insert (format "\\CircledItem %s\n\n"
+                              (cadr row)))))
+        (buffer-string))
+#+end_src
+
+** lay out page
+this wraps the problems with a tex header and footer.
+
+solution for how to enumerate with circled numbers from 
[[https://latex.org/forum/viewtopic.php?p=40006&sid=d202f756313add2391c3140fbeafe2ff#p40006][here]]
+
+#+name: page
+#+begin_src latex :results value silent :noweb yes
+  \documentclass[12pt]{article}
+  \usepackage[top=1in, bottom=0.8in, left=0.8in, right=0.8in]{geometry}
+  \usepackage{fancyhdr}
+  \newsavebox{\myheadbox}% Heading storage box
+  \usepackage{multicol}
+  \usepackage{rotating}
+  \usepackage{xcolor}
+  \usepackage{enumitem}
+  \usepackage{tikz}
+  \newcommand*\circled[1]{%
+    \tikz[baseline=(C.base)]\node[draw,circle,inner sep=1.2pt,line 
width=0.2mm,](C) {#1};}
+  \newcommand*\CircledItem{%
+    \stepcounter{enumi}\item[\circled{\theenumi}]}
+
+  \pagestyle{fancy}
+  \lhead{\textmd{\textsf{Name: student}}}
+  \rhead{\textmd{\textsf{Date: \today}}}
+  \cfoot{}
+
+  \renewcommand{\familydefault}{\ttdefault}
+
+  \begin{document}
+
+    \begin{multicols}{2}
+      \begin{enumerate}[itemsep=0.5cm]
+        <<layout-problems-answers(problemsp='t)>>
+      \end{enumerate}
+    \end{multicols}
+
+    \vspace*{0.1cm}
+    \noindent\rule{\linewidth}{0.4pt}
+    \vspace*{0.1cm}
+
+    \begin{turn}{180}
+      \begin{minipage}{\linewidth}
+        \color{gray}
+        \footnotesize
+        \begin{multicols}{4}
+          \begin{enumerate}
+            <<layout-problems-answers(problemsp='nil)>>
+          \end{enumerate}
+        \end{multicols}
+      \end{minipage}
+    \end{turn}
+
+  \end{document}
+#+end_src
+
+* generate pdf
+this writes the generated into a local file and runs ~texi2pdf~ to
+convert it to a pdf.
+
+#+begin_src elisp :results silent :var tex-content=page
+  (with-temp-file "worksheet.tex"
+    (insert tex-content))
+  (shell-command "texi2pdf worksheet.tex"
+                 (get-buffer-create "*Standard output*"))))
+#+end_src

Reply via email to