I know! I'll use my
Higher-order functions to
Order higher rolls. — CS7 Haiku
Click a die to re-roll it  ·  Double-click to roll all

Introduction

In this project, you will develop a simulator and multiple strategies for the dice game Hog. You will need to use control statements and higher-order functions together, drawing on Sections 1.1 through 1.6 of Composing Programs.

In Hog, two players alternate turns trying to reach 100 points first. On each turn, the current player chooses how many dice to roll (up to 10). The turn score is the sum of the dice — unless any die shows a 1, in which case the score for that turn is only 1 point (the Pig Out rule).

Special Rules

Three special rules spice up the game. Try the interactive demos below to understand each one before you start coding.

🥓

Free Bacon

Roll zero dice to score 1 more than the largest digit in your opponent's total score.

🎲

Hog Wild

If the sum of both players' scores is a multiple of 7, the current player rolls four-sided dice instead of six-sided.

You: Opp:
🔄

Swine Swap

If one player's score is exactly double the other's at the end of a turn, the players swap scores.

Edit scores, then hit ↔ to trigger the swap:

Try the Pig Out Rule

Roll some dice and see if you pig out. This is exactly what your roll_dice function will compute.

Roll 5 dice

Project Files

Download all project code as a zip archive. You will only need to edit hog.py.

hog.py A starter implementation of Hog. This is the only file you submit.
dice.py Functions for rolling dice.
ucb.py Utility functions for CS7.
hog_gui.py A graphical user interface for Hog.
hog_grader.py Tests to check the correctness of your implementation.
autograder.py Utility functions for grading.

Logistics

This is a 10-day project. You are strongly encouraged to work with a partner, although you may complete it alone.

Start early. The amount of time it takes to complete a project is unpredictable. Ask for help early and often — the TAs are here to help. Post on Piazza and come to office hours.

You and your partner submit one project. It is worth 40 points in total, split equally between two components:

Component Points How
Code (Poseidon autograder) 20 pts 17 for correctness · 3 for program composition
Oral Evaluation 20 pts Conducted by a TA after submission — see below

Submit only hog.py to Poseidon. Before you submit, read the Composition guide — it explains what the 3 composition points are looking for.

For functions we ask you to complete, some initial skeleton code is provided. You may delete it and start from scratch, but we advise keeping the skeleton. Do not modify any other functions or change any function signatures (names, argument order, or number of arguments).

Oral Evaluation

After the submission deadline, each pair will be assigned a TA who will conduct a short oral evaluation — a conversation to assess how well both partners understand the code they submitted. This is worth 20 points (half your total project score).

Why oral evaluations?
Submitting working code is not enough — you must be able to explain it. Oral evaluations ensure both partners genuinely understand their implementation and help us maintain academic integrity across the class.

Format. Your assigned TA will schedule a short session (roughly 10–15 minutes per pair) after the deadline. Both partners must attend. The TA will ask each person questions about specific parts of the code — your design choices, how a function works, what would happen if an input changed, and so on. You will not write any new code during the session.

Scoring. Each partner is assessed individually. Points are awarded based on depth of understanding:

Score Description
18 – 20 Deep understanding — can explain every function clearly, justify design decisions, and reason about edge cases without hesitation.
14 – 17 Good understanding — explains most functions correctly with minor gaps or prompting needed.
10 – 13 Partial understanding — understands the overall structure but struggles to explain specific implementation details.
5 – 9 Limited understanding — can describe what the code does at a surface level but cannot explain how or why.
0 – 4 Little to no understanding — unable to explain the submitted code. This may trigger an academic integrity review.

What to expect. Your TA may ask questions like:

The best preparation is simply to write the code yourself and understand every line. If you worked with a partner, make sure you can each explain the full project independently.

Graphical User Interface

A graphical user interface (GUI) is provided. It won't work until you implement the game logic, but once you finish Problem 4 you can play a fully interactive version of Hog.

One-time setup: The GUI requires pygame. Install it once before running the GUI:
pip install pygame

If pip gives a permissions error, try pip3 install pygame or add the --user flag.

python3 hog_gui.py

After completing Problem 9, you can play against your own final strategy:

python3 hog_gui.py -f

Testing

Test your code frequently — it makes bugs easier to isolate.

Most tests live in the docstrings of hog.py. Additional tests are in hog_grader.py. Run all tests until a failure is found:

python3 hog_grader.py

Run tests for a specific problem with -q:

python3 hog_grader.py -q 1

Call certain functions interactively from the terminal:

python3 hog.py -i roll_dice
1

Simulator

Implement the core game logic — dice rolling, taking turns, and a full game loop.

roll_dice 2 pt

Implement roll_dice in hog.py, which returns the number of points scored by rolling a fixed positive number of dice: either the sum of the dice or 1 (Pig Out). Call dice() exactly num_rolls times. The only rule to enforce here is Pig Out.

As you work, add print statements to inspect your program. Remove them when you're done.

python3 hog_grader.py -q 1
python3 hog.py -i roll_dice

take_turn 1 pt

Implement take_turn, which returns the number of points scored for the turn. Enforce the Free Bacon rule here. You may assume opponent_score is less than 100. Your implementation should call roll_dice.

python3 hog_grader.py -q 2

select_dice 1 pt

Implement select_dice, a helper that enforces the Hog Wild rule. The function takes the scores of both players and returns the correct type of dice (four-sided or six-sided) for the current turn.

python3 hog_grader.py -q 3

play 3 pt

Implement play, which simulates a full game of Hog. Players alternate turns using the strategies originally supplied, until one reaches the goal score. Return the final scores of both players, Player 0's score first.

python3 hog_grader.py -q 4
python3 hog.py -i play

Once finished, you can play the graphical version:

python3 hog_gui.py

Congratulations — you have finished Phase 1! 🎉

2

Strategies

Evaluate and improve on the baseline strategy of always rolling a fixed number of dice.

make_averaged 2 pt

Implement make_averaged. This higher-order function takes a function fn and returns another function that returns the average value of repeatedly calling fn on the same arguments. It should call fn exactly num_samples times.

Note: if fn is non-pure (e.g. uses random), so is the result.

You will need *args syntax to accept an arbitrary number of arguments and forward them:

>>> def printed(fn):
...     def print_and_return(*args):
...         result = fn(*args)
...         print('Result:', result)
...         return result
...     return print_and_return
>>> printed_pow = printed(pow)
>>> printed_pow(2, 8)
Result: 256
256
python3 hog_grader.py -q 5

max_scoring_num_rolls 2 pt

Implement max_scoring_num_rolls, which runs an experiment to determine the number of rolls (1–10) that gives the highest average score per turn. Use make_averaged and roll_dice. Print the average for each number of rolls as shown in the doctest.

python3 hog_grader.py -q 6

Run the experiment on randomized dice:

python3 hog.py -r

For the rest of the project, feel free to modify run_experiments as you wish. Calling average_win_rate lets you evaluate any strategy. Some experiments may take up to a minute; reduce num_samples in make_averaged to speed them up.

bacon_strategy 1 pt

Implement bacon_strategy. It should return 0 (roll zero dice, take Free Bacon) whenever doing so would score at least BACON_MARGIN points. Otherwise return BASELINE_NUM_ROLLS. Both constants are defined just above always_roll.

python3 hog_grader.py -q 7

Update run_experiments to evaluate this strategy — it should win more than half the time.

swap_strategy 2 pt

Implement swap_strategy to also exploit the Swine Swap rule:

  1. Roll 0 if it would trigger a beneficial swap (gaining points).
  2. Roll BASELINE_NUM_ROLLS if it would trigger a harmful swap (losing points).
  3. If no swap would occur, use the Free Bacon threshold logic from bacon_strategy.
python3 hog_grader.py -q 8

Update run_experiments — this strategy should perform even better than bacon_strategy on average.

Run the complete autograder to catch any remaining failures:

python3 hog_grader.py

final_strategy 3 pt

Implement final_strategy, combining all ideas (and any new ones) to achieve a win rate of at least 0.59 against always_roll(5). Some ideas to consider:

Note: you may want to increase num_samples for a better win-rate estimate. Poseidon will compute your exact average win rate when you submit.

python3 hog_gui.py -f

The GUI will alternate which player is controlled by you so you can test your strategy head-to-head.

Congratulations — you have reached the end of your first CS7 project! 🏆