(in-package :common-lisp-user)
(defpackage :com.stuartsierra.captcha.text.arithmetic
(:nicknames :captcha)
(:use :common-lisp)
(:export #:generate-captcha))
(in-package :com.stuartsierra.captcha.text.arithmetic)
(defvar *min-initial-value* 12)
(defvar *max-initial-value* 50)
(defvar *min-delta-value* 2)
(defvar *max-delta-value* 10)
(defvar *operations*
(list '+ '-))
(defvar *initial-state-strings*
(list "You started out with ~a."
"Before, you had ~a."
"In the beginning, there were ~a."
"Once upon a time, you had ~a."
"You were in possession of ~a."
"In the vague, distant past, ~a were your pride and joy."))
(defvar *+strings*
(list "Beneficent aliens from planet Grog gave you ~a."
"Your third cousin Warrl died and you inherited his ~a."
"By devious and suble means, you acquired an additional ~a."
"You quit your job and got ~a as part of your severance package."
"You lost them all in a stock deal, but then you got them all back plus ~a."
"You bought ~a."))
(defvar *-strings*
(list "When you least expected it, your best friend turned on you and stole ~a."
"Just as you were starting to enjoy them, ~a ran away."
"But, tragically, ~a went off to that big something-or-other in the sky."
"However, ~a didn't feel like sticking around, and left."
"After a few years, ~a and you didn't get along any more, so they left."
"Not through any fault of your own, you lost ~a."))
(defvar *question-strings*
(list "When all is said and done, what did you end up with?"
"How many did you have after that?"
"By the end of the story, you had how many?"
"Years later, when you were reflecting on this whole sordid process, you counted up how many you had. What was the result?"
"What number did you have then, after you got over the emotional shock?"
"Tell me how many you had when you finished."))
(defvar *nouns*
(list "apples" "ponies" "pieces of fruit" "PDP-10s" "laptops"
"clones of William Shatner" "Lisp Machines" "ice cream cones"
"lollipops" "oranges" "brown paper packages tied up with string"
"first-edition Superman comic books" "pairs of stiletto heels"))
(defun pick-random (list)
(nth (random (length list)) list))
(defun random-range (min max)
(+ min (random (- max min))))
(defun format-quantity (number noun)
(format nil "~r ~a" number noun))
(defun generate-initial-state-string (initial-value noun)
(format nil (pick-random *initial-state-strings*)
(format-quantity initial-value noun)))
(defun generate-change-string (operation delta-value noun)
(format nil (pick-random
(symbol-value
(find-symbol
(concatenate 'string "*"
(symbol-name operation)
(symbol-name :strings*)) :com.stuartsierra.captcha.text.arithmetic)))
(format-quantity delta-value noun)))
(defun generate-question (operation initial-value delta-value)
(let ((noun (pick-random *nouns*)))
(format nil "~a ~a ~a"
(generate-initial-state-string initial-value noun)
(generate-change-string operation delta-value noun)
(pick-random *question-strings*))))
(defun generate-answer (operation initial-value delta-value)
(format nil "~d" (funcall operation initial-value delta-value)))
(defun generate-captcha ()
(let ((initial-value (random-range *min-initial-value* *max-initial-value*))
(operation (pick-random *operations*))
(delta-value (random-range *min-delta-value* *max-delta-value*)))
(values (generate-question operation initial-value delta-value)
(generate-answer operation initial-value delta-value))))