diff --git a/common-lisp/bob/README.md b/common-lisp/bob/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e954987666a4d227b0258b3925663ff343152c43 --- /dev/null +++ b/common-lisp/bob/README.md @@ -0,0 +1,70 @@ +# Bob + +Bob is a lackadaisical teenager. In conversation, his responses are very limited. + +Bob answers 'Sure.' if you ask him a question, such as "How are you?". + +He answers 'Whoa, chill out!' if you YELL AT HIM (in all capitals). + +He answers 'Calm down, I know what I'm doing!' if you yell a question at him. + +He says 'Fine. Be that way!' if you address him without actually saying +anything. + +He answers 'Whatever.' to anything else. + +Bob's conversational partner is a purist when it comes to written communication and always follows normal rules regarding sentence punctuation in English. + +## Setup + +Check out [Installing Common +Lisp](https://exercism.io/tracks/common-lisp/installation) for +instructions to get started or take a look at the guides available in +the [track's side bar](https://exercism.io/my/tracks/common-lisp). + +## Formatting + +While Common Lisp doesn't care about indentation and layout of code, +nor whether you use spaces or tabs, this is an important consideration +for submissions to exercism.io. Excercism.io's code widget cannot +handle mixing of tab and space characters well so using only spaces is recommended to make +the code more readable to the human reviewers. Please review your +editors settings on how to accomplish this. Below are instructions for +popular editors for Common Lisp. + +### VIM + +Use the following commands to ensure VIM uses only spaces for +indentation: + +```vimscript +:set tabstop=2 +:set shiftwidth=2 +:set expandtab +``` + +(or as a oneliner `:set tabstop=2 shiftwidth=2 expandtab`). This can +be added to your `~/.vimrc` file to use it all the time. + +### Emacs + +Emacs is very well suited for editing Common Lisp and has many +powerful add-on packages available. The only thing that one needs to +do with a stock emacs to make it work well with exercism.io is to +evaluate the following code: + +`(setq-default indent-tabs-mode nil)` + +This can be placed in your `~/.emacs` (or `~/.emacs.d/init.el`) in +order to have it set whenever Emacs is launched. + +One suggested add-on for Emacs and Common Lisp is +[SLIME](https://github.com/slime/slime) which offers tight integration +with the REPL; making iterative coding and testing very easy. + +## Source + +Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. [http://pine.fm/LearnToProgram/?Chapter=06](http://pine.fm/LearnToProgram/?Chapter=06) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/common-lisp/bob/bob-test.lisp b/common-lisp/bob/bob-test.lisp new file mode 100644 index 0000000000000000000000000000000000000000..5e0e29a5d31b87dde823d3a40d99e4aa8394734f --- /dev/null +++ b/common-lisp/bob/bob-test.lisp @@ -0,0 +1,191 @@ +;;; +;;; bob v1.6.0 +;;; +(ql:quickload "lisp-unit") +#-xlisp-test (load "bob") + +(defpackage #:bob-test + (:use #:common-lisp #:lisp-unit)) +(in-package #:bob-test) + +(define-test + stating-something + (assert-equal + "Whatever." + (bob:response "Tom-ay-to, tom-aaaah-to."))) + + +(define-test + shouting + (assert-equal + "Whoa, chill out!" + (bob:response "WATCH OUT!"))) + + +(define-test + shouting-gibberish + (assert-equal + "Whoa, chill out!" + (bob:response "FCECDFCAAB"))) + + +(define-test + asking-a-question + (assert-equal + "Sure." + (bob:response "Does this cryogenic chamber make me look fat?"))) + + +(define-test + asking-a-numeric-question + (assert-equal + "Sure." + (bob:response "You are, what, like 15?"))) + + +(define-test + asking-gibberish + (assert-equal + "Sure." + (bob:response "fffbbcbeab?"))) + + +(define-test + talking-forcefully + (assert-equal + "Whatever." + (bob:response "Hi there!"))) + + +(define-test + using-acronyms-in-regular-speech + (assert-equal + "Whatever." + (bob:response "It's OK if you don't want to go work for NASA."))) + + +(define-test + forceful-question + (assert-equal + "Calm down, I know what I'm doing!" + (bob:response "WHAT'S GOING ON?"))) + + +(define-test + shouting-numbers + (assert-equal + "Whoa, chill out!" + (bob:response "1, 2, 3 GO!"))) + + +(define-test + no-letters + (assert-equal + "Whatever." + (bob:response "1, 2, 3"))) + + +(define-test + question-with-no-letters + (assert-equal + "Sure." + (bob:response "4?"))) + + +(define-test + shouting-with-special-characters + (assert-equal + "Whoa, chill out!" + (bob:response "ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!"))) + + +(define-test + shouting-with-no-exclamation-mark + (assert-equal + "Whoa, chill out!" + (bob:response "I HATE THE DENTIST"))) + + +(define-test + statement-containing-question-mark + (assert-equal + "Whatever." + (bob:response "Ending with ? means a question."))) + + +(define-test + non-letters-with-question + (assert-equal + "Sure." + (bob:response ":) ?"))) + + +(define-test + prattling-on + (assert-equal + "Sure." + (bob:response "Wait! Hang on. Are you going to be OK?"))) + + +(define-test + silence + (assert-equal + "Fine. Be that way!" + (bob:response ""))) + + +(define-test + prolonged-silence + (assert-equal + "Fine. Be that way!" + (bob:response " "))) + + +(define-test + alternate-silence + (assert-equal + "Fine. Be that way!" + (bob:response " "))) + + +(define-test + multiple-line-question + (assert-equal + "Whatever." + (bob:response (format nil "~% +Does this cryogenic chamber make me look fat?~% +No.")))) + + +(define-test + starting-with-whitespace + (assert-equal + "Whatever." + (bob:response " hmmmmmmm..."))) + + +(define-test + ending-with-whitespace + (assert-equal + "Sure." + (bob:response "Okay if like my spacebar quite a bit? "))) + + +(define-test + other-whitespace + (assert-equal + "Fine. Be that way!" + (bob:response (format nil "~% + ")))) + + +(define-test + non-question-ending-with-whitespace + (assert-equal + "Whatever." + (bob:response "This is a statement ending with whitespace "))) + +#-xlisp-test +(let ((*print-errors* t) + (*print-failures* t)) + (run-tests :all)) diff --git a/common-lisp/bob/bob.lisp b/common-lisp/bob/bob.lisp new file mode 100644 index 0000000000000000000000000000000000000000..75f92e2ced904cdbc6804ab3bf7d30d1a2143a89 --- /dev/null +++ b/common-lisp/bob/bob.lisp @@ -0,0 +1,8 @@ +(in-package #:cl-user) +(defpackage #:bob + (:use #:cl) + (:export #:response)) +(in-package #:bob) + +(defun response (hey-bob)) + diff --git a/common-lisp/word-count/split-string.lisp b/common-lisp/word-count/split-string.lisp new file mode 100644 index 0000000000000000000000000000000000000000..a52a535e70653892debf1a5e9cc57f4c5b8ffa9a --- /dev/null +++ b/common-lisp/word-count/split-string.lisp @@ -0,0 +1,7 @@ +(defun split-string (string &optional (delims '(#\space #\return #\newline #\,)) (list '())) + (let ((pos-delim + (position-if (lambda (char) (position char delims)) string))) + (if pos-delim + (progn (push (subseq string 0 pos-delim) list) + (split-string (subseq string (+ 1 pos-delim)) delims list)) + (push string list)))) diff --git a/common-lisp/word-count/word-count-test.lisp b/common-lisp/word-count/word-count-test.lisp index ba517698b28f58f2eae18ba503472111f1bd798e..f2104bdd9b674a72ed221c2c5ed1d55fd963442f 100644 --- a/common-lisp/word-count/word-count-test.lisp +++ b/common-lisp/word-count/word-count-test.lisp @@ -19,11 +19,10 @@ (sort (copy-seq expected) #'string< :key #'car) (sort (copy-seq actual) #'string< :key #'car))) -(define-test - count-one-word +(define-test count-one-word (assert-alist-equal - '(("word" . 1)) - (word-count:count-words "word"))) + '(("word" . 1)) + (word-count:count-words "word"))) (define-test diff --git a/common-lisp/word-count/word-count.lisp b/common-lisp/word-count/word-count.lisp index 1ff2f6a70489abb101dc91a6716d65f8583c424a..5200c8bf361d3516fcf8e8579cba97418e7683ed 100644 --- a/common-lisp/word-count/word-count.lisp +++ b/common-lisp/word-count/word-count.lisp @@ -4,13 +4,20 @@ (:export #:count-words)) (in-package #:word-count) +(defun split-string (string &optional (delims '(#\space))) + (labels ((split-string-r (string delims list) + (let ((pos-delim (position-if (lambda (char) (position char delims)) string))) + (if pos-delim + (split-string-r (subseq string (+ 1 pos-delim)) delims (push (subseq string 0 pos-delim) list)) + (push string list))))) + (split-string-r string delims '()))) + (defun count-words (sentence) (loop - :with res-list = '() - :for x :in (uiop:split-string sentence :separator '(#\Space #\, #\Newline #\Return )) - :do (let ((word (string-downcase (string-trim "'!@#$%^&*()_+:;{}|,.-=`~<>?/" x)))) - (if (assoc word res-list :test #'string-equal) - (incf (cdr (assoc word res-list :test #'string-equal))) - (if (/= 0 (length word)) - (setq res-list (acons word 1 res-list))))) - :finally (return res-list))) + :with res-list = '() + :for x :in (split-string sentence '(#\Space #\, #\Newline #\Return)) + :for word := (string-downcase (string-trim "'!@#$%^&*()_+:;{}|,.-=`~<>?/" x)) + :for comp := (assoc word res-list :test #'string-equal) + :if comp :do (incf (cdr comp)) + :else :when (/= 0 (length word)) :do (setf res-list (acons word 1 res-list)) + :finally (return res-list)))