CS 21: Algorithmic Problem Solving

 

HW #5: Yahtzee

Part 1 -- due 11:59pm Tuesday, February 27
Part 2 -- due 11:59pm Tuesday, March 6

Remember to run update21 to get the files needed for this assignment. The program handin21 will only submit files in the cs21/homework/5 directory.

Your programs are graded on both correctness and style. Please review the comments regarding programming style on the main page

Some of the problems will have optional components that allow you to further practice your skills in Python. Optional portions will not be graded, but may be interesting for those wanting some extra challenges.

The game of Yahtzee

In this two part assignment, you will write a Python version of the popular dice game Yahtzee. For those of you who may not be familiar with Yahtzee (or who need a refresher) here are the rules of the game.

The rules outlined below were borrowed heavily from the Wikipedia entry on Yahtzee, and many years of personal experience. If you would like to try out the game for yourself, there is an online working demo as a Java applet. The game is played with five six-sided dice. Each game consists of thirteen rounds. In this assignment, you will simulate one of these rounds. The rules for playing a round are as follows:

  1. The player rolls all five dice.
  2. The player selects and re-rolls zero or more dice.
  3. The player selects and re-rolls zero or more dice again. Dice that were not re-rolled on the second roll may be re-rolled on the third roll.
  4. The player scores the dice.

To score a set of five dice, the player picks one of thirteen categories in which to score. A category chosen in one round cannot be used again in a successive round. Because your are only implementing one round this week, you do not need to worry about this yet. The thirteen categories are: ones, twos, threes, fours, fives, sixes, three-of-a-kind, four-of-a-kind, full house, small straight, large straight, Yahtzee, and chance. Each category assigns a score to a set of dice as outlined below. In each category, the order of the dice do not matter, thus a roll of 1, 2, 3, 1, 2" is the same as "1, 1, 2, 2, 3". If you have questions about the scoring, try playing the game online, ask a friend, or ask us. We'll be happy to explain.

These rules are sufficient for the first part of the assignment. Next week we will add a few additional rules regarding bonuses, but this does not effect the scoring of a single category

Part One

In Part One of the assignment, you will writing many of the foundational components of the game. Below is a list of the functions that your program must have, along with a brief description of what each function should do. (As per Python's help, the functions below are listed in alphabetical order.)

    fourOfAKind(dielist)
        Returns the sum of the dice if these dice represent 4 of a kind;
        otherwise, returns 0.

        For example:
          fourOfAKind([5, 3, 5, 5, 5]) => 23
          fourOfAKind([3, 3, 3, 5, 3]) => 17
          fourOfAKind([3, 3, 3, 3, 3]) => 15  
          fourOfAKind([1, 3, 1, 3, 3]) => 0
    
    fullHouse(dielist)
        Returns 25 if these dice represent a full house; returns 0 otherwise.
        
        A full house occurs when three of the dice are all of one value
        and the remaining two have the same value.  For example:
          fullHouse([4, 4, 4, 5, 5]) => 25
          fullHouse([5, 4, 5, 4, 5]) => 25
          fullHouse([5, 5, 5, 4, 5]) => 0
          fullHouse([3, 3, 1, 3, 1]) => 25
        
        Note that 5 of a kind is considered to be a full house.  For
        example:
          fullHouse([5, 5, 5, 5, 5]) => 25
    
    hasAtLeastN(dielist, n)
        Returns True if the list of dice contain at least n of some value.
        
        In other words, this returns True if the list of dice could be
        described as having 'n' of a kind.  For example:
          hasAtLeastN([5, 3, 5, 5, 5], 4) => True
          hasAtLeastN([5, 3, 5, 5, 5], 3) => True
          hasAtLeastN([5, 3, 5, 5, 5], 5) => False
          hasAtLeastN([1, 2, 3, 2, 1], 2) => True

    hasExactlyN(dielist, n)
        Returns True if these dice contain exactly 'n' of a particular
        value.  For example:
          hasExactlyN([2, 5, 2, 4, 2], 3) => True (there are exactly three 2's)
          hasExactlyN([2, 5, 2, 4, 2], 2) => False
          hasExactlyN([2, 5, 2, 4, 2], 1) => True (exactly one 4 and one 5)
          hasExactlyN([2, 5, 2, 4, 2], 0) => True (exactly zero 1's, 3's and 6's)
    
    largeStraight(dielist)
        Returns 40 if these dice have a large straight; else returns 0.
        
        A large straight is a list of dice which contain any 5 dice with
        consecutive values.  For example:
          largeStraight([1, 2, 3, 4, 5]) => 40
          largeStraight([6, 4, 5, 2, 3]) => 40
          largeStraight([2, 3, 4, 1, 2]) => 0
          largeStraight([6, 4, 5, 2, 1]) => 0
    
    reroll(dielist)
        Queries the user as to which dice should be re-rolled and does the
        re-rolling.
        
        The user is presented a prompt where they can choose the dice that
        they wish to re-roll.  Each selected die is then re-rolled and the
        list is changed in-place, so no list is returned from this
        function.
    
    roll()
        Rolls 5 standard 6-sided dice and returns a list of the 5 values.
    
    showdice(dielist)
        Displays the current values of the 5 dice.
    
    showscores(dielist)
        Displays the possible score that the 5 dice would receive in each
        of the 13 scoring slots.
    
    smallStraight(dielist)
        Returns 30 if these dice have a small straight; otherwise returns 0.
        
        A small straight is a list of dice which contain any 4 dice with
        consecutive values.  For example:
          smallStraight([1, 2, 3, 4, 5]) => 30
          smallStraight([2, 3, 4, 1, 2]) => 30
          smallStraight([6, 4, 5, 3, 1]) => 30
          smallStraight([6, 4, 5, 2, 1]) => 0
    
    sumDice(dielist)
        Returns the sum of the dice.

        For example:
          sumDice([1, 2, 3, 4, 5]) => 15
          sumDice([2, 2, 5, 2, 3]) => 14
    
    sumOfN(dielist, num)
        Returns the sum of only those dice whose value is num.
        
        For example:
          sumOfN([5, 4, 5, 2, 5], 2) => 2
          sumOfN([5, 4, 5, 2, 5], 3) => 0
          sumOfN([5, 4, 5, 2, 5], 4) => 4
          sumOfN([5, 4, 5, 2, 5], 5) => 15
    
    threeOfAKind(dielist)
        Returns the sum of the dice if these dice represent 3 of a kind;
        otherwise, returns 0.

        For example:
          threeOfAKind([5, 3, 5, 3, 5]) => 21
          threeOfAKind([3, 3, 3, 5, 3]) => 17
          threeOfAKind([3, 3, 3, 3, 3]) => 15  
          threeOfAKind([1, 3, 1, 2, 3]) => 0
    
    yahtzee(dielist)
        Returns 50 if these dice represent a Yahtzee (5 of a kind);
        otherwise returns 0.

        For example:
          yahtzee([5, 5, 5, 5, 5]) => 50
          yahtzee([2, 2, 2, 2, 2]) => 50
          yahtzee([2, 1, 2, 2, 2]) => 0


We have provided for you the main function. When you run the program (and have completed each of the above functions), you should have output similar to the following:

Position:   A  B  C  D  E
   Value:   1  6  2  3  3
Enter dice to re-roll: ABC

Position:   A  B  C  D  E
   Value:   1  2  2  3  3
Enter dice to re-roll: A

Position:   A  B  C  D  E
   Value:   2  2  2  3  3

      Slot   Points
      Ones        0
      Twos        6
    Threes        6
     Fours        0
     Fives        0
     Sixes        0
    3/Kind       12
    4/Kind        0
  Full Hse       25
   Sm Strt        0
   Lg Strt        0
    Chance       12
   Yahtzee        0

If the player wishes to re-roll none of the dice, they can just press enter at the prompt to re-roll. In the below example, the player rolled a Large Straight on the opening roll and didn't want to change anything:

Position:   A  B  C  D  E
   Value:   5  4  6  2  3
Enter dice to re-roll:

Position:   A  B  C  D  E
   Value:   5  4  6  2  3
Enter dice to re-roll:

Position:   A  B  C  D  E
   Value:   5  4  6  2  3

      Slot   Points
      Ones        0
      Twos        2
    Threes        3
     Fours        4
     Fives        5
     Sixes        6
    3/Kind        0
    4/Kind        0
  Full Hse        0
   Sm Strt       30
   Lg Strt       40
    Chance       20
   Yahtzee        0

To help you manage this large project, you should write functions one at a time and test each of them before moving on to the next function. You should begin by writing (and testing) the roll and reroll functions. Then, you can write the showdice and showscores functions. Once those four functions are in place, the main function we provided for you will work.

Now you can move on to writing each of the scoring functions. The easiest scoring function to write is Chance. Write this function and make sure it is working before proceeding. You should try to write the scoring functions in this order (approximately reflecting easiest to hardest):

  1. Chance
  2. Yahtzee
  3. Three of a Kind, Four of a Kind
  4. One, Two, Three, Four, Five, Six.
  5. Full House
  6. Small Straight, Large Straight
Remember to be sure to test each function before proceeding on to the next one.
Part Two
See Homework 6.