# Eliminating Loops: A Number Guessing Game in Python

### Interact with this notebook on Binder here.¶

Just for fun, let us take a quick look at how we could take out all loops from any Python program. Most of the time this is a bad idea, both for readability and performance, but it is worth looking at how simple it is to do in a systematic fashion as background to contemplate those cases where it is actually a good idea.

Excerpt From: David Mertz. Functional Programming in Python

In :
from IPython.display import display, Image

In :
display(
Image(
url="https://minio.apps.selfip.com/mymedia/screenshots/functional_programming_in_python.png"
)
) ## Basic REPL¶

In :
def identity(item):
print(f"output: {item}")
return item

echo = lambda: identity(input("Type something:\r")) == "quit" or echo()
echo()

Type something:
Hello,
output: Hello,
Type something:
world.
output: world.
Type something:
quit
output: quit

Out:
True
In :
import random

EXIT_WORD = "quit"
EXIT_WORDS = {EXIT_WORD, "q", "bye", "exit"}

def get_verification(guess):
guess_int = int(guess)
return EXIT_WORD
return "higher" if guess_int < ANSWER else "lower"

def identity(item):
verification = hint = get_verification(item)
if verification != EXIT_WORD:
print(f'your guess: "{item}" should be {hint}')

return verification

echo = lambda: identity(input("Type something:\r")) in EXIT_WORDS or echo()
echo()

Type something:
1
your guess: "1" should be higher
Type something:
5
your guess: "5" should be lower
Type something:
3
your guess: "3" should be lower
Type something:
2

Out:
True

### Make the game more complex. It now has state.¶

In :
import random

EXIT_WORDS = {"quit", "q", "bye", "exit"}
START, STOP = 1, 11
END = STOP - 1

GUESSES = 3
counter = 0

def count():
global counter
counter += 1

def get_message(guess):
if guess in EXIT_WORDS:
return guess
guess_int = int(guess)
return f'The answer "{guess_int}" is correct.'
hint = "higher" if guess_int < ANSWER else "lower"
return f'Guess {hint} than "{guess}".'

def identity(item):
print(get_message(item))
count()
return item

echo = (
lambda: any(
(
identity(input(f"Type a number between {START} and {END}:\r"))
in EXIT_WORDS,
counter > GUESSES,
)
)
or echo()
)
echo()

Type a number between 1 and 10:
1
Guess higher than "1".
Type a number between 1 and 10:
5
Guess higher than "5".
Type a number between 1 and 10:
7
Guess higher than "7".
Type a number between 1 and 10:
10
Guess lower than "10".

Out:
True

### Refactor to handle malformed input.¶

Add a try, except where the guess is cast to an int.

In :
import random

EXIT_WORDS = {"quit", "q", "bye", "exit"}
START, STOP = 1, 11
END = STOP - 1

MAX_GUESSES = 3
counter = 0

def count():
global counter
counter += 1

def get_message(guess):
if guess in EXIT_WORDS:
return guess
try:
guess_int = int(guess)
except ValueError:
return f'"guess" is not valid input.'
return f'The answer "{guess_int}" is correct.'
hint = "higher" if guess_int < ANSWER else "lower"
return f'Guess {hint} than "{guess}".'

def identity(item):
print(get_message(item))
count()
return item

echo = (
lambda: any(
(
identity(input(f"Type a number between {START} and {END}:\r"))
in EXIT_WORDS,
counter >= MAX_GUESSES,
)
)
or echo()
)
echo()
if counter >= GUESSES:
print(f'Maximum guesses of "{MAX_GUESSES}" exceeded.')

Type a number between 1 and 10:
cat
"guess" is not valid input.
Type a number between 1 and 10:
1
Guess higher than "1".
Type a number between 1 and 10:
10
Guess lower than "10".
Maximum guesses of "3" exceeded.

Out:
'The answer is 7'

### Refactor to remove the lambda.¶

Add a try, except where the guess is cast to an int.

In :
import random

EXIT_WORDS = {"quit", "q", "bye", "exit"}
START, STOP = 1, 11
END = STOP - 1

MAX_GUESSES = 3
counter = 0

def count():
global counter
counter += 1

def get_message(guess):
if guess in EXIT_WORDS:
return guess
try:
guess_int = int(guess)
except ValueError:
return f'"guess" is not valid input.'
return f'The answer "{guess_int}" is correct.'
hint = "higher" if guess_int < ANSWER else "lower"
return f'Guess {hint} than "{guess}".'

def identity(item):
print(get_message(item))
count()
return item

def echo():
return (
any(
(
identity(input(f"Type a number between {START} and {END}:\r"))
in EXIT_WORDS,
counter >= MAX_GUESSES,
)
)
or echo()
)

echo()
if counter >= GUESSES:
print(f'Maximum guesses of "{MAX_GUESSES}" exceeded.')

Type a number between 1 and 10:
1
Guess higher than "1".
Type a number between 1 and 10:
10
Guess lower than "10".
Type a number between 1 and 10:
5
5
Maximum guesses of "3" exceeded.

Out:
'The answer is 5'