[quiz] [QUIZ #1] Solution by Joseph Abrahamson
Tel
abrahamson.j at gmail.com
Wed May 3 00:17:26 UTC 2006
Here's my take at it, though it's obviously the work of a beginner.
CL-USER> (captcha:generate-captcha)
"what is six plus four?"
"10"
CL-USER> (captcha:generate-captcha)
"what is the difference between five and four?"
"1"
CL-USER> (loop for x from 1 to 1000
do (captcha:generate-captcha))
NIL
~~~~~~~~~~
;;;;;;;;;;;;;;
;
; CAPTCHA
; -------
; A Completely Automated Public Turing test
; to tell Computers and Humans Apart
; generator.
; Generates simple written arithmatic problems.
;
; -- DEPENDS on:
; "Iterate":http://common-lisp.net/project/iterate/
;
;
; AUTHOR: Joseph Abrahamson
; YEAR: 2006
;
;;;;;;;;;;;;;;
(defpackage :captcha
(:use :cl)
(:export #:generate-captcha))
(in-package :captcha)
(defconstant +numbermax+ 10)
(defvar *query-strings* '((* "what is ~r times ~r?"
(gennumber gennumber))
(* "what is the product of ~r and ~r?"
(gennumber gennumber))
(* "what is the area of a ~r by ~r rectangle?"
(gennumber gennumber))
(* "If you have ~r card~:p in a deck, then give the deck away,
how many cards do you have?~*"
(gennumber 0))
(+ "what is ~r plus ~r?"
(gennumber gennumber))
(+ "what is the sum of ~r, ~r, and ~r?"
(gennumber gennumber gennumber))
(+ "if you have ~r apricot~:p and buy ~r more, how many do you have?"
(gennumber gennumber))
(- "what is ~r less ~r?"
(gennumber gennumber))
(- "what is the difference between ~r and ~r?"
(gennumber gennumber))
(- "if you have ~r dollar~:p but owe ~r, you effectively have how many?"
(gennumber gennumber))
(/ "what is ~r over ~r?"
(gennumber gennumber))
(/ "what is the quotient of ~r and ~r"
(gennumber gennumber))
(/ "if you split ~r watch~:*~[es~;~:;es~] into ~r equal group~:p,
how many are in each group?"
(gennumber gennumber))))
; Etc...
(defun gennumber (&optional (max +numbermax+) (min 0))
(+ (random (- max min)) min))
(defclass query ()
((text
:initarg :text
:initform (error "Query must have text.")
:documentation "FORMAT string to convert to captcha query.")
(string-types
:initarg :string-types
:initform (error "Query must have FORMAT args.")
:documentation "Arguments of generator functions which will
produce values for captcha.")
))
(defclass query+ (query) ())
(defclass query- (query) ())
(defclass query* (query) ())
(defclass query/ (query) ())
;; DATABASE AND SUCH
(defun generate-query-database (&optional (data *query-strings*))
(loop
for query in data
collect (let ((type (first query))
(string (second query))
(args (third query)))
(make-instance (intern (concatenate 'string
"QUERY"
(symbol-name type)))
:text string
:string-types args))))
(defvar *db* (generate-query-database))
;; PERFORM QUERY
;
; Returns a string to print and a string to be compared against as the answer.
(defgeneric perform (q &optional string-args)
(:documentation "PERFORM analyzes passed query and generates a
questionform and its
cooresponding answerform."))
(defmacro perform-values (q fn string-args)
(let ((s-a string-args))
`(values (apply #'format (append (list nil (slot-value ,q 'text))
,s-a))
(format nil "~a" (reduce ,fn ,s-a)))))
(defmethod perform :around ((q query) &optional string-args)
(call-next-method q (or string-args
(mapcar (lambda (x)
(typecase x
(list (apply (car x) (cdr x)))
(symbol (if (fboundp x)
(funcall x)
(error "Symbol ~A is not bound to function. Must be removed
from args list of query ~a" x q)))
(t x)))
(slot-value q 'string-types)))))
(defmethod perform ((q query/) &optional (string-args ()))
; Avoid division by 0.
(perform-values q #'/ (substitute-if (gennumber +numbermax+ 1)
#'zerop string-args)))
(defmethod perform ((q query*) &optional (string-args ()))
(perform-values q #'* string-args))
(defmethod perform ((q query+) &optional (string-args ()))
(perform-values q #'+ string-args))
(defmethod perform ((q query-) &optional (string-args ()))
(perform-values q #'- (sort (copy-list string-args) #'>)))
;; GENERATE-CAPTCHA
(defun generate-captcha (&key type (db *db*))
"Produces a random CAPTCHA from DB. If TYPE is supplied, only CAPTCHAs of that
type may be returned."
(let ((db (remove-if (if type
(lambda (x)
(not (eq (type-of x) type)))
(constantly nil))
db)))
(perform (elt db (random (length db))))))
~~~~~~~~~~
Cheers.
--
~ja.
More information about the Quiz
mailing list