我正在浏览Lisp Koans,这很有趣!但我坚持使用计分项目(我有一个糟糕的解决方案)。在这个项目中,我们被要求实现一个名为*Greed*. 问题描述在这里:
; *Greed* is a dice game where you roll up to five dice to accumulate
; points.  The following "score" function will be used to calculate the
; score of a single roll of the dice.
;
; A greed roll is scored as follows:
; * A set of three ones is 1000 points
; * A set of three numbers (other than ones) is worth 100 times the
;   number. (e.g. three fives is 500 points).
; * A one (that is not part of a set of three) is worth 100 points.
; * A five (that is not part of a set of three) is worth 50 points.
; * Everything else is worth 0 points.
;
; Examples:
;
; (score '(1 1 1 5 1)) => 1150 points
; (score '(2 3 4 6 2)) => 0 points
; (score '(3 4 5 3 3)) => 350 points
; (score '(1 5 1 2 4)) => 250 points
;
; More scoring examples are given in the tests below:
;
; Your goal is to write the score method.
我的解决方案如下:
警告!如果你还没有玩过这个。不要看到这个!
我使用一个occurs函数来计算 number 的出现并在 assoc-list 中表示。以及一个为formula-wrapper函数提供正确参数的formula函数。formula计算分数的函数。我的解决方案非常难看!欢迎任何建议!先感谢您。
(defun occurs (lst)
  (let ((acc nil))
    (dolist (obj lst)
      (let ((p (assoc obj acc)))
        (if p
            (incf (cdr p))
            (push (cons obj 1) acc))))
    (sort acc  #'> :key #'cdr)))
(defun formula-wrapper (lst)
  (formula (car lst) (cdr lst)))
(defun formula (number times)
  (cond ((= times 0) 0)
        ((= times 1)
         (case number
           (1 100)
           (5 50)
           (otherwise 0)))
        ((= times 2)
         (case number
           (1 200)
           (5 100)
           (otherwise 0)))
        ((= times 3)
         (case number
           (1 1000)
           (otherwise (* 100 number))))
        ((= times 4)
         (case number
           (1 1100)
           (5 550)
           (otherwise 0)))
        ((= times 5)
         (case number
           (1 1200)
           (5 600)
           (otherwise 0)))
        (times 0)))
(defun score (dice)
  (let ((rolls (occurs dice)))
    (if (null rolls)
        0
        (apply #'+ (mapcar #'formula-wrapper rolls))))))
测试:
(define-test test-score-of-an-empty-list-is-zero
    (assert-equal 0 (score nil)))
(define-test test-score-of-a-single-roll-of-5-is-50
    (assert-equal 50 (score '(5))))
(define-test test-score-of-a-single-roll-of-1-is-100
    (assert-equal 100 (score '(1))))
(define-test test-score-of-multiple-1s-and-5s-is-the-sum-of-individual-scores
    (assert-equal 300 (score '(1 5 5 1))))
(define-test test-score-of-single-2s-3s-4s-and-6s-are-zero
    (assert-equal 0 (score '(2 3 4 6))))
(define-test test-score-of-a-triple-1-is-1000
    (assert-equal 1000  (score '(1 1 1))))
(define-test test-score-of-other-triples-is-100x
    (assert-equal 200  (score '(2 2 2)))
    (assert-equal 300  (score '(3 3 3)))
    (assert-equal 400  (score '(4 4 4)))
    (assert-equal 500  (score '(5 5 5)))
    (assert-equal 600  (score '(6 6 6))))
(define-test test-score-of-mixed-is-sum
    (assert-equal 250  (score '(2 5 2 2 3)))
    (assert-equal 550  (score '(5 5 5 5))))