This question already has answers here:
Lisp randomize and using two functions to pull from list into another
(2 answers)
Closed 8 years ago.
Hey guys I'm new here and I was wondering if you guys can give me any help. I'm creating a candy machine that dispense colors randomly.I've ran this code and it goes on for 7 times for (get-candy gummy-bear) but it should go for 4 times till nil.
So heres my code:
;;; function get-candy
(defun get-candy (machine)
(funcall machine))
;;; variable colors
(defvar *colors* '(red blue green brown yellow purple))
;;; function generate-candy-supply
(defun generate-candy-supply (num)
(if (= 0 num)
(cons (nth (+ 1 (random (- (length *colors*) 1))) *colors*) *colors* )
(generate-candy-supply (- num 1))))
;;; function candy-machine
(defun candy-machine (candy)
(function
(lambda ()
(prog1 (car candy)
(setq candy (cdr candy))))))
;;; variable gummy-bear
(defvar *gummy-bear*
(candy-machine (generate-candy-supply 4)))
;;; variable easter-egg
(defvar *easter-egg*
(candy-machine (generate-candy-supply 6)))
And the sample run should look like this:
[1]> (load 'candy.lisp)
;; Loading file candy.lisp ...
;; Loaded file candy.lisp
T
[2]> (get-candy *gummy-bear*)
BLUE
[3]> (get-candy *gummy-bear*)
BROWN
[4]> (get-candy *gummy-bear*)
YELLOW
[5]> (get-candy *gummy-bear*)
YELLOW
[6]> (get-candy *gummy-bear*)
NIL
[7]> (get-candy *easter-egg*)
BLUE
[8]> (get-candy *easter-egg*)
BROWN
[9]> (get-candy *easter-egg*)
GREEN
[10]> (get-candy *easter-egg*)
BROWN
[11]> (get-candy *easter-egg*)
YELLOW
[12]> (get-candy *easter-egg*)
BLUE
[13]> (get-candy *easter-egg*)
NIL
Your problem is the function generate-candy-supply. It has two branches depending on num. If it is not 0 you recurse with (1- num) and do nothing else. When num is 0 you return a list starting with a random element of *colors* followed by the elements of *colors*. This will always yield a list with exactly 7 elements.
I'll leave it at this for now, so you can have a try at figuring a solution out. Feel free to ask further questions in the comments.
Related
I'm using a function that uses a mapcar to apply a (simple) function to all members of a list, like this :
(mapcar 'my-concat-function '(
"/path/one.php"
"/path/two.php"))
But I want to use directory-files to generate the file list and filter it, something like this :
(mapcar 'my-concat-function '(
(directory-files "/path/" nil "\\.php$")))
But I always get a
find-file-noselect: Wrong type argument: stringp, (directory-files "/path/" nil "\\.php$")
When I evaluate
(directory-files "/path/" nil "\\.php$")
It returns
("one.php" "two.php" "three.php" ...)
(I did not add the "..." ; Emacs did. No matter the size of the list, it seems to always end with "...")
Question :
How can I format the output of directory-files so that it produces exactly what mapcar wants, a single list of atoms, I don't really know how to call this form :
"one.php" "two.php" "three.php"
Without the parenthesis, and without those weird "..."?
EDIT
When I try the forms suggested (thank you guys) the quoted function as 1st arg of mapcar does not work (the regexp don't find anything, all files end up open in empty (?) buffers) anymore :(
Here is the full code, thank you very much for helping, it's weird, this function took very little time to write, and now i'm blocked since hours on this simple list issue, arg.
(defun px-bpm-parse (fname)
"Extract elements. Basic Project Management."
(setq in-buf (set-buffer (find-file fname)))
(setq u1 '())
(setq u2 '())
(setq u3 '())
(setq project-dir "/var/www/html/microlabel.git/")
(beginning-of-buffer)
(while
(re-search-forward "^.*<link.*href=\"\\([^\"]+\\)\".*rel=\"stylesheet\"" nil t)
(when (match-string 0)
(setq url (match-string 1) )
(setq u3 (cons (concat "[[file:" project-dir url "][" url "]]\n") u3))))
(beginning-of-buffer)
(while
(re-search-forward "^.*<a.*href=\"\\([^\"]+\\)\"[^>]+>\\([^<]+\\)</a>" nil t)
(when (match-string 0)
(setq url (match-string 1) )
(setq title (match-string 2) )
(setq u1 (cons (concat "[[file:" project-dir url "][" title "]]\n") u1))))
(beginning-of-buffer)
(while
(re-search-forward "^.*<script.*src=\"\\([^\"]+\\)\"" nil t)
(when (match-string 0)
(setq url (match-string 1) )
(setq u2 (cons (concat "[[file:" project-dir url "][" url "]]\n") u2))))
(beginning-of-buffer)
(progn
(with-current-buffer "BPM.org"
(insert "** File: ")
;; (org-insert-link &optional COMPLETE-FILE LINK-LOCATION DEFAULT-DESCRIPTION)
(insert fname)
(insert "\n*** HREF Links (by name)\n")
(mapcar 'insert u1)
(insert "\n*** SCRIPT Links\n")
(mapcar 'insert u2)
(insert "\n*** CSS Links\n")
(mapcar 'insert u3)
(insert "\n\n"))
(switch-to-buffer "BPM.org")
(org-mode)))
(defun px-bpm ()
;; (defun px-bpm (prj-root)
"List all links"
(interactive)
;; (interactive "sEnter project root directory ")
(progn
(with-current-buffer (get-buffer-create "BPM.org")
(insert "* File dependencies\n\n"))
;; (mapcar 'px-bpm-parse '(
;; "/var/www/html/microlabel.git/add.php"
;; ))
(mapcar 'px-bpm-parse (directory-files "/var/www/html/microlabel.git/" nil "\\.php$"))
))
When you evaluate a form and see a result of the form (x y z ...), it's just printed in that way because the output is long. The result is actually the list that you'd expect. For instance,
(list 1 2 3 4 5 6 7 8 9 10 11 12 13)
;=> (1 2 3 4 5 6 7 8 9 10 11 12 ...)
Yet, the last element of the list is what it should be:
(last (list 1 2 3 4 5 6 7 8 9 10 11 12 13))
;=> (13)
Since (directory-files "/path/" nil "\\.php$") returns a list and the second argument to mapcar should be a list, you can make it the second argument:
(mapcar 'my-concat-function (directory-files "/path/" nil "\\.php$"))
I think it is apparent from this code what I'm trying to do, that is, change 'blue to 'purple:
CL-USER> (defparameter myassoc '((color red blue) (shape circle square)))
MYASSOC
CL-USER> myassoc
((COLOR RED BLUE) (SHAPE CIRCLE SQUARE))
CL-USER> (defun getsecondof (assoc) (second (rest (assoc assoc myassoc))))
GETSECONDOF
CL-USER> (getsecondof 'color)
BLUE
CL-USER> (setf (getsecondof 'color) 'purple)
; in: SETF (GETSECONDOF 'COLOR)
; (FUNCALL #'(SETF GETSECONDOF) #:NEW954 'COLOR)
; ==>
; (SB-C::%FUNCALL #'(SETF GETSECONDOF) #:NEW954 'COLOR)
;
; caught STYLE-WARNING:
; undefined function: (SETF GETSECONDOF)
;
Now, if instead of using my own function getsecondof with setf I instead pass a built-in CL expression to extract the location I want to change, it works.
Is it possible to use custom getters as setters with setf?
You need to define a setf for it:
(defun (setf getsecondof) (assoc value)
(setf (caddr (assoc assoc myassoc)) value)) ; (caddr x) == (second (rest x))
(setf (getsecondof 'color) 'purple) ; ==> PURPLE
(getsecondof 'color) ; ==> PURPLE
You have do define a setf function.
http://www.lispworks.com/documentation/HyperSpec/Body/m_defset.htm#defsetf
I'd like to control the color of the text displayed in Common Lisp.
Something like this pseudo-code:
(print-color (:red "hello") (:blue "world"))
Is there any way this can be done? I use SBCL and my repl is inside emacs.
Thanks!
You can use ANSI escape code to print colorful texts:
(format t "~c[31mabc~c[0m~%" #\ESC #\ESC) ; this prints a red "abc" for most modern terminals
I'm not sure whether this works in slime, although.
To enable ANSI color escape sequences, load the http://melpa.org/#/slime-repl-ansi-color package — but due to a bug, you may have to M-x slime-repl-ansi-color-mode RET in the REPL buffer. Distilled from various abandoned buggy versions, find the best and latest version at https://gitlab.com/augfab/slime-repl-ansi-color
slime-repl-ansi-color.el
(require 'ansi-color)
(require 'slime)
(define-minor-mode slime-repl-ansi-color-mode
"Process ANSI colors in Lisp output."
nil
:lighter " SlimeANSI")
(define-slime-contrib slime-repl-ansi-color
"Turn on ANSI colors in REPL output"
(:authors "Max Mikhanosha")
(:license "GPL")
(:slime-dependencies slime-repl)
(:on-load
(add-hook 'slime-repl-mode-hook 'slime-repl-ansi-color-mode)))
(defadvice slime-repl-emit (around slime-repl-ansi-colorize activate compile)
"Process ANSI colors in the Lisp output."
(with-current-buffer (slime-output-buffer)
(let ((start slime-output-start))
(setq ad-return-value ad-do-it)
(when slime-repl-ansi-color-mode
(ansi-color-apply-on-region start slime-output-end)))))
(provide 'slime-repl-ansi-color)
In your .emacs init file, something like
(add-to-list 'slime-contribs 'slime-repl-ansi-color)
should enable the slime repl expression
(format t "~c[31mRed~:*~c[32mGreen~:*~c[34mBlue~:*~c[mPlain~%" (code-char 27))
to produce varicolored output. Try
(ql:quickload :cl-ansi-text)
(cl-ansi-text:with-color (:green :style :background)
(cl-ansi-text:with-color (:yellow :effect :bright)
(princ " Yellow on Green ")))
(princ (cl-ansi-text:green
(cl-ansi-text:yellow " Yellow on Green " :effect :bright)
:style :background))
(defun color-text (string color); ANSI escape code
(let((color
(cond
((string= color "red") "31")
((string= color "green") "32")
((string= color "yellow") "33")
((string= color "white") "37")
((string= color "bright blue") "94")
((string= color "bright yellow") "93")
((string= color "bright cyan") "96")
((string= color "bright magneta") "95")
(t "90")
)))
(format t (concatenate 'string "~c[" color "m" ) #\ESC )
(eval(read-from-string string))
(format t (concatenate 'string "~c[" color "m~c[0m" ) #\ESC #\ESC))
); (color-text "(format t \"~a\" \"ADASDASDASDA dsfsdf\")" "red")
I have code to change default color theme. I prefer this way because I add more classes then default font-lock.
(defmacro /construct-face (name comment &rest args)
"Define face and specify attributes."
(list 'progn
(list 'defface name nil comment)
(nconc (list 'set-face-attribute (list 'quote name) nil) args)))
(/construct-face ⋅function-name "Face to highlight functions."
:foreground "SlateBlue")
(setq font-lock-function-name-face '⋅function-name)
(/construct-face ⋅comment "Face to display comments"
:foreground "gray20"
:bold t)
(setq font-lock-comment-face '⋅comment)
Weirdness is that comment colors became gray, but function's names did not became purple. What is the difference and what should I try to check?
Because it is not "gray20" but "grey20", I made this mistake yesterday as well, but with grey10.
I know that to (funcall (car (nth (random (length color-themes)) color-themes))) gives me a random color theme on every Emacs startup; but I hardly restart Emacs. How do I cycle between random color themes, say, every hour?
(defun random-color-theme ()
(interactive)
(random t)
(funcall (car (nth (random (length color-themes)) color-themes))))
(random-color-theme)
(run-with-timer 1 (* 60 60) 'random-color-theme)
Credit goes to ggole # #emacs (freenode); and aecrvol (below) for the (random t) tip.
A little improvment: adding to the function (random t),
otherwise generated sequence will be the same in each Emacs run (
from http://www.gnu.org/software/emacs/elisp/html_node/Random-Numbers.html).
(defun random-color-theme ()
(interactive)
(random t) ; randomazing
(funcall (car (nth (random (length color-themes)) color-themes))))
Here is my update:
(setq color-themes (custom-available-themes))
(defun random-color-theme ()
(interactive)
(random t)
(load-theme
(nth (random (length color-themes)) color-themes)
t))
(random-color-theme)
(run-with-timer 1 (* 60 60) 'random-color-theme)