The classic game, played from a list of guesses so it can be tested.
/build/project-number-guessing-game with the starter and the rubric already in it.Build the guess-the-number game with safe input parsing, a try limit and a score, driven by a fixed list of guesses instead of input(). Then write the perfect player: binary search, which never needs more than 7 guesses from 1 to 100.
A game driven by a list is a game you can test, which is the habit that separates a script from software. Ending with binary search turns a toy into the algorithm behind half of all interview questions on sorted data.
You can validate messy input, write a loop with two exit conditions and implement binary search.
Each step is one function in guess_game.py. In the workspace, press Check next to a step: it runs your file and tells you exactly what is still wrong.
Build against this exact list — it is the spec your published project is judged on.
Copy this into a new file — or open it in a workspace as guess_game.py. The TODO parts are yours to fill.
"""
Number guessing game, driven by a fixed list of guesses.
A real game would call input(). Here the guesses come from a list, so the
game runs the same way every time and a checker can test it. Swap GUESSES
for input() on your own machine once it works.
Fill in one function per step, press Run, then press "Check step".
"""
SECRET = 37
MAX_TRIES = 7
GUESSES = ["50", "25", "abc", "40", "150", "37", "12"]
def parse_guess(raw: str) -> int | None:
# TODO: strip spaces; return the int if raw is a whole number from 1 to
# 100, otherwise None ("abc", "", "150", "-3" are all None).
raise NotImplementedError("step 1, parse_guess(): text -> number or None")
def check_guess(secret: int, guess: int) -> str:
# TODO: "low" if guess < secret, "high" if guess > secret, else "correct"
raise NotImplementedError("step 2, check_guess(): low, high or correct")
def play(secret: int, guesses: list[str], max_tries: int = MAX_TRIES) -> dict:
# TODO: go through guesses in order and return
# {"won": bool, "tries": int, "history": [(raw, result), ...]}
# - an invalid guess goes in history as (raw, "invalid") and costs no try
# - stop at the first "correct"
# - stop when max_tries valid guesses have been used
raise NotImplementedError("step 3, play(): run the game on the list of guesses")
def score(game: dict, max_tries: int = MAX_TRIES) -> int:
# TODO: 0 if the game was lost, else (max_tries - tries + 1) * 10
raise NotImplementedError("step 4, score(): fewer tries, more points")
def best_guesses(secret: int, low: int = 1, high: int = 100) -> list[int]:
# TODO: the guesses a perfect player makes: always guess the middle
# (low + high) // 2, then move low or high past it. Binary search.
raise NotImplementedError("step 5, best_guesses(): binary search the secret")
def main() -> None:
first = parse_guess(GUESSES[0])
print(f"Secret is between 1 and 100. First guess {first} is {check_guess(SECRET, first)}.")
game = play(SECRET, GUESSES)
for raw, result in game["history"]:
print(f"guess {raw!r:>6} -> {result}")
if game["won"]:
print(f"You won in {game['tries']} tries. Score: {score(game)}")
else:
print(f"Out of tries. The number was {SECRET}.")
# TODO: print how many guesses binary search needs, and which:
# "Binary search needs 3 guesses: [50, 25, 37]"
raise NotImplementedError("step 6, main(): print the binary search line")
if __name__ == "__main__":
try:
main()
except NotImplementedError as todo:
# A fresh starter is SUPPOSED to stop here. Say which step is next
# instead of printing a traceback that looks like a bug.
print(f"Not built yet: {todo}")
print("Write that function, then press Run again. Each step you finish moves this message forward.")
Try every step first. This version passes all 6 checks; yours can look different and still pass.
"""
Number guessing game, driven by a fixed list of guesses.
A real game would call input(). Here the guesses come from a list, so the
game runs the same way every time and a checker can test it. Swap GUESSES
for input() on your own machine once it works.
"""
SECRET = 37
MAX_TRIES = 7
GUESSES = ["50", "25", "abc", "40", "150", "37", "12"]
def parse_guess(raw: str) -> int | None:
raw = raw.strip()
if not raw.isdigit():
return None
value = int(raw)
return value if 1 <= value <= 100 else None
def check_guess(secret: int, guess: int) -> str:
if guess < secret:
return "low"
if guess > secret:
return "high"
return "correct"
def play(secret: int, guesses: list[str], max_tries: int = MAX_TRIES) -> dict:
history = []
tries = 0
for raw in guesses:
if tries == max_tries:
break
guess = parse_guess(raw)
if guess is None:
history.append((raw, "invalid"))
continue
tries += 1
result = check_guess(secret, guess)
history.append((raw, result))
if result == "correct":
return {"won": True, "tries": tries, "history": history}
return {"won": False, "tries": tries, "history": history}
def score(game: dict, max_tries: int = MAX_TRIES) -> int:
if not game["won"]:
return 0
return (max_tries - game["tries"] + 1) * 10
def best_guesses(secret: int, low: int = 1, high: int = 100) -> list[int]:
guesses = []
while low <= high:
mid = (low + high) // 2
guesses.append(mid)
if mid == secret:
break
if mid < secret:
low = mid + 1
else:
high = mid - 1
return guesses
def main() -> None:
first = parse_guess(GUESSES[0])
print(f"Secret is between 1 and 100. First guess {first} is {check_guess(SECRET, first)}.")
game = play(SECRET, GUESSES)
for raw, result in game["history"]:
print(f"guess {raw!r:>6} -> {result}")
if game["won"]:
print(f"You won in {game['tries']} tries. Score: {score(game)}")
else:
print(f"Out of tries. The number was {SECRET}.")
print(f"Binary search needs {len(best_guesses(SECRET))} guesses: {best_guesses(SECRET)}")
if __name__ == "__main__":
main()
guess_game.py and a README.md holding all 5 rubric items as a checklist.pyrun.in/u/<handle>/w/project-number-guessing-game.pyrun.in/u/<handle> portfolio page.Your workspace saves to this browser only. Sign in to keep it across devices and to publish it.
Flip the workspace to Public and paste its URL below, or push the file to a GitHub gist or repo. Paste the code inline too if you want the optional AI review to comment on specific lines.
A published PyRun workspace URL (pyrun.in/u/<handle>/w/project-number-guessing-game) works as the public URL too.