mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-05 20:40:25 -08:00
181 lines
5.4 KiB
Python
181 lines
5.4 KiB
Python
"""
|
|
Bagels
|
|
|
|
From: BASIC Computer Games (1978)
|
|
Edited by David H. Ahl
|
|
|
|
"In this game, the computer picks a 3-digit secret number using
|
|
the digits 0 to 9 and you attempt to guess what it is. You are
|
|
allowed up to twenty guesses. No digit is repeated. After
|
|
each guess the computer will give you clues about your guess
|
|
as follows:
|
|
|
|
PICO One digit is correct, but in the wrong place
|
|
FERMI One digit is in the correct place
|
|
BAGELS No digit is correct
|
|
|
|
"You will learn to draw inferences from the clues and, with
|
|
practice, you'll learn to improve your score. There are several
|
|
good strategies for playing Bagels. After you have found a good
|
|
strategy, see if you can improve it. Or try a different strategy
|
|
altogether and see if it is any better. While the program allows
|
|
up to twenty guesses, if you use a good strategy it should not
|
|
take more than eight guesses to get any number.
|
|
|
|
"The original authors of this program are D. Resek and P. Rowe of
|
|
the Lawrence Hall of Science, Berkeley, California."
|
|
|
|
|
|
Python port by Jeff Jetton, 2019
|
|
"""
|
|
|
|
|
|
import random
|
|
from typing import List
|
|
|
|
MAX_GUESSES = 20
|
|
|
|
|
|
def print_rules() -> None:
|
|
print("\nI am thinking of a three-digit number. Try to guess")
|
|
print("my number and I will give you clues as follows:")
|
|
print(" PICO - One digit correct but in the wrong position")
|
|
print(" FERMI - One digit correct and in the right position")
|
|
print(" BAGELS - No digits correct")
|
|
|
|
|
|
def pick_number() -> List[str]:
|
|
# Note that this returns a list of individual digits
|
|
# as separate strings, not a single integer or string
|
|
numbers = list(range(10))
|
|
random.shuffle(numbers)
|
|
num = numbers[:3]
|
|
return [str(i) for i in num]
|
|
|
|
|
|
def get_valid_guess(guesses: int) -> str:
|
|
valid = False
|
|
while not valid:
|
|
guess = input(f"Guess # {guesses} ? ")
|
|
guess = guess.strip()
|
|
# Guess must be three characters
|
|
if len(guess) == 3:
|
|
# And they should be numbers
|
|
if guess.isnumeric():
|
|
# And the numbers must be unique
|
|
if len(set(guess)) == 3:
|
|
valid = True
|
|
else:
|
|
print("Oh, I forgot to tell you that the number I have in mind")
|
|
print("has no two digits the same.")
|
|
else:
|
|
print("What?")
|
|
else:
|
|
print("Try guessing a three-digit number.")
|
|
|
|
return guess
|
|
|
|
|
|
def build_result_string(num: List[str], guess: str) -> str:
|
|
result = ""
|
|
|
|
# Correct digits in wrong place
|
|
for i in range(2):
|
|
if num[i] == guess[i + 1]:
|
|
result += "PICO "
|
|
if num[i + 1] == guess[i]:
|
|
result += "PICO "
|
|
if num[0] == guess[2]:
|
|
result += "PICO "
|
|
if num[2] == guess[0]:
|
|
result += "PICO "
|
|
|
|
# Correct digits in right place
|
|
for i in range(3):
|
|
if num[i] == guess[i]:
|
|
result += "FERMI "
|
|
|
|
# Nothing right?
|
|
if result == "":
|
|
result = "BAGELS"
|
|
|
|
return result
|
|
|
|
|
|
def main() -> None:
|
|
# Intro text
|
|
print("\n Bagels")
|
|
print("Creative Computing Morristown, New Jersey\n\n")
|
|
|
|
# Anything other than N* will show the rules
|
|
response = input("Would you like the rules (Yes or No)? ")
|
|
if len(response) > 0:
|
|
if response.upper()[0] != "N":
|
|
print_rules()
|
|
else:
|
|
print_rules()
|
|
|
|
games_won = 0
|
|
still_running = True
|
|
while still_running:
|
|
|
|
# New round
|
|
num = pick_number()
|
|
num_str = "".join(num)
|
|
guesses = 1
|
|
|
|
print("\nO.K. I have a number in mind.")
|
|
guessing = True
|
|
while guessing:
|
|
|
|
guess = get_valid_guess(guesses)
|
|
|
|
if guess == num_str:
|
|
print("You got it!!!\n")
|
|
games_won += 1
|
|
guessing = False
|
|
else:
|
|
print(build_result_string(num, guess))
|
|
guesses += 1
|
|
if guesses > MAX_GUESSES:
|
|
print("Oh well")
|
|
print(f"That's {MAX_GUESSES} guesses. My number was {num_str}")
|
|
guessing = False
|
|
|
|
valid_response = False
|
|
while not valid_response:
|
|
response = input("Play again (Yes or No)? ")
|
|
if len(response) > 0:
|
|
valid_response = True
|
|
if response.upper()[0] != "Y":
|
|
still_running = False
|
|
|
|
if games_won > 0:
|
|
print(f"\nA {games_won} point Bagels buff!!")
|
|
|
|
print("Hope you had fun. Bye.\n")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
|
|
######################################################################
|
|
#
|
|
# Porting Notes
|
|
#
|
|
# The original program did an unusually good job of validating the
|
|
# player's input (compared to many of the other programs in the
|
|
# book). Those checks and responses have been exactly reproduced.
|
|
#
|
|
#
|
|
# Ideas for Modifications
|
|
#
|
|
# It should probably mention that there's a maximum of MAX_NUM
|
|
# guesses in the instructions somewhere, shouldn't it?
|
|
#
|
|
# Could this program be written to use anywhere from, say 2 to 6
|
|
# digits in the number to guess? How would this change the routine
|
|
# that creates the "result" string?
|
|
#
|
|
######################################################################
|