HW 4 (Pig)
Assignment overview
In this assignment, you'll write code that simulates playing the game Pig.
Goals
Get practice using functions (especially with return values) and using conditional statements.
Logistics
This is a partner assignment, which means you should complete all pieces of this assignment with your assigned partner. In particular, any coding must be completed side-by-side in a pair programming style. You are welcome to discuss the assignment with other classmates, course staff or Anna. Make sure to cite any help you receive in the "acknowlegdements" portion of the assignment.
Unless we have worked out a different arrangement together, you are working with the same partner as for HW2.
This assignment is due at 10PM on Friday, April 17.
Setup
Mount the COURSES drive and create a folder called hw4 in your STUWORK folder.
Open the new folder in VSCode.
If you need a refresher on how to complete these steps, refer back to the in-class
lab from the first day of class.
Next, download this
starter Python file.
Move the file (pig.py) to your new hw4 folder.
For this assignment, you will fill in the missing code in pig.py to implement the game Pig.
Rules of Pig
Pig is a game in which two players take turns rolling dice. There are many variations of the game, but here are the rules we will be playing with:
- A player rolls two dice at a time.
- If either die (but not both dice) is a 1, the player's turn ends and they get 0 points.
- If both dice are the same number (including two 1's), 15 points are added to the player's turn total. In this scenario, the player must re-roll the die as described below (they cannot choose to "hold").
- If the player's turn hasn't ended by rolling a single 1, they can decide to either re-roll the two dice to
have a chance of scoring more points, or they can hold.
- If the player re-rolls, the same rules as above apply.
- If the player holds, their turn total is added to their score and it becomes the other player's turn.
There is also an overall cap on how many times a player can roll during their turn
(in the code, I call this maxRollsPerTurn). This can be anywhere from
two to 10 rolls. This cap means that if the player completes their nth roll (where n is the cap),
their turn automatically ends after that roll. (Even if they roll doubles, they do not roll again.)
The game ends when a player has achieved a certain goal score (e.g., 100 points) at the conclusion of their turn.
There is also total number of allowed turns (e.g., 50 or 100). If the players reach the number of allowed turns, (e.g., they each have taken 25 turns or 50 turns), the game ends and the player with the higher score wins. If both players have the same number of points at this time, the game ends in a tie.
The functions in pig.py
I recommend implementing the functions in the order described here. Test each function before
moving to the later parts. For instance, to test rollDice, open the Python interpreter (type
python3 at the command line), import pig.py (i.e., type import pig), then test the function
as pig.rollDice().
rollDice
rollDice simulates rolling two dice. It should return a tuple containing the values of the two
dice rolls. You will want to use the random module (imported at the top of the file). In particular,
the random.randInt() function will
be helpful.
Strategy functions
Strategy functions include alwaysHold, alwaysRoll, human, and holdIfWinning.
alwaysHold(completed for you). Always return False to simulate never choosing to re-roll within a single turn.alwaysRoll(completed for you). Always return True to simulate always choosing to re-roll.humanasks the user to decide whether they want to hold or re-roll. Return True to re-roll or False to hold.holdIfWinningreturns False to hold if the current player is winning (according tooldScore + newScore) and True to roll otherwise.
All of these functions take 4 parameters: newScore (points earned so far in the current player's
current turn), oldScore (the current player's score before their current turn began), opponentScore,
and goalScore. You'll notice that not all of these functions need to use all parameters. We still need
to include them all as parameters for reasons described in the next section.
getScore and turn
getScore is a helper function that accepts a dice roll (a tuple of two values) and returns the
score according to the game rules. Recall that you can use the syntax t[0] and t[1] to access the first
and second items in a tuple, respectively.
turn simulates one player's turn. The parameters to this function include the current game status
(playerScore and opponentScore), details about the game settings (goalScore and maxRollsPerTurn),
and a strategy that describes how the turn should proceed.
Note that the final parameter of turn, strategy is itself a function,
which is something we haven't seen before.
Python treats variables and functions similarly; functions can be passed as parameters to functions
and also returned from functions. We won't do this often in CS111, but it's very powerful.
The following code snippets shows an example of how to pass functions as parameters using a simplified version of the functions in this assignment:
def winningStrategy(playerScore, goalScore):
# don't reroll if we've won, otherwise reroll
return playerScore < goalScore
def turn(playerScore, goalScore, strategy):
roll = strategy(playerScore, goalScore)
turn(0, 100, winningStrategy)
The cool thing here is that if I have another function that also takes two parameters, I can pass the
name of that function as the parameter instead. This is why we have the unused parameters in some of the
strategy functions. (I've included goalScore as a parameter in case you want to write your own
strategy function that includes goalScore in its logic.)
Before trying to write code for turn,
write pseudocode. Think about how your turn would proceed, if you're playing Pig. Details about when to
roll the dice, how to calculate your new score, and whether to roll again will all be handled in this
function (or in helper functions that you create and then call from this function). turn should return
the value of the points that the player earns during this single turn. (You should handle updating the
playerScore variables in the next function, play.)
play
play switches off between initiating turns (i.e., calling turn) for each of the two players. It takes
in parameters about the game's settings (goalScore, globalMaxTurns, and maxRollsPerTurn) and
about the players (strategy1 and strategy2). You
may find it useful to print updates (such as whose turn it is, and what the current scores are) from
this function. play should return a value to indicates who wins (Player 1, Player 2, or a tie)
main
main is called when the program is executed from the command line. It should call play and then
print who wins based on the return value of play. In main, you can hardcode the two players'
strategies, or you can find a way to ask for user input to set the strategies.
You are welcome to write and call additional helper functions, but please keep the names and signatures (i.e., how many parameters they take and what the parameters are called) the same for the existing functions.
Code notes and tips
Testing in the interpreter
As I mentioned above, you should test each function in the interpreter after you complete it.
The syntax is a little different when passing function names in the interpreter. For instance, in
your code, you call play like this:
play(50, 50, 5, human, alwaysHold)
but in the interpreter you have to call
pig.play(50, 50, 5, pig.human, pig.alwaysHold)
Playing the game
By the end of this assignment, you should be able to run python3 pig.py and actually play against the
computer!
Here's an example interaction I had while playing the game against the computer:
(You don't need to match this interaction exactly, see below for what you need to print and what
is optional.)
Player 1: computer; Player 2: human --- Turn 1 (Player 1's turn) --- --- Current scores --- --- Player 1: 0 ; Player 2: 0 --- Rolled 6 and 3 --- Turn 2 (Player 2's turn) --- --- Current scores --- --- Player 1: 9 ; Player 2: 0 --- Rolled 4 and 4 Rolled 2 and 6 Your score is 23 ( 23 points are new) and your opponent's score is 9 Do you want to roll again or hold? Type h for hold anything else for roll: h --- Turn 3 (Player 1's turn) --- --- Current scores --- --- Player 1: 9 ; Player 2: 23 --- Rolled 3 and 4 Rolled 3 and 6 --- Turn 4 (Player 2's turn) --- --- Current scores --- --- Player 1: 25 ; Player 2: 23 --- Rolled 4 and 6 Your score is 33 ( 10 points are new) and your opponent's score is 25 Do you want to roll again or hold? Type h for hold anything else for roll: r Rolled 5 and 3 Your score is 41 ( 18 points are new) and your opponent's score is 25 Do you want to roll again or hold? Type h for hold anything else for roll: r Rolled 3 and 5 Your score is 49 ( 26 points are new) and your opponent's score is 25 Do you want to roll again or hold? Type h for hold anything else for roll: r Rolled 6 and 2 Your score is 57 ( 34 points are new) and your opponent's score is 25 Do you want to roll again or hold? Type h for hold anything else for roll: h Player 1: 25 ; Player 2: 57 Player 2 wins!
What do I need to print?
At a minimum, you should print the current scores and turn number for each turn. You should also print the final scores at the end of the game along with a message of who won.
You can print out the values of the dice rolls, intermediate information that can help the user
decide whether to re-roll (e.g., the (34 points are new) part of my example output above), or
anything else that makes the interactive game play smoother from the command line.
When I was writing and testing my code, I found it useful to add the line input() at places in the code
where I wanted to be able to pause and check the output (e.g., at the end of the computer's turn before
my turn began). Then, I could press enter to get more text printed to the screen only when I was ready
to read it. If you do this, you should remove the extra input() statements before submtiting your code.
Optional extensions
- Write your own strategy function.
Wrap up
When you're finished, make sure to complete the usual documentation steps. This includes adding comments, writing function docstrings where they are missing or incomplete, and filling out all pieces of the header.
You should also think about coding style. Have you written everything in a consistent way that is easy to read? Does your code have any unnecessary print statements? (Remove them.) Review the style document on Moodle for the expectations for this assignment.
Assignment submission and misc. notes
Handing in the assignment
You need to hand in pig.py on Gradescope.
Only one partner should submit the assignment to Gradescope (but make sure to add your partner to
your group after submitting)
Grading
This assignment is worth 40 points, broken up as follows:
rollDicefunction (4 points)humanfunction (4 points)holdIfWinningfunction (4 points)getScorefunction (6 points)turnfunction (6 points): Do you successfully callrollDiceandgetScore? Do you successfully call the passed-in strategy function? Do you obey themaxRollsPerTurnparameter?playfunction (6 points): Do you alternate turns between players, print the current scores for each turn, and correctly determine the game's winner?mainfunction (4 points)- Style (6 points): header, comments, following the style guidelines from Moodle.
Start early, ask lots of questions, and have fun!
Anna's acknowledgements
This assignment was adapted from assignments used by Anna Rafferty and Layla Oesper. Thanks for sharing!