-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy path04-guess-the-number-multi-round.Rmd
176 lines (121 loc) · 9.87 KB
/
04-guess-the-number-multi-round.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# Guess the Number: a multi round edition {#guess-the-number-multi-round}
In previous chapter, you programmed a single-attempt-only "Guess the Number" game. Now, we will expand to allow multiple attempts and will add other bells-and-whistles to make it more fun. Create a new subfolder and download the [exercise notebook](notebooks/Guess the number - multi round.ipynb) before we start!
## Chapter concepts
* Repeating code using [while](#while-loop) loop.
* Making in [emergency exit](#break) from a loop.
## While loop {#while-loop}
If you want to repeat something, you need to use loops. There are two types of loops: [while](https://docs.python.org/3/reference/compound_stmts.html#the-while-statement) loop, which is repeated _while_ a condition is true, and [for](https://docs.python.org/3/reference/compound_stmts.html#the-for-statement) loop that iterates over items (we will use it later).
The basic structure of a _while_ loop is
```{python eval=FALSE}
# statements before the loop
while <condition>:
# statements inside are executed
# repeatedly for as long as
# the condition is True
# statements after the loop
```
The `<condition>` here is any expression that is evaluated to be either `True` or `False`, just like in an `if...elif...else` [conditional statement](#comparisons). Also, the same [indentations rules](#indentation) determine which code is inside the loop and which outside.
::: {.practice}
Do exercise #1.
:::
Let us use _while_ loop to allow the player to keep guessing until they finally get it right. You can copy-paste the code you programmed during the last seminar or could redo it from scratch (I would strongly recommend you doing the latter!). The overall program structure should be the following
```{python eval=FALSE}
# import random library so you can use randint function
# generated a random number and store in number_picked variable
# get player input, convert it to an integer, and store in guess variable
# while players guess is not equal to the value the computer picked:
# print out "my number is smaller" or "my number is larger" using if-else statement
# get player input, convert it to an integer, and store in guess variable
# print "Spot on!"
# (because if we got here that means guess is equal to the computer's pick)
```
::: {.program}
Put your code into `code01.py`.
:::
Do not forget to document the file and use breakpoints and step overs to explore the program flow.
## Counting attempts
Now let us add a variable that will count a total number of attempts by the player. For this, create a new variable (call it `attempts` or something similar) _before the loop_ and initialize it `1` (because the first attempt is before the player enter the loop). Add `1` to it every time the player enters a guess. After the loop, expand the `"Spot on!"` message by adding information about the number of attempts. Use [string formatting](##string-formatting) to make things look nice, e.g., `"Spot on, and you needed just 5 attempts!"`. Check that the number of attempts your required _matches_ the number of attempts reported by the program!
::: {.program}
Put your code into `code02.py`.
:::
## Breaking (and exiting){#break}
Code inside the _while_ loop is executed repeatedly while the condition is `True` and, importantly, all of code inside is executed before the condition is evaluated again. However, sometimes you may need to abort sooner without executing the remaining code. For this, Python has a [break](https://docs.python.org/3/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops) statement that causes the program to exit the loop immediately without executing the rest of the code inside the loop, so that the program continues with the code _after_ the loop.
```{python eval=FALSE}
# this code runs before the loop
while <some_condition>:
# this code runs on every iteration
if <some_other_condition>:
break
# this code runs on every iteration but not when you break out of the loop
# this code runs after the loop
```
::: {.practice}
Do exercise #2 to build your intuition.
:::
## Limiting number of attempts via break
Let's put the player under some pressure! Decide on maximal number of attempts you allow and stores it as a [CONSTANT](#constants). Pick an appropriate name (e.g. `MAX_ATTEMPTS`) and REMEMBER, ALL CAPITAL LETTERS for a constant name! Now, use `break` to quit the `while` loop, if the current attempt number is greater than `MAX_ATTEMPTS`. Think about when (within the code inside the loop) you should check this.
::: {.program}
Put your code into `code03.py`.
:::
## Correct end-of-game message
Let us update the final message. Currently it says "Spot on..." because we assumed that program exited the loop only if the player gave a correct answer. With limited attempts that is not necessarily the case. Now there are two reasons why it exited the while loop:
1. The player answered correctly
2. The player ran out of attempts.
Use `if-else` conditional statement to print out an appropriate message. E.g., print `"Better luck next time!"`, if the player lost (ran out of attempts).
::: {.program}
Put your code into `code04.py`.
:::
## Limiting number of attempts without a break
Although it was my idea to add the `break` statement, you should use it sparingly. Without `break` there is a _single_ place in the code that you need to check to understand when the program will exit the loop: the condition. However, if you add a `break`, you now have _two_ places that need to be examined. And every additional `break` keeps adding to that. This does not mean that you should avoid them at all costs! You _should_ use them, if this makes the code easier to understand. But always check if a modified condition could also do the trick.
Let us try exactly that. Modify your code to work _without_ the `break` statement. You need a more complicated condition for your while loop. so that it repeats while player's guess is incorrect and the number of attempts is still less than the maximally allowed. Test that your code works both when you win and when you lose.
::: {.program}
Put your code into `code05.py`.
:::
## Show remaining attempts
It is all about the user interface! Modify the `input` prompt message to include a number of _remaining_ attempts. E.g. `"Please enter the guess, you have X attempts remaining"`.
::: {.program}
Put your code into `code06.py`.
:::
## Repeating the game {#guess-the-number-repeat-game}
Let us give an option for the player to play again. This means putting _all_ the current code inside of another `while` loop (this is called _nested loops_) that is repeated for as long as the player wants to keep playing. The code should look as follows:
```{python eval=FALSE}
# import random library so you can use randint function
# define MAX_ATTEMPTS
# define a variable called "want_to_play" and set to True
# while the player still wants to play
# your current working game code goes here
# ask user whether via input function. E.g. "Want to play again? Y/N"
# want_to_play should be True if user input is equal to "Y" or "y"
# very final message, e.g. "Thank you for playing the game!"
```
**Pay extra attention to indentations to group the code properly!**
::: {.program}
Put your code into `code07.py`.
:::
## You do not need a comparison, if you already have the value
In your updated code, you have `want_to_play` variable that is either `True` or `False`. It is used in the loop that repeats while its value is `True`. Sometimes, people write `want_to_play == True` to express that. While it is technically correct and will certainly work correctly, it is also redundant. Since `want_to_play` can only be `True` or `False` this comparison turns into `True == True` (which is of course `True`) or `False == True` (which is `False`). So comparing either value to `True` produces exactly the same value. Thus, you can just write `while want_to_play:` and use the logical value directly.
## Best score
A "proper" game typically keeps the track of players' performance. Let us record a fewest number of attempts that the player needed to guess the number. For this, create a new variable `fewest_attempts` and set it to `MAX_ATTEMPTS` (this is as bad as the player can be). Think, where do you need to create it. You should update it after each game round. Add the information about "Best so far" into the round-over message.
::: {.program}
Put your code into `code08.py`.
:::
## Counting game rounds
Let us count how many times the player played the game. The idea and implementation is the same as with counting the attempts. Create a new variable, initialize it to 0, increment by 1 whenever a new round starts. Include the total number of games played into the very final message, e.g. "Thank you for playing the game _X_ times!"
::: {.program}
Put your code into `code09.py`.
:::
## Multi round one-armed bandit
At the end of the previous chapter, you have programmed a single round one-armed bandit game. You already know everything you need to implement a multiple round version and its structure is similar (but simpler) than of the multi-round guess-the-number game that you just implemented.
Let player start with an initial pot of money, say 10 coins. Playing each round costs 1 coin, getting three of a kind pays off 10 coins, while getting a pair pays off 2 coins (you can change payoffs as you see fit). On each round:
* Take one coin from the pot (price for playing the game).
* Roll the dice (you already implemented that).
* Tell the player about the outcome (you implemented that as well).
* Add coins to the pot, if necessary.
* Print out the amount of coins left in pot.
* Ask the player where they want to continue.
Special case, once the player runs out of coins, the game is definitely over.
::: {.program}
Put your code into `code10.py`.
:::
## Wrap up
Most excellent, you now have two proper working computer games with game rounds, limited attempts, best score, and what not! Zip the folder and submit.