Quiz mode
Here is a tiny emacs app just for fun. Someone asked me for a program that would test their subject knowledge prior to an exam. I could have implemented this in a million different ways and I chose emacs to make a simple keyboard driven interface.
The questions are along the lines of given a case who is the claimant and who is the defendant. The obvious data structure is a list of triples containing the name of the case and the parties. As most of emacs editing functionality is not required it makes sense to make a major mode which I will call quiz.
Specifying all of the questions took most of the time…
(defconst *quiz-questions* ‘( ["Invitation to treat" "Fisher" "Bell"] ["Offer" "Carlill" "Carbolic Smoke"] ;; … More cases )) (defconst *quiz-number-of-questions* (length *quiz-questions*)) (defvar quiz-current-question 0)
A bunch of accessors is just good style in case I decide on an alternative data structure.
(defsubst quiz-get-case (q) (aref q 0)) (defsubst quiz-get-claimant (q) (aref q 1)) (defsubst quiz-get-defendant (q) (aref q 2)) (defsubst quiz-get-number-of-parties (q) (- (length q) 1))
I store the number of the current question and the current question in quiz-current question.
(defun quiz-choose-question () (let ((n (random *quiz-number-of-questions*))) (setq quiz-current-question (cons n (nth n *quiz-questions*)))))
This user would probably like to see all of the options available at all times. Therefore asking a question should look like this:
(n)ext | (a)nswer | (q)uit Offer --> ?
…and selecting the answer should say:
(n)ext | (a)nswer | (q)uit Offer --> Carlill vs Carbolic Smoke
(defun quiz-init-buffer () (erase-buffer) (insert “(n)ext | (a)nswer | (q)uit\n\n”)) (defun quiz-display-question () (let ((q (quiz-get-case (cdr quiz-current-question)))) (insert (format “%s –> ?” q)) (backward-char))) (defun quiz-parties-to-string (c) (let ((p (quiz-get-number-of-parties c)) (claimant (quiz-get-claimant c))) (if (= p 1) (format “%s” claimant) (format “%s vs %s” claimant (quiz-get-defendant c)))))
The actual interface is provided by quiz-next-question quiz-get-answer and quiz-quit. get-answer could do with a bit of a tidy-up but for a quick hack it will do.
(defun quiz-next-question () (interactive) (quiz-init-buffer) (quiz-choose-question) (quiz-display-question)) (defun quiz-get-answer () (interactive) (let* ((q (cdr quiz-current-question)) (c (quiz-get-case q)) (p (quiz-parties-to-string q))) (quiz-init-buffer) (insert (format “%s –> %s” c p)))) (defun quiz-quit () (interactive) (when (y-or-n-p “Really quit? “) (save-buffers-kill-emacs)))
Now set up the major mode. It is a lot easier than you might think with define-derived-mode.
A quick note about the keymap: I want to disable other key-bindings. There are a couple of ways to do this: (suppress-keymap quiz-mode-map) or (define-key quiz-mode-map [t] ‘undefined). I used the second of these which disables every key you haven’t defined but I add back in M-x as I’m always scared of being trapped in a mode with no way out.
(defvar quiz-mode-map nil “Keymap for quiz major mode.”) (define-derived-mode quiz-mode text-mode “Quiz” “Major mode for interacting with databases. Special commands: \\{quiz-mode-map}”) (if quiz-mode-map nil (setq quiz-mode-map (make-sparse-keymap)) (define-key quiz-mode-map “n” ‘quiz-next-question) (define-key quiz-mode-map “a” ‘quiz-get-answer) (define-key quiz-mode-map “q” ‘quiz-quit) (define-key quiz-mode-map [t] ‘undefined) (define-key quiz-mode-map “\M-x” ‘execute-extended-command)) (defun quiz-enter-quiz-mode () (interactive) (switch-to-buffer “*quiz*” t) (random t) (quiz-mode) (quiz-next-question))
Finally, load up the defaults and enter the mode when we start.
(load “c:/packages/emacs-files/my-vars.el”) (add-to-list ‘load-path *elisp-dir*) (require ‘my-defaults) ;; … (quiz-enter-quiz-mode)
The complete file looks like this:
;; ———————————————————————- ;; (load “c:/packages/emacs-files/my-vars.el”) (add-to-list ‘load-path *elisp-dir*) (require ‘my-defaults) ;; ———————————————————————- ;; (defconst *quiz-questions* ‘( ["Invitation to treat" "Fisher" "Bell"] ["Offer" "Carlill" "Carbolic Smoke"] ;; … More cases )) (defconst *quiz-number-of-questions* (length *quiz-questions*)) (defvar quiz-current-question 0) (defsubst quiz-get-case (q) (aref q 0)) (defsubst quiz-get-claimant (q) (aref q 1)) (defsubst quiz-get-defendant (q) (aref q 2)) (defsubst quiz-get-number-of-parties (q) (- (length q) 1)) ;; ———————————————————————- ;; (defun quiz-choose-question () (let ((n (random *quiz-number-of-questions*))) (setq quiz-current-question (cons n (nth n *quiz-questions*))))) (defun quiz-display-question () (let ((q (quiz-get-case (cdr quiz-current-question)))) (insert (format “%s –> ?” q)) (backward-char))) (defun quiz-init-buffer () (erase-buffer) (insert “(n)ext | (a)nswer | (q)uit\n\n”)) (defun quiz-next-question () (interactive) (quiz-init-buffer) (quiz-choose-question) (quiz-display-question)) (defun quiz-parties-to-string (c) (let ((p (quiz-get-number-of-parties c)) (claimant (quiz-get-claimant c))) (if (= p 1) (format “%s” claimant) (format “%s vs %s” claimant (quiz-get-defendant c))))) (defun quiz-get-answer () (interactive) (let* ((q (cdr quiz-current-question)) (c (quiz-get-case q)) (p (quiz-parties-to-string q))) (quiz-init-buffer) (insert (format “%s –> %s” c p)))) (defun quiz-quit () (interactive) (when (y-or-n-p “Really quit? “) (save-buffers-kill-emacs))) ;; ———————————————————————- ;; (defvar quiz-mode-map nil “Keymap for quiz major mode.”) (define-derived-mode quiz-mode text-mode “Quiz” “Major mode for interacting with databases. Special commands: \\{quiz-mode-map}”) (if quiz-mode-map nil (setq quiz-mode-map (make-sparse-keymap)) (define-key quiz-mode-map “n” ‘quiz-next-question) (define-key quiz-mode-map “a” ‘quiz-get-answer) (define-key quiz-mode-map “q” ‘quiz-quit) (define-key quiz-mode-map [t] ‘undefined) (define-key quiz-mode-map “\M-x” ‘execute-extended-command)) (defun quiz-enter-quiz-mode () (interactive) (switch-to-buffer “*quiz*” t) (random t) (quiz-mode) (quiz-next-question)) ;; ———————————————————————- ;; (quiz-enter-quiz-mode) ;; ———————————————————————- ;;
This is the batchfile to start quiz mode.
set EMACS_FILES=c:/packages/emacs-files set EMACS_DIR=c:/packages/emacs-22.1 %EMACS_DIR%/bin/runemacs.exe -q --load %EMACS_FILES%/quiz.el
May 27th, 2008 at 9:47 am
There’s always the option of using FlashCard or similar offerings from Category Education on Emacs Wiki.