تمرین و پروژه‌های پایتون

ساخت بازی حدس عدد با پایتون؛ پروژه کامل با سطح سختی و امتیازدهی

ساخت بازی حدس عدد با پایتون

🗓 آخرین به‌روزرسانی:

بازی حدس عدد یکی از بهترین پروژه‌های شروع برنامه‌نویسی با پایتون است؛ چون در یک برنامه کوچک، چند مفهوم پایه و مهم را کنار هم قرار می‌دهد: دریافت ورودی از کاربر، شرط‌ها، حلقه‌ها، تولید عدد تصادفی، تبدیل نوع داده و مدیریت ورودی نامعتبر. در این آموزش قرار نیست فقط یک نمونه چندخطی بسازیم. هدف، ساخت یک بازی کامل و قابل اجراست که سطح سختی داشته باشد، تعداد تلاش‌ها را محدود کند، به کاربر بگوید حدس او بزرگ‌تر یا کوچک‌تر از عدد مخفی است و در پایان امکان بازی دوباره بدهد.

اگر با تابع input در پایتون، شرط‌های if، elif و else و حلقه while آشنا هستید، این پروژه فرصت خوبی است تا آن مفاهیم را در یک مسئله واقعی کنار هم استفاده کنید. اگر هنوز در یکی از این بخش‌ها ضعف دارید، می‌توانید هم‌زمان با ساخت پروژه به آموزش مربوط مراجعه کنید و دوباره به همین صفحه برگردید.

در این پروژه چه چیزی می‌سازیم؟

برنامه‌ای می‌سازیم که در شروع از کاربر سطح بازی را می‌پرسد. هر سطح، بازه عددی و تعداد تلاش متفاوتی دارد. سپس کامپیوتر با کمک ماژول random یک عدد مخفی انتخاب می‌کند. کاربر باید آن عدد را حدس بزند. بعد از هر حدس، برنامه اعلام می‌کند که باید عدد بزرگ‌تری یا کوچک‌تری وارد شود. بازی تا زمانی ادامه پیدا می‌کند که کاربر عدد را پیدا کند یا تعداد تلاش‌های او تمام شود.

  • سطح آسان: عددی بین ۱ تا ۵۰ با ۱۰ تلاش
  • سطح متوسط: عددی بین ۱ تا ۱۰۰ با ۸ تلاش
  • سطح سخت: عددی بین ۱ تا ۲۰۰ با ۷ تلاش
  • کنترل ورودی نامعتبر و جلوگیری از توقف برنامه
  • نمایش تعداد تلاش باقی‌مانده
  • امکان شروع دوباره بازی پس از پایان هر دور

پیش‌نیازهای پروژه

برای اجرای این پروژه فقط به Python نیاز دارید و هیچ کتابخانه خارجی نصب نمی‌شود. ماژول random همراه خود پایتون ارائه می‌شود. بنابراین بعد از ساخت یک فایل با پسوند .py می‌توانید برنامه را مستقیماً اجرا کنید.

برای مثال فایلی با نام زیر بسازید:

guess_number.py

سپس آن را از ترمینال یا محیط توسعه خود اجرا کنید:

python guess_number.py

مرحله اول: تولید عدد تصادفی

در نسخه‌های خیلی ساده بازی حدس عدد، معمولاً یک عدد ثابت مثل ۷ داخل برنامه قرار داده می‌شود. این روش برای توضیح حلقه مناسب است، اما برای ساخت یک بازی واقعی کافی نیست. اگر عدد ثابت باشد، کاربر بعد از یک بار بازی پاسخ را می‌داند. به همین دلیل از random.randint() استفاده می‌کنیم.

import random

secret_number = random.randint(1, 100)

تابع randint(1, 100) یک عدد صحیح تصادفی در بازه ۱ تا ۱۰۰ تولید می‌کند. هر دو مرز بازه نیز می‌توانند انتخاب شوند؛ یعنی ۱ و ۱۰۰ هم جزو جواب‌های ممکن هستند.

مرحله دوم: دریافت حدس کاربر

ورودی input() همیشه به‌صورت رشته برمی‌گردد. برای مقایسه آن با عدد مخفی باید رشته را به عدد صحیح تبدیل کنیم.

guess = int(input("حدس شما: "))

این کد در حالت عادی کار می‌کند، اما یک مشکل مهم دارد. اگر کاربر به‌جای عدد عبارتی مثل hello وارد کند، تبدیل به int ممکن نیست و برنامه با ValueError متوقف می‌شود. در پروژه نهایی این وضعیت را مدیریت می‌کنیم تا یک ورودی اشتباه کل بازی را خراب نکند.

مرحله سوم: مقایسه حدس با عدد مخفی

هسته اصلی بازی سه حالت دارد: حدس کوچک‌تر از پاسخ است، بزرگ‌تر از پاسخ است یا دقیقاً برابر با آن است.

if guess < secret_number:
    print("بالاتر حدس بزن.")
elif guess > secret_number:
    print("پایین‌تر حدس بزن.")
else:
    print("درست حدس زدی!")

همین منطق ساده باعث می‌شود کاربر در هر مرحله بازه جست‌وجوی خود را کوچک‌تر کند. از نظر آموزشی، این بخش تمرین خوبی برای مقایسه عددی و زنجیره شرط‌هاست.

مرحله چهارم: محدود کردن تعداد تلاش‌ها

اگر تعداد تلاش‌ها نامحدود باشد، بازیکن بالاخره پاسخ را پیدا می‌کند. برای ایجاد چالش، تعداد فرصت‌ها را محدود می‌کنیم. متغیر attempts_left تعداد تلاش باقی‌مانده را نگه می‌دارد.

attempts_left = 8

while attempts_left > 0:
    # دریافت و بررسی حدس
    attempts_left -= 1

هر بار که کاربر یک حدس معتبر وارد می‌کند، یک واحد از فرصت‌ها کم می‌شود. نکته مهم این است که ورودی نامعتبر را نباید تلاش واقعی محسوب کنیم. بنابراین کاهش شمارنده باید بعد از اعتبارسنجی ورودی انجام شود.

مرحله پنجم: اضافه کردن سطح سختی

برای اینکه بازی فقط یک حالت نداشته باشد، مشخصات هر سطح را در یک دیکشنری قرار می‌دهیم. این روش از چندین شرط تکراری جلوگیری می‌کند و بعداً اضافه کردن سطح جدید را ساده‌تر می‌سازد.

levels = {
    "1": {"name": "آسان", "max_number": 50, "attempts": 10},
    "2": {"name": "متوسط", "max_number": 100, "attempts": 8},
    "3": {"name": "سخت", "max_number": 200, "attempts": 7},
}

برای هر سطح سه داده نگه می‌داریم: نام سطح، بزرگ‌ترین عدد ممکن و تعداد تلاش مجاز. وقتی کاربر گزینه ۱، ۲ یا ۳ را انتخاب کند، برنامه تنظیمات همان سطح را دریافت می‌کند.

ساخت تابع انتخاب سطح

def choose_level():
    levels = {
        "1": {"name": "آسان", "max_number": 50, "attempts": 10},
        "2": {"name": "متوسط", "max_number": 100, "attempts": 8},
        "3": {"name": "سخت", "max_number": 200, "attempts": 7},
    }

    while True:
        print("\nسطح بازی را انتخاب کنید:")
        print("1) آسان")
        print("2) متوسط")
        print("3) سخت")

        choice = input("انتخاب شما: ").strip()

        if choice in levels:
            return levels[choice]

        print("گزینه نامعتبر است. فقط 1، 2 یا 3 را وارد کنید.")

حلقه while True در اینجا عمداً استفاده شده است. تا زمانی که کاربر یکی از گزینه‌های معتبر را وارد نکند، تابع پایان پیدا نمی‌کند. به محض انتخاب درست، دستور return اطلاعات سطح را برمی‌گرداند.

اعتبارسنجی حدس کاربر

یک بازی قابل اعتماد باید ورودی اشتباه را مدیریت کند. همچنین اگر بازه بازی ۱ تا ۱۰۰ باشد، وارد کردن عدد ۸۰۰ نباید به‌عنوان یک تلاش منطقی پذیرفته شود.

def get_guess(max_number):
    while True:
        value = input(f"یک عدد بین 1 تا {max_number} وارد کنید: ").strip()

        try:
            guess = int(value)
        except ValueError:
            print("ورودی باید یک عدد صحیح باشد.")
            continue

        if 1 <= guess <= max_number:
            return guess

        print(f"عدد باید بین 1 تا {max_number} باشد.")

بلوک try/except جلوی توقف برنامه را در زمان وارد کردن متن یا مقدار غیرقابل تبدیل می‌گیرد. بعد از تبدیل موفق، بازه عدد نیز بررسی می‌شود.

تابع اصلی اجرای یک دور بازی

def play_game():
    level = choose_level()

    max_number = level["max_number"]
    attempts_left = level["attempts"]
    secret_number = random.randint(1, max_number)

    print(
        f"\nسطح {level['name']} شروع شد. "
        f"عدد مخفی بین 1 تا {max_number} است."
    )

    while attempts_left > 0:
        print(f"\nتلاش باقی‌مانده: {attempts_left}")
        guess = get_guess(max_number)

        if guess == secret_number:
            used_attempts = level["attempts"] - attempts_left + 1
            print(
                f"آفرین! عدد {secret_number} را "
                f"در {used_attempts} تلاش پیدا کردی."
            )
            return

        attempts_left -= 1

        if guess < secret_number:
            print("عدد مخفی بزرگ‌تر است.")
        else:
            print("عدد مخفی کوچک‌تر است.")

    print(f"\nفرصت‌ها تمام شد. عدد مخفی {secret_number} بود.")

این تابع تمام اجزای اصلی بازی را کنار هم قرار می‌دهد. ابتدا سطح دریافت می‌شود، سپس عدد تصادفی ساخته می‌شود. در هر دور حلقه، حدس کاربر گرفته و با پاسخ مقایسه می‌شود. اگر جواب صحیح باشد، با return همان دور بازی پایان می‌یابد. اگر فرصت‌ها تمام شوند، پاسخ صحیح نمایش داده می‌شود.

اضافه کردن امکان بازی مجدد

بهتر است بعد از پایان هر دور مجبور نباشیم فایل را دوباره اجرا کنیم. یک حلقه دیگر می‌تواند کنترل اجرای کل بازی را بر عهده بگیرد.

def main():
    print("=== بازی حدس عدد با پایتون ===")

    while True:
        play_game()

        again = input("\nدوباره بازی می‌کنی؟ (y/n): ").strip().lower()

        if again not in ("y", "yes"):
            print("بازی تمام شد. موفق باشی!")
            break

با استفاده از strip() فاصله‌های اضافی ابتدا و انتهای ورودی حذف می‌شوند و lower() حروف انگلیسی بزرگ را به کوچک تبدیل می‌کند. بنابراین Y و y یک رفتار خواهند داشت.

کد کامل بازی حدس عدد با پایتون

حالا تمام بخش‌ها را در یک فایل قرار می‌دهیم. این نسخه مستقل است و برای اجرا به نصب پکیج خارجی نیاز ندارد.

import random


def choose_level():
    levels = {
        "1": {"name": "آسان", "max_number": 50, "attempts": 10},
        "2": {"name": "متوسط", "max_number": 100, "attempts": 8},
        "3": {"name": "سخت", "max_number": 200, "attempts": 7},
    }

    while True:
        print("\nسطح بازی را انتخاب کنید:")
        print("1) آسان - عدد 1 تا 50 - ده تلاش")
        print("2) متوسط - عدد 1 تا 100 - هشت تلاش")
        print("3) سخت - عدد 1 تا 200 - هفت تلاش")

        choice = input("انتخاب شما: ").strip()

        if choice in levels:
            return levels[choice]

        print("گزینه نامعتبر است. فقط 1، 2 یا 3 را وارد کنید.")


def get_guess(max_number):
    while True:
        value = input(
            f"یک عدد بین 1 تا {max_number} وارد کنید: "
        ).strip()

        try:
            guess = int(value)
        except ValueError:
            print("ورودی باید یک عدد صحیح باشد.")
            continue

        if 1 <= guess <= max_number:
            return guess

        print(f"عدد باید بین 1 تا {max_number} باشد.")


def play_game():
    level = choose_level()

    max_number = level["max_number"]
    attempts_left = level["attempts"]
    secret_number = random.randint(1, max_number)

    print(
        f"\nسطح {level['name']} شروع شد. "
        f"عدد مخفی بین 1 تا {max_number} است."
    )

    while attempts_left > 0:
        print(f"\nتلاش باقی‌مانده: {attempts_left}")
        guess = get_guess(max_number)

        if guess == secret_number:
            used_attempts = level["attempts"] - attempts_left + 1
            print(
                f"آفرین! عدد {secret_number} را "
                f"در {used_attempts} تلاش پیدا کردی."
            )
            return

        attempts_left -= 1

        if guess < secret_number:
            print("عدد مخفی بزرگ‌تر است.")
        else:
            print("عدد مخفی کوچک‌تر است.")

    print(f"\nفرصت‌ها تمام شد. عدد مخفی {secret_number} بود.")


def main():
    print("=== بازی حدس عدد با پایتون ===")

    while True:
        play_game()

        again = input(
            "\nدوباره بازی می‌کنی؟ (y/n): "
        ).strip().lower()

        if again not in ("y", "yes"):
            print("بازی تمام شد. موفق باشی!")
            break


if __name__ == "__main__":
    main()

چرا از if __name__ == “__main__” استفاده کردیم؟

این شرط باعث می‌شود تابع main() فقط زمانی اجرا شود که فایل را مستقیماً اجرا کرده باشید. اگر در آینده بخواهید توابع همین فایل را داخل پروژه دیگری import کنید، بازی به‌صورت ناخواسته شروع نمی‌شود. برای یک پروژه کوچک الزام مطلق نیست، اما استفاده از آن عادت خوبی برای ساخت برنامه‌های منظم‌تر است.

نمونه اجرای برنامه

=== بازی حدس عدد با پایتون ===

سطح بازی را انتخاب کنید:
1) آسان - عدد 1 تا 50 - ده تلاش
2) متوسط - عدد 1 تا 100 - هشت تلاش
3) سخت - عدد 1 تا 200 - هفت تلاش
انتخاب شما: 2

سطح متوسط شروع شد. عدد مخفی بین 1 تا 100 است.

تلاش باقی‌مانده: 8
یک عدد بین 1 تا 100 وارد کنید: 50
عدد مخفی بزرگ‌تر است.

تلاش باقی‌مانده: 7
یک عدد بین 1 تا 100 وارد کنید: 75
عدد مخفی کوچک‌تر است.

تلاش باقی‌مانده: 6
یک عدد بین 1 تا 100 وارد کنید: 64
آفرین! عدد 64 را در 3 تلاش پیدا کردی.

منطق پیدا کردن عدد را بهتر کنیم

این بازی علاوه بر تمرین برنامه‌نویسی، یک نکته الگوریتمی هم دارد. اگر بازه ۱ تا ۱۰۰ باشد، حدس تصادفی روش خوبی نیست. بهتر است همیشه نزدیک وسط بازه باقی‌مانده حدس بزنید. برای مثال ابتدا ۵۰ را امتحان کنید. اگر برنامه بگوید عدد بزرگ‌تر است، بازه شما به ۵۱ تا ۱۰۰ محدود می‌شود. حدس بعدی می‌تواند حدود ۷۵ باشد. این روش ذهنیت جست‌وجوی دودویی را تمرین می‌دهد، حتی اگر خود الگوریتم Binary Search را هنوز پیاده‌سازی نکرده باشید.

اشتباه‌های رایج هنگام ساخت پروژه

کم نکردن تعداد تلاش‌ها

اگر متغیر تلاش‌ها داخل حلقه کاهش پیدا نکند، حلقه ممکن است تا همیشه ادامه پیدا کند. محل کاهش تلاش نیز مهم است؛ بهتر است فقط بعد از دریافت یک حدس معتبر شمارنده را کم کنید.

مقایسه رشته با عدد

خروجی input() رشته است. مقایسه مستقیم آن با عدد مخفی صحیح نیست. ابتدا باید آن را با int() تبدیل کنید و خطای تبدیل را هم مدیریت کنید.

تولید دوباره عدد مخفی داخل حلقه

عدد تصادفی باید قبل از حلقه حدس تولید شود. اگر random.randint() را داخل حلقه قرار دهید، پاسخ در هر تلاش تغییر می‌کند و عملاً بازی قابل حل نخواهد بود.

پذیرفتن اعداد خارج از بازه

وقتی کاربر سطح متوسط را انتخاب کرده و بازه ۱ تا ۱۰۰ است، عددی مثل ۵۰۰ نباید یک حدس معتبر باشد. اعتبارسنجی بازه هم تجربه کاربر را بهتر می‌کند و هم منطق برنامه را شفاف نگه می‌دارد.

تمرین‌های توسعه پروژه

نسخه فعلی کامل و قابل اجراست، اما ارزش اصلی پروژه زمانی بیشتر می‌شود که خودتان قابلیت‌های جدید به آن اضافه کنید. این تمرین‌ها را به ترتیب انجام دهید:

  1. سیستم امتیاز: هرچه کاربر با تلاش کمتری پاسخ را پیدا کرد امتیاز بیشتری دریافت کند.
  2. بهترین رکورد: کمترین تعداد تلاش را در طول اجرای برنامه نگه دارید.
  3. ذخیره رکورد در فایل: بهترین امتیاز را در یک فایل متنی یا JSON ذخیره کنید تا بعد از بستن برنامه هم باقی بماند.
  4. راهنمای فاصله: به‌جای فقط بزرگ‌تر/کوچک‌تر، مشخص کنید کاربر خیلی نزدیک، نزدیک یا دور است.
  5. سطح سفارشی: اجازه دهید کاربر بیشترین عدد و تعداد تلاش‌ها را خودش تعیین کند.
  6. حالت دو نفره: نفر اول عددی تعیین کند و نفر دوم آن را حدس بزند.
  7. نسخه گرافیکی: همین منطق را بعداً با Tkinter به یک بازی پنجره‌ای تبدیل کنید.

نسخه چالشی: پیام نزدیک یا دور

یکی از توسعه‌های ساده این است که فاصله حدس با عدد مخفی را محاسبه کنیم:

distance = abs(secret_number - guess)

if distance <= 5:
    print("خیلی نزدیک شدی!")
elif distance <= 15:
    print("نزدیکی.")
else:
    print("هنوز فاصله زیادی داری.")

تابع abs() قدر مطلق اختلاف را برمی‌گرداند. بنابراین مهم نیست حدس بالاتر یا پایین‌تر از عدد مخفی باشد؛ فقط فاصله عددی اندازه‌گیری می‌شود.

این پروژه چه مفاهیمی از پایتون را تمرین می‌دهد؟

بازی حدس عدد در ظاهر ساده است، اما بخش قابل توجهی از مبانی برنامه‌نویسی را به شکل عملی ترکیب می‌کند:

  • تعریف و استفاده از متغیرها
  • دریافت ورودی با input()
  • تبدیل رشته به عدد صحیح
  • مقایسه اعداد
  • شرط‌های چندشاخه
  • حلقه‌های while
  • استفاده از دیکشنری برای تنظیمات
  • تعریف و فراخوانی تابع
  • مدیریت خطا با try/except
  • استفاده از ماژول استاندارد random
  • تقسیم یک مسئله به چند تابع کوچک

به همین دلیل این پروژه بهتر است بعد از یادگیری مبانی انجام شود، نه اینکه فقط کد نهایی آن کپی شود. سعی کنید ابتدا نسخه ساده را خودتان بنویسید، سپس قابلیت سطح سختی و اعتبارسنجی را اضافه کنید و در پایان کد خود را با نسخه کامل مقایسه کنید.

جمع‌بندی

در این آموزش یک بازی حدس عدد واقعی با پایتون ساختیم که برخلاف نمونه‌های چندخطی، عدد تصادفی تولید می‌کند، سه سطح دشواری دارد، تعداد تلاش‌ها را کنترل می‌کند، ورودی اشتباه را مدیریت می‌کند و امکان اجرای دوباره بازی را می‌دهد. این ساختار نشان می‌دهد چگونه می‌توان چند مفهوم پایه پایتون را از حالت تمرین‌های جداگانه خارج کرد و در یک پروژه منسجم به کار برد.

قبل از رفتن سراغ پروژه بعدی، پیشنهاد می‌شود حداقل یکی از قابلیت‌های بخش «تمرین‌های توسعه پروژه» را بدون نگاه کردن به پاسخ آماده پیاده‌سازی کنید. هدف این مجموعه فقط اجرای کد نیست؛ باید بتوانید منطق پروژه را تغییر دهید، خطاهای آن را پیدا کنید و ویژگی جدید به آن اضافه کنید.

📌 همچنین بخوانید: تمرین پایتون با جواب، ساخت بازی با پایتون و Pygame و ساخت ربات با پایتون

می‌خواهی پیشرفتت ذخیره شود؟با ورود یا ثبت‌نام رایگان، درس‌های تمام‌شده را علامت بزن و درصد پیشرفتت را در حساب کاربری ببین.ورود / ثبت‌نام برای ذخیره پیشرفت
درس بعدی · پروژه‌های پایتون (2 از 19)ساخت بازی سنگ کاغذ قیچی با پایتون؛ پروژه کامل با امتیازدهی ←
آموزش‌های تازه، کد آماده و رفع خطاهر هفته در کانال Dev Source؛ رایگان.
🧭 مسیر یادگیری پایتون از صفر
ماژول 3: شرط و حلقه — درس 13 از 44

برای ذخیره پیشرفت در همه دستگاه‌ها و دریافت گواهی پایان مسیر، رایگان ثبت‌نام کن یا وارد شو.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *