;;; Copyright 2013 Google Inc. ;;; ;;; Licensed under the Apache License, Version 2.0 (the "License"); ;;; you may not use this file except in compliance with the License. ;;; You may obtain a copy of the License at ;;; ;;; http://www.apache.org/licenses/LICENSE-2.0 ;;; ;;; Unless required by applicable law or agreed to in writing, software ;;; distributed under the License is distributed on an "AS IS" BASIS, ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ;;; See the License for the specific language governing permissions and ;;; limitations under the License. ;;; Greed is a dice game played among 2 or more players, using 5 ;;; six-sided dice. ;;; ;;; Each player takes a turn consisting of one or more rolls of the dice. ;;; On the first roll of the game, a player rolls all five dice which are ;;; scored according to the following: ;;; ;;; Three 1's => 1000 points ;;; Three 6's => 600 points ;;; Three 5's => 500 points ;;; Three 4's => 400 points ;;; Three 3's => 300 points ;;; Three 2's => 200 points ;;; One 1 => 100 points ;;; One 5 => 50 points ;;; ;;; A single die can only be counted once in each roll. For example, ;;; a "5" can only count as part of a triplet (contributing to the 500 ;;; points) or as a single 50 points, but not both in the same roll. ;;; ;;; Example Scoring ;;; ;;; Throw Score ;;; --------- ------------------ ;;; 5 1 3 4 1 50 + 2 * 100 = 250 ;;; 1 1 1 3 1 1000 + 100 = 1100 ;;; 2 4 4 5 4 400 + 50 = 450 ;;; ;;; The dice not contributing to the score are called the non-scoring ;;; dice. "3" and "4" are non-scoring dice in the first example. "3" is ;;; a non-scoring die in the second, and "2" is a non-score die in the ;;; final example. ;;; ;;; More scoring examples are given in the tests below. ;;; ;;; Your goal is to write the scoring function for Greed. (defun score-once (&rest dice) (let ((sorted (sort (copy-list dice) #'<))) (cond ((search '(1 1 1) sorted) (list 1000 (remove 1 sorted :count 3))) ((search '(2 2 2) sorted) (list 200 (remove 2 sorted :count 3))) ((search '(3 3 3) sorted) (list 300 (remove 3 sorted :count 3))) ((search '(4 4 4) sorted) (list 400 (remove 4 sorted :count 3))) ((search '(5 5 5) sorted) (list 500 (remove 5 sorted :count 3))) ((search '(6 6 6) sorted) (list 600 (remove 6 sorted :count 3))) ((find 5 sorted) (list 50 (remove 5 sorted :count 1))) ((find 1 sorted) (list 100 (remove 1 sorted :count 1))) (t (list 0 '()))))) (defun score (&rest dice) (loop for current-dice = dice then remaining-dice for (score remaining-dice) = (apply #'score-once current-dice) sum score while remaining-dice)) (define-test score-of-an-empty-list-is-zero (assert-equal 0 (score))) (define-test score-of-a-single-roll-of-5-is-50 (assert-equal 50 (score 5))) (define-test score-of-a-single-roll-of-1-is-100 (assert-equal 100 (score 1))) (define-test score-of-multiple-1s-and-5s-is-the-sum-of-individual-scores (assert-equal 300 (score 1 5 5 1))) (define-test score-of-single-2s-3s-4s-and-6s-are-zero (assert-equal 0 (score 2 3 4 6))) (define-test score-of-a-triple-1-is-1000 (assert-equal 1000 (score 1 1 1))) (define-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 score-of-mixed-is-sum (assert-equal 250 (score 2 5 2 2 3)) (assert-equal 550 (score 5 5 5 5)))