emacs.d/CL-gentle-intro/variables-side-effects.lisp

96 lines
4.1 KiB
Common Lisp

;;; Chapter 5 - Variables and Side Effects
;;; Exercises
;;; Ex 5.1
;;; Rewrite function POOR-STYLE to create a new local variable Q using LET, instead of using SETF to change P.
;;; Call your new function GOOD-STYLE.
(defun poor-style (p)
(setf p (+ p 5))
(list 'result 'is p))
(defun good-style (p)
(let ((q (+ p 5)))
(list 'result 'is q)))
;;; Ex 5.6 a
;;; Write a function THROW-DIE that returns a random number from 1 to 6, inclusive. Remember that (RANDOM 6) will pick numbers from 0 to 5.
;;; THROW-DIE doesn't need any inputs, so its argument list should be NIL.
(defun throw-die ()
"Returns a random number from 1 to 6."
(+ (random 6) 1))
;;; Ex 5.6 b
;;; Write a function THROW-DICE that throws two dice and returns a list of two numbers: the value of the first die and the value of the second. We'll call this list a "throw."
;;; For example, (THROW-DICE) migh return the throw (3 5), indicating that the first die was a 3 and the second a 5.
(defun throw-dice ()
"Throws two dice and returns the result in a list"
(list (throw-die) (throw-die)))
;;; Ex 5.6 c
;;; Throwing two ones is called "snake eyes"; two sixes is called "boxcars." Write predicates SNAKE-EYES-P and BOXCARS-P that takes a throw as input and return T if the throw is equal to (1 1) or (6 6), respectively.
(defun snake-eyes-p (l)
(eq (+ (car l) (cadr l)) 2))
(defun boxcars-p (l)
(eq (+ (car l) (cadr l)) 12))
;;; Ex 5.6 d
;;; In playing craps, the first throw of the dice is crucial. A throw of 7 or 11 is an instant win. A throw of 2, 3 or 12 is an instant loss (American casino rules).
;;; Write predicates INSTANT-WIN-P and INSTANT-LOSS-P to detect these conditions. Each should take a throw as input.
(defun instant-win-p (l)
(let ((s (+ (car l) (cadr l))))
(if (or (eq s 7) (eq s 11)) t)))
(defun instant-loss-p (l)
(let ((s (+ (car l) (cadr l))))
(if (or (eq s 2) (eq s 3) (eq s 12)) t)))
;;; Ex 5.6 e
;;; Write a function SAY-THROW that takes a throw as input and returns either the sum of the two dice or the symbol SNAKE-EYES or BOXCARS if the sum is 2 or 12.
;;; (SAY-THROW '(3 4)) should return 7. (SAY-THROW '(6 6)) should return BOXCARS.
(defun say-throw (l)
(cond ((snake-eyes-p l) 'snake-eyes)
((boxcars-p l) 'boxcars)
(t (+ (car l) (cadr l)))))
;;; Ex 5.6 f
;;; If you don't win or lose on the first throw of the dice, the value you threw becomes your "point," which will be explained shortly.
;;; Write a function (CRAPS) that produces the following sort of behaviour. Your solution should make use of the functions you wrote in previous steps.
;;; > (craps)
;;; (THROW 1 AND 1 -- SNAKEYES -- YOU LOSE)
;;; > (craps)
;;; (THROW 3 AND 4 -- 7 -- YOU WIN)
;;; > (craps)
;;; (THROW 2 AND 4 -- YOUR POINT IS 6)
(defun craps ()
(let ((l (list (throw-die) (throw-die))))
(cond ((instant-win-p l)
(list 'throw (car l) 'and (cadr l) '--
(+ (car l) (cadr l)) 'you 'win))
((instant-loss-p l)
(cond ((snake-eyes-p l) '(throw 1 and 1 -- snakeeyes -- you lose))
((boxcars-p l) '(throw 6 and 6 -- boxcars -- you lose))
(t (list 'throw (car l) 'and (cadr l) '--
(+ (car l) (cadr l)) 'you 'lose))))
(t (list 'throw (car l) 'and (cadr l) '--
'your 'point 'is (+ (car l) (cadr l)))))))
;;; Ex 5.6 g
;;; Once a point has been established, you continue throwing the dice until you either win by making the point again or lose by throwing a 7.
;;; Write the function TRY-FOR-POINT that simulates this part of the game, as follows:
;;; > (try-for-point 6)
;;; (THROW 3 and 5 -- 8 -- THROW AGAIN)
;;; > (try-for-point 6)
;;; (THROW 5 and 1 -- 6 -- YOU WIN)
;;; > (craps)
;;; (THROW 3 and 6 -- 9 -- YOUR POINT IS 9)
;;; > (try-for-point 9)
;;; (THROW 6 and 1 -- 7 -- YOU LOSE)
(defun try-for-point (x)
(let* ((l (list (throw-die) (throw-die)))
(s (+ (car l) (cadr l))))
(if (eq s x)
(list 'throw (car l) 'and (cadr l) '-- s '-- 'you 'win)
(if (eq (random 2) 1)
(list 'throw (car l) 'and (cadr l) '-- s '-- 'throw 'again)
(list 'throw (car l) 'and (cadr l) '-- s '-- 'you 'lose)))))