Seminar 2 Guess the Number

Seminar #1 covered Python basics, so now you are ready to start developing you first game! We will build it step by step and there will be a lot to learn about input, libraries, conditional statements, and indentation. As before, download exercise notebook, copy it in your designated folder, and open it in Jupyter Notebook.

2.1 Game description

We will program a game in which one participant (computer) picks the number within a certain range (say, between 1 and 10) and the other participant (player) is trying to guess it. After every guess, the first participant (computer) responds whether the actual number is lower than a guess, higher than a guess, or matches it. The game is over when the player correctly guess the number or (in the later version of the game) runs out of attempts.

Our first version will allow just one attempt (will make it more fun later on) and the overall game algorithm will look like this:

# 1. computer generates a random number
# 2. prints it out for debug purposes
# 3. prompts user to enter a guess
# 4. compares two numbers and print outs the outcome
#    "My number is lower", "My number is higher", or "Spot on!"

2.2 Let’s pick the number (Exercise 1)

Let us start by creating a variable that will hold a number that computer “picked”. Let us name it number_picked (you can some other meaningful name as well but it might be easier if we all stick to the same name). To make things a bit simpler at the beginning, let us assign some hard=coded arbitrary number between 1 and 10 to it (whatever you fill like). Then, let us print it out, so that we know the number ourselves (we know it now but that won’t be the case when computer will generate it randomly). Use string formatting to make things user-friendly, e.g., print out something like “The number I’ve picked is …”. Your code should be a two-liner:

# 1. create variable and set it value
# 2. print out the value

Put your code into exercise #1 and make sure your code works!.

2.3 Asking user for a guess (Exercise 2)

Now we need to ask the player to enter their guess. For this, we will use input([prompt]) function (here and below the links lead to the official documentation). It prints out prompt (a string) if you supplied it, reads the input (key presses) until the user presses Enter, and returns it as a string. For a moment, let us assume that the input is always an valid integer number (so, type only valid integers!), so we can convert it to an integer without extra checks (will add them later) and assign this value to a new variable called guess. Thus, you need to write a single line assignment statement with guess variable on the left side, whereas on the right should be a call to the input(...) function (think of a nice prompt message) wrapped by the type-conversion to int(...). Switch to exercise 2 and, for the moment, only enter valid integers when running the code, so that the conversion works without an error.

Put your code into exercise #2.

2.4 Conditional if statement

Now we have two numbers: One that computer picked and one that is player’s guess. Now, we need to compare them to provide correct output message. For this, we will use conditional if statement:

if some_condition_is_true:
    # do something
elif some_other_condition_is_true:
    # do something else
elif yet_another_condition_is_true:
    # do yet something else
else:
    # do something only if all conditions above are false.

Only the if part is required, whereas elif (short for “else, if”) and else are optional. Thus you can do something, only if a condition is true:

if some_condition_is_true:
    # do something, but OTHERWISE DO NOT DO ANYTHING 
    # and continue with code execution
  
# some code that is executed after the if-statement,
# irrespective of whether the condition was true or not.

Before we can properly use conditional statements, you need to understand (1) the conditions themselves and (2) use of indentation as a mean of grouping statements together.

2.5 Conditions and comparisons (exercises 3-8)

Condition is any expression that can be evaluated to see whether it is True or False. A straightforward example of such expression are comparisons, in human language expressed as “is today Thursday?”, “is the answer equal to 42”, “is it raining and I have an umbrella?”. We will concentrate on them here but later you will see that in Python any expression is either True or False, even when it does not look like a comparison.

For the comparison, you can use the following operators:

  • “A is equal B” is written as A == B.
  • “A is not equal B” is written as A != B.
  • “A is greater than B” and “A is smaller than B” are, respectively, A > B and A < B.
  • “A is greater than or equal to B” and “A is smaller than or equal to B” are, respectively, A >= B and A <= B (please note the order of symbols!).

Go to exercise #3 to solve some comparisons.

You can invert the logical value using not operator, as not True is False and not False is True. This means that A != B is the same as not A == B and, correspondingly, A == B is not A != B. To see how that works, consider both cases when A is indeed equal B and when it is not.

  • If A is equal B then A == B evaluates to True. The A != B is then False, so not A != Bnot FalseTrue.
  • If A is not equal B then A == B evaluates to False. The A != B is then True, so not A != Bnot TrueFalse.

Go to exercise #4 to explore this inversion yourself.

You can also combine several comparisons using and and/or or operators. As in human language, and means that both parts must be true: True and TrueTrue but True and FalseFalse, False and TrueFalse, and False and FalseFalse. Same holds if you have more have than two conditions/comparisons, all of them must be true. In case of or only one of the statements must be true, e.g. True and TrueTrue, True and FalseTrue, False and TrueTrue, but False and FalseFalse. Again, for more than two comparisons/conditions at least one of them should be true for the entire expression to be true.

Do exercises #5 and #6.

Subtle but important point: conditions are evaluated from left to right until the whole expression can be definitely resolved. This means that if the first expression in a and pair is False, the second one is never evaluated. I.e., if first and second expressions both need to be True and you know that already first expression is false, the whole expression will be False in any case. This means that in the code below there will be no error, even though evaluating int("e123") raises ValueError.

2 * 2 == 5 and int("e123") == 123

However, reverse the order, so that int("e123") == 123 needs to be evaluated first and you get the error message

int("e123") == 123 and 2 * 2 == 4
# Generates ValueError: invalid literal for int() with base 10: 'e123'

Similarly, if any expression in or is True, you do not need to check the rest.

2 * 2 == 4 or int("e123") == 123

However, if the first condition is False, we do need to continue (and stumble into an error):

2 * 2 == 5 or int("e123") == 123
# Generates ValueError: invalid literal for int() with base 10: 'e123'

Do exercise #7.

Finally, like in simple arithmetic, you can use brackets () to group conditions together. Thus a statement “I always eat chocolate but I eat spinach only when I am hungry” can be written as food == "chocolate" or (food == "spinach" and hungry). Here, the food == "chocolate" and food == "spinach" and hungry are evaluated independently, their values are substituted in their place and then the and condition is evaluated.

Do exercise #8.

2.6 Grouping statements via identation (exercise #9)

Let us go back to the conditional if-statement. Take a look at following code example, in which statement #1 is executed only if some condition is true, whereas statement #2 is executed after that irrespective of the condition.

if some_condition_is_true:
    statement #1
statement #2 

Both statements #1 and #2 appear after the if-statement, so how does Python now that the first one is executed only if condition is true but the other one always runs? The answer is indentation (the 4 (four!) spaces, they are automatically added whenever you press Tab and removed whenever you press Shift + Tab) that puts statement #1 inside the if-statement. Thus, indentation shows whether statements belong to the same group (same indentation as for if and statement #2) or are inside conditional statement, loop, or function (statement #1). For more complex code that will have, for example, if-statement inside an if-statement inside a loop, you will express this by adding more levels of indentation. E.g.

# some statements outside of the loop (0 indentation)
while game_is_not_over: # (0 indentation)
    # statements inside of the loop 
    if key_pressed: # (indentation of 4)
        # inside loop and if-statement 
        if key == "Space": # (indentation of 8)
            # inside the loop, and if-statement, and another if-statement
            jump() # (indentation of 12)
        else: # (indentation of 4)
            # inside the loop, and if-statement, and else part of another if-statement
            stand() # (indentation of 12)
    
    # statements inside of the loop but outside of the outermost if-statement
    print(key) # (indentation of 4)
    
# some statements outside of the loop (0 indentation)

Pay very close attention to the indentation as it determines which statements are executed together!

Do exercise #9.

The if and ifelse statements are evaluated until one of them turns out to be True. After that any following ifelse and else statements are simply ignored.

Do exercise #10.

2.7 Checking the answer (Exercise 11)

Now you have all necessary instruments to finish the first version of our game. Go to exercise #11 and, first, copy-paste your solutions to exercise #1 (settings computer pick and printing it out) and #2 (getting player input as an integer). Now, add conditional statements below, so that

  • if the computer pick is smaller than player’s guess, it will print "My number is lower!"
  • if the computer pick is larger than player’s guess, it will print "My number is higher!"
  • if two numbers are identical, it will print "Spot on!"

Put your code into exercise #11.

2.8 Picking number randomly (Exercise 12)

Our game is “feature-complete”: computer picks a number, player makes a guess, computer responds appropriately. However, currently we are playing for both sides, as we hand pick the number for computer. Now, we will let computer pick this number itself using randint(a, b) function. It is part of the random library, so you will need to import it first. We will talk about libraries and importing them in greater detail later. For now, it suffices that the top line of your code is

from random import randint

Function randint(a, b) generates a random integer on the interval a..b. In our case, this interval is 1..10. Go to exercise #11. First copy-paste your solution for exercise #12. Add the from random import randint as the first line. Then, replace the hard-coded value you used for computer’s pick with a call to randint() function. Run the code several times to check that computer does pick different random values.

Put your code into exercise #12.

Congratulations, you just programmed your first computer game! Yes, it is very simple but it has key ingredients: a random decision by computer, user input, and feedback. Next time, you will learn about loops to allow for multiple attempts and about functions to make your code modular and reliable. In the meantime, let us solidify your knowledge by programming yet another game!

2.9 One-armed bandit (Exercise 13)

You know everything you need to program a simple version of an “one-armed bandit” game (exercise #13). Here is the game logic:

  1. from random import randint
  2. Generate three random integers (say, between 1 and 5) and store them in three variables slot1, slot2, and slot3.
  3. Print out the numbers, use string formatting to make it look nice.
  4. In addition,
    • if all three values are the same, print "Three of a kind!".
    • If only two numbers match, print "Pair!".
    • Print nothing, if all numbers are different.

Put your code into exercise #13.