# Validating input

When you read input from a person running your program, you should be prepared for them to type something unexpected!

For example, let’s imagine you work for a doctor and you want to write a simple program to ask a person how much pain they are in, using a standard 10-point scale, where 10 is highest:

```
def get_number():
while True:
response = int(input('How much pain are you in? Enter a number from 1 to 10: '))
if response > 10:
print('That was too high, try again:')
continue
return response
print(get_number())
```

This code will check to be sure the number they enter is not too high. But what if they enter one of the following?

- zero
- a negative number
- a fraction
- a decimal
- a letter

Let’s write a better version:

```
def get_number():
while True:
response = input('How much pain are you in? Enter a number from 1 to 10: ')
# check if it is a digit
if not response.isdigit():
print('That is not a number, try again')
continue
# now we can convert to an integer
response = int(response)
# check if too high
if response > 10:
print('That was too high, try again')
continue
# check if too low
if response < 1:
print('That was too low, try again')
continue
return response
print(get_number())
```

## Number Game

This program plays a game with any number of players to guess a number. Each player gets one chance. The player that is closest wins. Ties go to the player that guessed earlier.

The computer randomly picks a number between a lower bound and an upper bound. Each player is prompted to guess a number. A guess is invalid if:

- it isn’t a positive integer
- it isn’t between the lower and upper bounds
- another player has already guessed that number

If a player submits an invalid guess, they should be informed why their guess was invalid and they must guess again.

The function to play the game takes these arguments:

`play_number_game(lower, upper, num_players)`

### A flow chart

Here is a flow chart illustrating how to write this game:

### Code for the main game loop

Let’s write the code for the main game loop:

- pick a random number
- loop through all the players
- get a guess from each player
- add to a list of guesses

- determine winner

```
import sys
import random
def play_number_game(lower, upper, num_players):
guesses = []
number = random.randint(lower, upper)
for player in range(num_players):
guess = get_a_guess(player, lower, upper, guesses)
guesses.append(guess)
print(f"The number is {number}")
winner = find_a_winner(number, guesses)
print(f'Player {winner + 1} wins!')
if __name__ == '__main__':
play_number_game(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3]))
```

Notice how we have purposely left two functions undefined — `get_a_guess()`

and
`find_a_winner()`

. This is a good way to start writing the code.

### Getting a guess

The next step is to write the `get_a_guess()`

function.

```
def get_a_guess(player):
guess = input(f'Player {player + 1} guess: ')
return guess
```

OK, that will sort of work. :-) But it doesn’t do any of the input validation.
And to do that, this function needs the lower and upper bounds as a parameter.
And if the user makes a mistake, we need to keep letting them input a number
until they provide a correct guess. That means we need a `while True`

.

```
def get_a_guess(player, lower, upper):
while True:
guess = input(f'Player {player + 1} guess: ')
guess = int(guess)
if guess < lower or guess > upper:
print(f"The number must be between {lower} and {upper}.")
continue
return guess
```

Notice how we can return out of the while loop as soon as we get a valid guess.

This is a good start, but what about checking if another player has already made the same guess? We need to add yet another parameter to the function — all the guesses made previously.

```
def get_a_guess(player, lower, upper, previous_guesses):
while True:
guess = input(f'Player {player + 1} guess: ')
guess = int(guess)
if guess < lower or guess > upper:
print(f"The number must be between {lower} and {upper}.")
continue
if guess in previous_guesses:
print("That number has already been guessed. Guess another.")
continue
return guess
```

### Trying what we have

OK, that looks pretty good! Let’s be sure to call it correctly and let’s comment out the other function we haven’t written yet.

```
import sys
import random
def play_number_game(lower, upper, num_players):
guesses = []
number = random.randint(lower, upper)
for player in range(num_players):
guess = get_a_guess(player, lower, upper, guesses)
guesses.append(guess)
print(f"The number is {number}")
# winner = find_a_winner(number, guesses)
# print(f'Player {winner + 1} wins!')
if __name__ == '__main__':
play_number_game(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3]))
```

If we run this:

```
% python number_game.py 1 10 2
Player 1 guess: 100
The number must be between 1 and 10.
Player 1 guess: 3
Player 2 guess: 3
That number has already been guessed. Guess another.
Player 2 guess: 7
The number is 9
```

We can see the game appears to be working, except for picking a winner.

### Determining a winner

Now we need to write `find_a_winner()`

. We are given the correct number and all
of the guesses. We could write a flow chart for this piece as well. Or we could
write an english description:

- keep track of best distance from guess to correct number
- keep track of the closest player
- loop through all the guesses
- compute how far this guess is from the answer
- if this guess is closer than the closet one so far
- update the best distance and the closest player return closest player

```
def find_a_winner(number, guesses):
best_distance = None
closest_player = None
for player in range(len(guesses)):
# find the distance between this player's guess and the true number
distance = abs(guesses[player] - number)
# check if we have found a closest yet
if best_distance == None:
best_distance = distance
closest_player = player
continue
# check if we have a better distance
if distance < best_distance:
best_distance = distance
closest_player = player
return closest_player
```

### Putting it together

You can add the `find_a_winner() function, uncomment those two lines in the main loop, and see how this works. You should be able to play the complete game.