[ prog / sol / mona ]

sol


What Is To Be Done?

11 2021-08-28 16:43

Why won't anyone think of the Americans! *sobs lightly*

(defvar my/prompt-returns
  (cl-mapcan
   #'(lambda (a)
       (mapcar
        #'(lambda (b)
            (cons (format "%d * %d = ?" a b) (* a b)))
        (number-sequence a 9)))
   (number-sequence 2 9)))

(defun my/times-table-helper (time-expectation prompt-return-alist)
  (let (incorrect-alist)
    (while prompt-return-alist
      (let* ((too-slow-p)
             (timer (run-with-timer time-expectation nil #'(lambda () (setq too-slow-p t))))
             (q-and-a (seq-random-elt prompt-return-alist))
             (attempt (read-number (format "Evaluate: %s\n" (car q-and-a)))))
        (cancel-timer timer)
        (cond ((/= attempt (cdr q-and-a))
               (message (format "You answered %d instead of %d." attempt (cdr q-and-a)))
               (push q-and-a incorrect-alist))
              (too-slow-p
               (message "You answered too slowly.")
               (push q-and-a incorrect-alist))
              (t (message "Correct!")))
        (setq prompt-return-alist (remove q-and-a prompt-return-alist))
        (sleep-for 0.5)))
    incorrect-alist))

(defun my/times-table (time-expectation)
  (interactive "P")
  (cond ((not time-expectation) (setq time-expectation 2))
        ((not (floatp time-expectation)) (error "time-expectatation must be a float."))
        ((<= time-expectation 0) (error "time-expectatation must be positive.")))
  (let ((prompt-return-alist my/prompt-returns))
    (while (setq prompt-return-alist
                 (my/times-table-helper time-expectation prompt-return-alist))
      (prin1 prompt-return-alist))))
12 2021-09-02 20:48

>>11
This is version 2, save the Americans edition, get it while supplies last!

;;; DATA-STRUCTURE
(defun my/make-question (prompt response required-time)
  (list prompt response required-time))

(defun my/required-time (question) (nth 2 question))
(defun my/response (question) (nth 1 question))
(defun my/prompt (question) (nth 0 question))

;;; MAIN LOOP
(defun my/quiz-round (randomp prompts)
  (let (incorrect timelyp q-and-a attempt)
    (while prompts
      (unwind-protect
          (setq q-and-a (if randomp (seq-random-elt prompts) (car prompts))
                prompts (delete q-and-a prompts)
                timelyp (let ((time (my/required-time q-and-a)))
                          (or (not time) (run-with-timer time nil #'(lambda () (setq timelyp)))))
                attempt (read-number (format "Evaluate: %s\n" (my/prompt q-and-a))))
        (when (timerp timelyp) (cancel-timer timelyp)))
      (cond ((/= attempt (my/response q-and-a))
             (message (format "You answered %d instead of %d." attempt (my/response q-and-a)))
             (push q-and-a incorrect)
             (sleep-for 0.5))
            ((not timelyp)
             (message "You answered too slowly.")
             (push q-and-a incorrect))
            (t (message "Correct!")))
      (sleep-for 0.5))
    incorrect))

(defun my/quiz (randomp prompts)
  (while (setq prompts (my/quiz-round randomp prompts))
    ;; (prin1 prompts)
    (message "New Round!")
    (sleep-for 2)))

;;; USER-INTERFACE
(defmacro my/time-check (required-time default)
  `(cond ((not ,required-time) (setq ,required-time ,default))
         ((not (floatp ,required-time))
          (error ,(concat (symbol-name required-time) " must be a float.")))
         ((<= ,required-time 0)
          (error ,(concat (symbol-name required-time) " must be positive.")))))

(defun my/beginner-multiplication-quiz (required-time)
  (interactive "P")
  (my/time-check required-time 2)
  (my/quiz t (my/basic-times-table required-time)))

(defun my/intermediate-multiplication-problems-quiz (digit-time)
  (interactive "P")
  (my/time-check digit-time 4)
  (my/quiz nil (my/random-multiplication-problems 10 digit-time '(1000 100000) '(2 10))))

(defun my/advanced-multiplication-problems-quiz (digit-time)
  (interactive "P")
  (my/time-check digit-time 4)
  (my/quiz nil (my/random-multiplication-problems 10 digit-time '(1000 100000) '(100 1000))))

(defun my/intermediate-division-problems-quiz (digit-time)
  (interactive "P")
  (my/time-check digit-time 4)
  (my/quiz nil (my/random-division-problems 10 digit-time '(1000 100000) '(2 10))))

(defun my/advanced-division-problems-quiz (digit-time)
  (interactive "P")
  (my/time-check digit-time 4)
  (my/quiz nil (my/random-division-problems 10 digit-time '(1000 100000) '(100 1000))))

;;; DATA-SETS
(defun my/basic-times-table (required-time)
  (cl-mapcan
   #'(lambda (a)
       (mapcar
        #'(lambda (b)
            (my/make-question (format "%d * %d = ?" a b) (* a b) required-time))
        (number-sequence a 9)))
   (number-sequence 2 9)))

(defun my/bounded-random (min max)
  (+ (mod (random) (- max min)) min))

(defmacro my/generator (number fun)
  (let ((prompts (gensym))
        (i (gensym)))
    `(let (,prompts)
       (dotimes (,i ,number ,prompts)
         (push (,fun ,i) ,prompts)))))

(defmacro my/defun-random-arithmetic (name bindings fun)
  `(defun ,name (number digit-time bounds1 bounds2)
     (my/generator
      number
      (lambda (_)
        ((lambda ,bindings ,fun)
         (my/bounded-random (cadr bounds1) (car bounds1))
         (my/bounded-random (cadr bounds2) (car bounds2)))))))

(my/defun-random-arithmetic
 my/random-multiplication-problems (a b)
 (my/make-question (format "%d * %d = ?" a b) (* a b) (* digit-time (ceiling (log10 (* a b))))))

(my/defun-random-arithmetic
 my/random-division-problems (a b)
 (my/make-question (format "%d / %d = ?" (* a b) b) a (* digit-time (ceiling (log10 (* a b))))))
42


VIP:

do not edit these