This game needs a loop, and the previous implementation was not complete. If there is a tie, then the game has to be repeated, and a winner must be determined. This means that the loop in this case is as follows:

while there is no winner:

This happens only when the player and the computer select the same object, and in the original code, it was handled by the statements:

if player == choice:

print (“Game is a tie. Please try again.”)

The condition “no winner” becomes **player == choice**. The complete solution involves the **while** loop and another input from the user within the loop. Here is one possible answer:

choice = “paper” # Computer chooses paper.

print (“Rock-paper-scissors: type in your choice: “)

player = input ()

# ——– The new section of code ———————-

while player == choice: # Repeat input until there is a

winner

print (“Game is a tie. Please try again.”)

player = input ()

#

if player == “rock”:

if choice == “scissors”:

print (“Congratulations. You win.”)

else:

print (“Sorry – computer wins.”)

elif player == “paper”:

if choice == “scissors”:

print (“Sorry – computer wins.”)

else:

print (“Congratulations. You win.”)

elif player == “scissors”:

if choice == “rock”:

print (“Sorry – computer wins.”)

else:

print (“Congratulations. You win.”)

else:

print (“Error: Select one of: rock, paper, scissors”)

The termination of the loop depends on the user’s input, and on the value of the computer’s choice, which could also (and should) change inside the loop. The probability of the loop continuing after one iteration is 1 in 3, and the probability that it will still be looping after N iterations is (1/3)^{N}, so there is a very small chance of the loop repeating more than 2 or 3 times.

### 1. Random Numbers

Most games depend on an element of unpredictability or chance. Those that do not might be more properly called *puzzles*. Given that computers do calculations, and that calculations should have the same result every time, how does one produce anything that is random using a computer? The answer is partly in how the term *random* is defined. The discussion involves some mathematics or at least some basic ideas in probability and statistics.

If integers in the range 1 through 10 inclusive are considered, what is the likelihood (chance, probability) that the number 5 will be selected at random? The answer is 1 in 10, or 0.1. This is true each time the question is asked. If the number 5 has just been chosen and another number is to be chosen, what is the chance that it will be a 5? Same answer: 1 in 10. The principle is that the next choice does not depend on the previous one.

Perhaps the wrong question is being asked. What is the likelihood that the number 5 will be selected twice in a row at random? The answer is 1 in 100, or 0.01. Why? Because it depends on the question asked. To get two in a row, the first one must be a 5 (1 in 10) and the second one must also be a 5 (also 1 in 10), so the resulting likelihood is 1 in 10*10 or 1 in 100. But each time a number is chosen, the number 5 has a 1 in 10 chance of being selected. A mathematical discussion of randomness depends on the asking the right question, and on probabilities. If some event is completely random, then it should have the same probability of happening as the other possible events, but events can be collected to form more complex events. Each card in a deck of playing cards should have the same probability of turning up, but if the question is “What’s the chance of a flush?,” then the different ways that a flush can be comprised have to be taken into account.

Numbers, in particular, are random only with respect to each other. Is the number 6 random? That’s not really a good question. Is the sequence 87394 random? Perhaps a test could be devised to answer that. Is the sequence 66666 random? Most would say not, but it has the same probability of being generated at random as does 87354. To create good games and simulations, it is necessary to devise ways to generate a random number using a computer and to test numbers to see if they are in fact random. Then it would be possible to simulate the flipping of a coin or the rolling of a die.

What is the 100^{th} digit of pi? It can be found easily. Are consecutive digits of pi effectively random? As it happens, the answer is not known, but it is a good question. What is 108763 is divided by 98581? What is the remainder? Call the remainder x: what is 108763 divided by x? Are these numbers random? The search for a method for generating really good random numbers continues, but there are some pretty good methods (See Chapter 10). In Python, a random number created by a computer algorithm can be requested by using a built-in function.

A built-in function is like a mathematical function, and it is provided by the language itself. The language element print is a built-in function, as are int () and float (). The functions *sine* and *square root* are also built-in functions. Such functions belong to *modules* in Python and have to be requested by the program so that they can be used. This means that the name of the module has to be known as well as the names of the built-in functions within it. The common mathematical functions are located within the module **math** and can be used by requesting the math module with the statement:

import math

Using a function in the math module involves using the name math followed by a period (.) followed by the name of the function. The “” opens the module so that the names within can be used, because there may be other built-in functions or even variables that have the same name. If the statements

x = math.sqrt(64)

print (x)

are executed, the program prints the number 8, which is the square root of 64. The expression **sqrt (64)** is called a function call, and executes the code needed to calculate the square root of 64. The name **sqrt** is the name of the function, which is code provided by the Python language. This particular call always returns the value 8, because 8 is always the square root of 64. A module can be thought of as a bag of programs. Each bag contains a set of programs that do a particular class of things, like mathematics or drawing. By specifying the name of the module, access to all of the functions within is granted, and by specifying the specific name of a function, the code that we want is specifically made available.

The **import** statement should be at the very beginning of the program.

Imagine that it is possible to have a function that produces a random number as a value. It is in the module named random, and the function is called random, too. For example,

import random

print ( random.random() )

Every time the function is used, it gives a different value, a random value. This value can be used to make games more realistic, because games have a random aspect.

This code prints the value 0.07229650795715237. Why? Because** random. random ()** produces a random number between 0.0 and 1.0. This is the most common example of a random number function, and is really very general. Increasing the range is done simply by multiplying by the maximum value desired; **random. random ()*100** gives a random number between 0 and 100, for instance.

What if the problem is to simulate the roll of a die? The bag of code that is the **random** module contains other functions related to the generation of random numbers, and one of them is especially suited to this problem. A die roll would be implemented as follows:

random.randint (1, 6)

The **randint** function accepts two numbers, called *parameters*. The first is the lower limit of the range of random integers to be produced and the second is the upper limit. Specifying 1 as the lower limit and 6 as the upper limit, as in the example above, means that it will generate numbers between 1 and 6 inclusive, which is what would be expected from rolling a die. The result of rolling two dice would be a number between 2 and 12, found by **random.randint (2,12).**

Flipping a coin is a two-level choice, and could be done with** random.rand- int (1,2)**.

if (random.randint(1,2) == 1): print (“Heads”) else:

print (“Tails”)

Going back again to the number guessing game, a random choice for the computer’s number is now possible. Instead of the first line of code being

choice = 7

it should now be

choice = random.randint(1,10)

Every time the program executes the program, it will select a new random number, as opposed to the choice always being 7.

The introduction of a random choice is a little more complicated for the rock- paper-scissors program because the variable holding the player’s choice is a string. There are three possible choices, so to select one at random might look like this:

i = random.randint(1,3)

if i == 1:

choice = “rock”

elif i == 2:

choice = “paper”

else:

choice = “scissors”

Many of the examples in this book involve a game or puzzle of some kind, so the use of random numbers will be a consistent feature of the code shown.

Source: Parker James R. (2021), *Python: An Introduction to Programming*, Mercury Learning and Information; Second edition.