[quiz] [QUIZ #1] Solution by Stuart Sierra

Jean-Christophe Helary fusion at mx6.tiki.ne.jp
Wed May 3 16:37:29 UTC 2006


Is it possible to suggest that the CAPTCHA must be "easily"  
localizable ?

By abstarcting the translatable strings for ex ?

I would see another problem, namely the structure of the end string.

This structure should be also abstracted to a certain point so that  
languages that do not use a structure similar to English (Japanese  
for ex) could still make use of the code.

How hard would that be to have a "source" file including things like  
key=value for the localizable strings:

initial-state-string_1="something in English"
initial-state-string_1="something else in English"

that would be parsed for display, and easily translatable to any  
other language

and a "pattern" model that would be parsed to create the "generate- 
question" code ?

(I am asking because I am not a programmer by any stretch of the  
imagination, I am just here to look at some short code and learn from  
it, and I don't intend to be disruptive with my questions, but it  
happens that I am also a translator in real life and that it is one  
of the reasons I got interested in Lisp)

Sincere regards,
Jean-Christophe Helary




On 2006/05/04, at 0:07, Stuart Sierra wrote:

> This is very similar to Joseph Abrahamson's solution.  The main  
> difference is that I use separate databases for each part of the  
> question: the initial set-up, the operation (addition or  
> subtraction), and the final question.  I also got a little silly  
> with the text of the questions.
>
> This code can be extended to other operations by adding to the  
> *operations* list and creating another *Xstrings* list, where X is  
> the symbol name of the operation (e.g. +, -, *, ...).
>
> My goal was to add enough "noise" to the question that it could not  
> be solved by simple text calculators such as Google.  It's still  
> pretty easy to crack this once you know the algorithm -- just scan  
> the question string for numbers, add or subtract them, and you've  
> got a 50% chance of getting the right answer.
>
> Code attached.
> -Stuart
> ;; CAPTCHA.TEXT.ARITHMETIC
>
> ;; version 1, released 3 May 2006
>
> ;; A text-based CAPTCHA (completely automated public Turing test to
> ;; tell computers and humans apart) in ANSI Common Lisp.
>
> ;; This Lisp package has one public function, GENERATE-CAPTCHA, called
> ;; with no arguments.  It returns two strings, the first containing a
> ;; question and the second containing the answer.  The answer will
> ;; always be in the form of numerical digits.
>
> ;; Example:
>
> ;; >  (generate-captcha)
> ;; "You started out with three Lisp Machines.  You bought ten.  In the
> ;; end, how many did you have?"
> ;; "13"
>
>
> ;; Copyright 2006 Stuart Sierra
>
> ;; This program is free software; you can redistribute it and/or  
> modify
> ;; it under the terms of the GNU General Public License as  
> published by
> ;; the Free Software Foundation; either version 2 of the License, or
> ;; (at your option) any later version.
>
> ;; This program is distributed in the hope that it will be useful,
> ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
> ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> ;; GNU General Public License for more details.
>
> ;; You should have received a copy of the GNU General Public License
> ;; along with this program; if not, write to the Free Software
> ;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA   
> 02110-1301  USA
>
> ;; CAPTCHA is a trademark of Carnegie Mellon University
>
>
> (in-package :common-lisp-user)
>
> ;; package names should be descriptive ;)
> (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*)) ; to allow for lowercase readers
> 		 :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))))
> _______________________________________________
> quiz mailing list
> quiz at common-lisp.net
> http://common-lisp.net/cgi-bin/mailman/listinfo/quiz




More information about the Quiz mailing list