**Starting Files**

Download this zip with a dummy project and tests.

**Hog Dummy Project.xcodeproj: **the Xcode project with the playground. I put the playground inside a dummy project so that autocomplete works in the sources folder of the playground. Otherwise, a playground by itself wouldn’t compile the code real-time.

**check**: a Python script that checks your understanding of the questions.

**Introduction**

In this project, you will develop a simulator and multiple strategies for the dice game Hog. You will need to use what you’ve learned in the past month.

In Hog, two players alternate turns trying to be the first to end a turn with at least 100 total points. On each turn, the current player chooses some number of dice to roll, up to 10. That player’s score for the turn is the sum of the dice outcomes.

To spice up the game, we will play with some special rules:

**Pig Out**. If any of the dice outcomes is a 1, the current player’s score for the turn is 1.*Example 1*: The current player rolls 7 dice, 5 of which are 1’s. They score 1 point for the turn.*Example 2*: The current player rolls 4 dice, all of which are 3’s. Since Pig Out did not occur, they score 12 points for the turn.

**Free Bacon**. A player who chooses to roll zero dice scores the one more than the last digit of the product of the digits in the opponent’s score.*Example 1*: The opponent has 46 points, and the current player chooses to roll zero dice. 4 * 6 = 24; the last digit is a 4, so the current player gains 4 + 1 = 5 points.*Example 2*: The opponent has 28 points, and the current player chooses to roll zero dice. 2 * 8 = 16; the last digit is a 6, so the current player gains 6 + 1 = 7 points.*Example 3*: The opponent has 5 points, and the current player chooses to roll zero dice. 0 * 5 = 0; the last digit is a 0, so the current player gains 0 + 1 = 1 point.

**Swine Swap**. After points for the turn are added to the current player’s score, if the ones digit of the current player’s score is the same as the tens digit of the opponent’s score, the two scores are swapped.*Example 1*: The current player has a total score of 41 and the opponent has 92. The current player rolls two dice that total 8. The player’s new score is 49, and the opponent’s score is 92. The ones and tens digits are the same (4**9**and**9**2), so the scores are swapped! The current player now has 92 points and the opponent has 49. The turn ends.*Example 2*: The current player has a total score of 34 and the opponent has 5. The current player rolls three dice that total 6. The player’s new score is 40, and the ones digit is the same as the opponent’s tens digit (4**0**and**0**5), so the scores are swapped. The current player now has 5 points and the opponent has 40.*Example 3*: The current player has a total score of 91 and the opponent has 12. The current player rolls five dice that total 20. The player’s new score is 111, and the ones digit is the same as the opponent’s tens digit (11**1**and**1**2), so the scores are swapped. The opponent ends the turn with 111 points and wins the game.

**Getting started**

Double click on Hog Dummy Project to open the Xcode project. Inside, you should see a playground named Hog.playground. Click the arrow on the left of the playground to expand it. Then, expand the sources folder as well.

You will be writing code inside the hog.swift file.

**Checking your understanding with the script**

Inside the Hog folder, there’s also a file called “check”. To check your understanding with questions using this file, you need to use the terminal.

First, use the **cd **(change directory) command to locate the Hog folder. For instance, if your Hog folder is on the Desktop, your command should look like this:

```
cd Desktop
cd Hog
```

Then, type the command below:

`python3 -i check`

Next, call the function for the corresponding question like below:

`>>> problem1()`

Then, you should be able to see questions pop up. You simply need to enter what the expression on the last line would evaluate to or the answer for an MCQ. Press enter to check your answer.

To exit out of the current check, press **control + c**

To exit out the entire script, press **control + z**

**Graphical Interface**

This game has a graphical interface. After you’ve finished the implementation, go back to Hog.playground and run everything. Then, open the assistant editor and pull up the live view.

**Part 1: Simulator**

**Problem 0**

The `dice.swift`

file represents dice using non-pure zero-argument functions. These functions are non-pure because they may have different return values each time they are called. `dice.swift`

implements the two different types of dice used in the project:

- Dice can be fair, meaning that they produce each possible outcome with equal probability. Example:
`sixSided`

. - For testing functions that use dice, deterministic test dice always cycle through a fixed sequence of values that are passed as arguments to the
`makeTestDice`

function.

Before we start writing any code, read over the `dice.swift`

file and check your understanding by using the script and calling problem0().

```
python3 -i check
>>> problem0()
let testDice = Dice.makeTestDice(outcomes: 4,1,2)
testDice()
```

**Problem 1: Roll Dice**

Implement the `rollDice`

function in `hog.swift`

. It takes two arguments: a positive integer called `numRolls`

giving the number of dice to roll and a `dice`

function. It returns the number of points scored by rolling the dice that number of times in a turn: either the sum of the outcomes or 1 (*Pig Out*).

To obtain a single outcome of a dice roll, call `dice()`

. You should call `dice()`

exactly `numRolls`

times in the body of `rollDice`

. **Remember to call ****dice()**** exactly ****numRolls**** times even if Pig Out happens in the middle of rolling.** In this way, we correctly simulate rolling all the dice together.

**Also, inside your loop, make sure you append the result of your dice roll to the array named ****diceValues****. This makes the game’s graphical interface work.**

**Understand the problem**:

Before writing any code, use the script to verify your understanding of the question.

```
python3 -i check
>>> problem1()
```

**Write code and check your work**:

Once you are done with the questions in the script, begin implementing your solution in the `hog.swift`

file . Go back to Hog.playground to check if your code passes the tests. Run the test that is named rollDiceTests by executing up to the line below:

`rollDiceTests.defaultTestSuite.run()`

**Debugging your code interactively**:

If the tests don’t pass, it’s time to debug. You can observe the behavior of your function by using the playground file. First, go back to the `Hog.playground`

file. Then, you can call the `rollDice`

function with your own arguments like below:

`Hog.rollDice(numRolls: <some integer>, dice: <some dice function>)`

You can call your `rollDice`

function on any number of dice you want. The `rollDice`

function has a default argument value for `dice`

that is a random six-sided dice function. Therefore, the following call to `rollDice`

simulates rolling four fair six-sided dice.

`Hog.rollDice(numRolls: <some integer>)`

You will find that the previous expression may have a different result each time you call it, since it is simiulating random dice rolls. You can also use test dice that fix the outcomes of the dice in advance. For example, rolling twice when you know that the dice will come up 3 and 4 should give a total outcome of 7.

```
let fixedDice = Dice.makeTestDice(outcomes: 3,4)
Hog.rollDice(numRolls: 2, dice: fixedDice)
```

## Problem 2: Free Bacon!

Implement the `freeBacon`

helper function that returns the number of points scored by rolling 0 dice, based on the opponent’s current `opponentScore`

. You can assume that `opponentScore`

is less than 100. For a score less than 10, assume that the first of the two digits is 0.

Before writing any code, use the script to verify your understanding of the question.

```
python3 -i check
>>> problem2()
```

Once you are done with that, begin implementing your solution. You can check your correctness with:

`freeBaconTests.defaultTestSuite.run()`

As noted above, you can also test `freeBacon`

interactively by writing your own code in `Hog.playground`

and then calling `freeBacon`

with various inputs.

## Problem 3: Take a Turn

Implement the `takeTurn`

function, which returns the number of points scored for a turn by rolling the given `dice`

`numRolls`

times.

You will need to implement the *Free Bacon* rule based on `opponentScore`

, which you can assume is less than 100.

Your implementation of `takeTurn`

should call both `rollDice`

and `freeBacon`

when possible.

Before writing any code, use the script to verify your understanding of the question.

```
python3 -i check
>>> problem3()
```

Once you are done checking, begin implementing your solution. You can check your correctness with:

`takeTurnTests.defaultTestSuite.run()`

## Problem 4: is Swap?

Implement `isSwap`

, which returns whether or not the scores should be swapped because the ones digit of the current player’s score is the same as the tens digit of the opponent’s score.

The `isSwap`

function takes two arguments: the players’ scores. It returns a boolean value to indicate whether the *Swine Swap* condition is met.

Before writing any code, use the script to verify your understanding of the question.

```
python3 -i check
>>> problem4()
```

Once you are done checking, begin implementing your solution. You can check your correctness with:

`isSwapTests.defaultTestSuite.run()`

## Problem 5: Playyy!

Implement the `play`

function, which simulates a full game of Hog. Players alternate turns rolling dice until one of the players reaches the `goal`

score.

To determine how much dice are rolled each turn, each player uses their respective strategy (Player 0 uses `strategy0`

and Player 1 uses `strategy1`

). A *strategy* is a function that, given a player’s score and their opponent’s score, returns the number of dice that the current player wants to roll in the turn. Each strategy function should be called only once per turn. Don’t worry about the details of implementing strategies yet. You will develop them in Phase 3.

When the game ends, `play`

returns the final total scores of both players, with Player 0’s score first, and Player 1’s score second **in a tuple.**

Here are some hints:

- You should use the functions you have already written! You will need to call
`takeTurn`

with all three arguments. - Only call
`takeTurn`

once per turn. - Enforce all the special rules.
- You can get the number of the other player (either 0 or 1) by calling the provided function
`other`

. - Call the
`say`

function every turn. It provides commentary in the console.

Before writing any code, use the script to verify your understanding of the question.

```
python3 -i check
>>> problem5()
```

Once you are done checking, begin implementing your solution. You can check your correctness with:

`playTests.defaultTestSuite.run()`

Once you are finished, you will be able to play a graphical version of the game! Run everything in the playground file and pull up the live view. The groups of two do not need to implement the next two strategy functions.

**Part 2: Strategies**

**Note that the groups of two are not required to finish this part.**

## Problem 6: Bacon Strategy

A strategy can take advantage of the *Free Bacon* rule by rolling 0 when it is most beneficial to do so. Implement `getBaconStrategy`

, **which returns a strategy function** that returns 0 whenever rolling 0 would give **at least** `margin`

points and returns `numRolls`

otherwise.

Note that `getBaconStrategy`

only takes in margin and numRolls as arguments. The strategy function it returns will take in the two scores.

Before writing any code, use the script to verify your understanding of the question.

```
python3 -i check
>>> problem6()
```

Once you are done checking, begin implementing your solution. You can check your correctness with:

`baconStrategyTests.defaultTestSuite.run()`

## Problem 7: Swap Strategy

A strategy can also take advantage of the *Swine Swap* rule. The `getSwapStrategy`

function returns a strategy function that rolls 0 if it would cause a beneficial swap. It also returns 0 if rolling 0 would give **at least** `margin`

points, even if this would cause a non-beneficial swap. Otherwise, the strategy rolls `numRolls`

.

Before writing any code, use the script to verify your understanding of the question.

```
python3 -i check
>>> problem7()
```

Once you are done checking, begin implementing your solution. You can check your correctness with:

`swapStrategyTests.defaultTestSuite.run()`

## You’re done! Congrats on building your first game in Swift.

After you’re done with this project, you will compress the folder into a zip and send it to me on Wechat. I will do some code review and give you guys feedback.