Aller au contenu principal

Lab 02 — Number Guessing Game

Hands-on Lab 35 min Beginner

Objectives

  1. Use while True + break for a game loop
  2. Apply if/elif/else for game logic
  3. Use random.randint() from the standard library
  4. Track attempts with a counter
  5. Use list comprehensions to analyze a history of guesses

Prerequisites

  • Module 02 lessons completed

Step 1 — Setup

mkdir ~/python-course/lab-02
cd ~/python-course/lab-02

Create guessing_game.py:

#!/usr/bin/env python3
"""
Lab 02 — Number Guessing Game
Demonstrates control flow, loops, and comprehensions.
"""

import random


def get_difficulty():
"""Let the user choose a difficulty level."""
print("\nChoose difficulty:")
print(" 1. Easy (1–50, 10 attempts)")
print(" 2. Medium (1–100, 7 attempts)")
print(" 3. Hard (1–200, 5 attempts)")

while True:
choice = input("Your choice (1/2/3): ").strip()
match choice:
case "1": return 50, 10, "Easy"
case "2": return 100, 7, "Medium"
case "3": return 200, 5, "Hard"
case _: print("Invalid choice — enter 1, 2 or 3.")


def play_game(max_number, max_attempts, difficulty):
"""Run one round of the guessing game."""
secret = random.randint(1, max_number)
guesses = []

print(f"\n{'=' * 45}")
print(f" Difficulty: {difficulty}")
print(f" Guess a number between 1 and {max_number}")
print(f" You have {max_attempts} attempts")
print(f"{'=' * 45}\n")

for attempt in range(1, max_attempts + 1):
# Get valid input
while True:
try:
guess = int(input(f"Attempt {attempt}/{max_attempts}: "))
if 1 <= guess <= max_number:
break
print(f" Please enter a number between 1 and {max_number}.")
except ValueError:
print(" Invalid input — enter an integer.")

guesses.append(guess)
distance = abs(guess - secret)

if guess == secret:
print(f"\n 🎉 Correct! The number was {secret}!")
return True, guesses, attempt

# Hint based on distance
if distance <= 5:
hint = "🔥 Very hot!"
elif distance <= 15:
hint = "♨️ Hot!"
elif distance <= 30:
hint = "🌤 Warm"
else:
hint = "❄️ Cold"

direction = "higher" if guess < secret else "lower"
print(f" {hint} Go {direction}. {max_attempts - attempt} attempts left.")

print(f"\n 💀 Game Over! The number was {secret}.")
return False, guesses, max_attempts


def analyze_guesses(guesses, secret):
"""Use comprehensions to analyze guess history."""
too_low = [g for g in guesses if g < secret]
too_high = [g for g in guesses if g > secret]
distances = [abs(g - secret) for g in guesses]

print(f"\n 📊 Analysis:")
print(f" Guesses : {guesses}")
print(f" Too low : {too_low}")
print(f" Too high: {too_high}")
if distances:
print(f" Best guess distance: {min(distances)}")
print(f" Average distance : {sum(distances) / len(distances):.1f}")


def show_score(wins, losses):
"""Display win/loss statistics."""
total = wins + losses
rate = (wins / total * 100) if total > 0 else 0
print(f"\n 🏆 Score: {wins}W / {losses}L ({rate:.0f}% win rate)")


def main():
"""Main game loop."""
print("=" * 45)
print(f"{'🎮 NUMBER GUESSING GAME':^45}")
print("=" * 45)

wins, losses = 0, 0
secret_tracker = []

while True:
max_num, max_att, difficulty = get_difficulty()
won, guesses, attempts = play_game(max_num, max_att, difficulty)

secret = None
for g in guesses:
if g == guesses[-1] and won:
secret = g
if not won:
secret = None

if won:
wins += 1
print(f" ✅ Won in {attempts} attempt(s)!")
else:
losses += 1

analyze_guesses(guesses, guesses[-1] if won else -1)
show_score(wins, losses)

again = input("\n Play again? (y/n): ").strip().lower()
if again != "y":
break

print("\n Thanks for playing! 👋")


if __name__ == "__main__":
main()

Step 2 — Run the Game

python3 guessing_game.py

Verification ✅

=============================================
🎮 NUMBER GUESSING GAME
=============================================

Choose difficulty:
1. Easy (1–50, 10 attempts)
2. Medium (1–100, 7 attempts)
3. Hard (1–200, 5 attempts)
Your choice (1/2/3): 1

=============================================
Difficulty: Easy
Guess a number between 1 and 50
You have 10 attempts
=============================================

Attempt 1/10: 25
🌤 Warm Go higher. 9 attempts left.
Attempt 2/10: 37
♨️ Hot! Go lower. 8 attempts left.
Attempt 3/10: 31

🎉 Correct! The number was 31!
✅ Won in 3 attempt(s)!

📊 Analysis:
Guesses : [25, 37, 31]
Too low : [25]
Too high: [37]
Best guess distance: 0
Average distance : 5.3

Bonus Challenge

Add a leaderboard that persists across games:

  1. Store (difficulty, attempts, timestamp) for each win
  2. At the end, show the top 3 fastest wins using a list comprehension with sorted
  3. Use datetime.now() from the standard library
from datetime import datetime

leaderboard = []
# After a win:
leaderboard.append((difficulty, attempts, datetime.now().strftime("%H:%M:%S")))

# Show top 3
top3 = sorted(leaderboard, key=lambda x: x[1])[:3]
for rank, (diff, att, time) in enumerate(top3, 1):
print(f" #{rank}: {diff} in {att} attempts at {time}")

Cleanup

No cleanup required — local script only.


Summary

In this lab you applied:

  • while True + break for the main game loop
  • match/case for difficulty selection
  • for loop with range() for the attempt counter
  • try/except ValueError for input validation
  • List comprehensions to analyze the guess history (too_low, too_high, distances)
  • min(), sum(), len() with lists built by comprehensions