تبلیغات

آموزش ساخت بازی سنگ کاغذ قیچی ساده در پایتون

آموزش ساخت بازی سنگ کاغذ قیچی ساده در پایتون

سنگ-کاغذ-قیچی، یکی از نوستالژی‌ترین بازی‌هاییست که تقریبا همه‌ی ما در دوران بچگی آن را تجربه کرده و حتی گاهی برای موارد مختلف در زندگیمان، آن را انجام می‌دهیم. مثلا دو دوست که کاری را به یکدیگر محول می‌کنند؛ اما در نهایت با یک بازی ساده، هرکس که ببازد، آن کار را انجام می‌دهد. 😀 (بسوزه پدر تجربه)

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

فرضیه

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

حالا بیایید شروع کنیم.

منطق کلی بازی

کد زیر را در نظر بگیرید تا در ادامه، توضیحات لازم داده شود: (بخش‌های مختلف توسط کامنت، جهت توضیح شماره‌گذاری شده‌اند)

#1
print("")
print("Let's play a Rock-Paper-Scissors Game...")
print("To left the game, just send exit or e")
print("")

while True: #2
    player = input('Rock Paper Scissors? ') #3
    player = optimizeChoice(player) #4

    #5
    if player == 'exit':
        break
    
    #6
    if not validateInput(player):
        print('Your choice is not valid!!!!!')
        continue

    #7
    computer = generateComputerChoince()
    print(f"I choiced {computer}")

    #8
    winner = getWinner(player, computer);
    
    #9
    if winner == WINNER_PLAYER:
        print("Congratulation... You Win!!!!!")
    elif winner == WINNER_COMPUTER:
        print("Sorry... You lost!!!!!")
    elif winner == WINNER_TIE:
        print("Ops... That's a Tie!!!!!")
    else:
        print("Erro 404 Winner NOT Found!!!!")

    #10
    print("")
    print("Let's play again...")
    print("")

#11
print('Bye... See ya later!!!!!')
  1. ابتدا پیام‌های خوش‌آمدگویی و راهنما نمایش داده شده است.
  2. یک حلقه‌ی بی‌نهایت نوشته شده است.
  3. توسط  تابع input، یک پیام نمایش داده شده و از کاربر درخواست ورودی شده است. این ورودی بایستی انتخاب کاربر باشد؛ که آن را در متغیر player قرار می‌دهیم.
  4. توسط تابع optimizeChoice که بعدا آن را می‌نویسیم، ورودی کاربر بهینه شده است! یعنی چه؟! مثلا فرض کنید کاربر، انتخابش را با حروف بزرگ وارد کند؛ یا آنکه بجای rock، حرف r را وارد کند؛ لذا داخل تابع optimizeChoice، این موارد را تشخیص داده و به انتخاب متنظار با آن تبدیل می‌کنیم. بنابراین پس از بهینه‌کردن، خروجی را در همان متغیر player قرار می‌دهیم.
  5. اگر ورودی کاربر، exit باشد، از برنامه خارج خواهد شد. بنابراین حلقه شکسته می‌شود.
  6. ورودی کاربر باید اعتبارسنجی شود؛ یعنی اگر انتخاب غیرمجازی داشته باشد، از او مجددا انتخاب دیگری تقاضا شود. برای انجام این کار نیز از تابع validateInput که بعدا آن را خواهیم نوشت، استفاده شده است. در بدنه‌ی این شرط، از continue برای تکرار مجدد while استفاده شده است. همچنین توجه داشته باشید که می‌توانستیم طی یک روش دیگری، به کمک تابع optimizeChoice نیز معتبر بودن دستور را تشخیص دهیم؛ ما این کار را به‌صورت جدا انجام دادیم تا کد تمیزتری داشته باشیم.
  7. تایع generateComputerChoince نیز که بعدا آن را می‌نویسیم، یک انتخاب جدید برای کامپیوتر (که بازیکن مقابل است) برمی‌گرداند. این انتخاب به‌طور تصادفی خواهد بود.
  8. تایع getWinner نیز که آن را هم بعدا خواهیم نوشت، با دریافت انتخاب بازیکن و کامپیوتر، نتیجه برنده شدن را تشخیص می‌دهد. نتیجه می‌تواند یکی از موارد این موارد باشد: تساوی، بازیکن، کامپیوتر
  9. نتیجه‌ی بازی بررسی شده و پیام متناظر با آن نیز چاپ شده است. همچنین ثابت‌هایی مثل WINNER_PLAYER را هم بعدا تعریف خواهیم کرد که به نتایج مختلفی اشاره دارند.
  10. کاربر یا همان بازیکن، توسط یک پیامی که چاپ شده، به انجام مجدد بازی سنگ-کاغذ-قیچی فراخوانی شده است.
  11. در نهایت نیز در صورت خروج از حلقه، از کاربر خداحافظی می‌شود.

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

ثابت‌ها

ثابت‌های زیر را در نظر بگیرید:

CHOICE_ROCK      = 'rock'
CHOICE_PAPER     = 'paper'
CHOICE_SCISSORS  = 'scissors'
CHOICE_EXIT      = 'exit'
CHOICEABLES      = [CHOICE_ROCK, CHOICE_PAPER, CHOICE_SCISSORS, CHOICE_EXIT]

WINNER_UNDEFINED = -1;
WINNER_TIE       = 0
WINNER_PLAYER    = 1
WINNER_COMPUTER  = 2

این موارد را در ابتدای فایل تعریف کنید. سه مورد اول، مقادیر انتخاب‌هایی که کاربر می‌تواند انجام دهد را دربرمی‌گیرند و CHOICEABLES نیز کل این انتخاب‌ها را در یک لیست قرار داده است؛ تا بعدا از آن در هنگام اعتبارسنجی استفاده شود.

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

پیاده‌سازی optimizeChoice

تابعی که قرار است ورودی کاربر را بهینه کند. آن را به‌صورت زیر پیاده‌سازی کنید:

def optimizeChoice(choice):
    choice = choice.lower()
    if choice == 'r':
        return CHOICE_ROCK
    if choice == 'p':
        return CHOICE_PAPER
    if choice == 's':
        return CHOICE_SCISSORS
    if choice == 'e':
        return CHOICE_EXIT
    return choice

طبیعتا این بهتر است که کاربر در مقدار ورودی، بتواند انواع مختلف متن را وارد کرده و سیستم آنها را شناسایی کند. برای مثال، کاربر ممکن است در ورودی، عبارت rock را برای انتخاب سنگ بنویسید؛ اما همچنان نیز ممکن است عبارت stone را نیز بنویسید. اگر بازی بتواند این موارد را به‌طور هوشمند تشخیص دهد، طبیعتا قدرتمندتر خواهد بود. اما ما در اینجا قصد پیچیده‌کردن الگوریتم تشخیص ورودی را نداریم و فقط از آنجایی که کاربر ممکن است از حروف بزرگ نیز استفاده کند، ابتدا ورودی را به حروف کوچک تبدیل کرده و سپس برای هرکدام از انتخاب‌های ممکن، یک حرف اختصاری را نیز بررسی کرده‌ایم. لذا در کد بالا، اگر انتخاب کاربر برای مثال مقدار  r باشد، همان CHOICE_ROCK در نظر گرفته می‌شود و … در نهایت نیز این مقدار، به بیرون برگدانده می‌شود.

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

پیاده‌سازی validateInput

نوبت این است که انتخاب کاربر، اعتبارسنجی شود. بنابراین، تابع validateInput را به شکل زیر پیاده کنید:

def validateInput(choice):
    for coiceable in CHOICEABLES:
        if (choice == coiceable):
            return True
    return False

در اینجا با دریافت انتخاب کاربر، بررسی می‌شود که آیا در لیست انتخاب‌های مجاز قرار دارد یا خیر. این کار به‌سادگی توسط یک حلقه و لیست CHOICEABLES (انتخاب‌های مجاز) که قبلا در بالا تعریف کردیم، قابل انجام است.

پیاده‌‍سازی generateComputerChoince

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

from random import randint

سپس تابع خودمان را بصورت زیر پیاده کنید:

def generateComputerChoince():
    rand_int = randint(0, 2)
    if rand_int == 0:
        return CHOICE_ROCK
    elif rand_int == 1:
        return CHOICE_PAPER
    else:
        return CHOICE_SCISSORS

در ابتدا یک عدد تصادفی، بین 0 تا 2 انتخاب شده است. که در نتیجه، یا 0 یا 1 و یا 2 خواهد بود. ما نیز سه انتخاب داریم (سنگ-کاغذ-قیچی). سپس فرض شده است که اگر مقدار عدد تصادفی، برابر 0 بود، انتخاب کامپیوتر سنگ باشد و اگر 1 بود، انتخاب کامپیوتر کاغذ باشد و اگر هیچکدام از اینها نبود، انتخاب کامپیوتر نیز قیچی باشد.

پیاده‌سازی getWinner

این متد نیز با دریافت انتخا‌ب‌ها، برنده را تشخیص می‌دهد. آن را بصورت زیر پیاده کنید:

def getWinner(player, computer):
    if (player == computer):
        return WINNER_TIE
    if (player == CHOICE_ROCK):
        if (computer == CHOICE_SCISSORS):
            return WINNER_PLAYER
        else:
            return WINNER_COMPUTER
    if (player == CHOICE_PAPER):
        if (computer == CHOICE_ROCK):
            return WINNER_PLAYER
        else:
            return WINNER_COMPUTER
    if (player == CHOICE_SCISSORS):
        if (computer == CHOICE_PAPER):
            return WINNER_PLAYER
        else:
            return WINNER_COMPUTER
    return WINNER_UNDEFINED

در ابتدا بررسی شده است که اگر انتخاب‌ها برابر بودند، نتیجه بازی مساوی باشد. بنابراین ثابت WINNER_TIE برگردانده شده است. سپس در شروط مختلفی، انتخاب‌های کاربر با انتخاب کامپیوتر بررسی شده است. برای مثال، یکی از شروط بررسی کرده است که اگر انتخاب کاربر برابر سنگ بود، در این صورت اگر انتخاب کامپیوتر برابر قیچی بود، پس کاربر برنده است؛ وگرنه، کامپیوتر برنده است! اما چرا کامپیوتر برنده است؟! چون اگر کاربر سنگ باشد و کامپیوتر قیچی نباشد، بنابراین کامپیوتر کاغذ است و کاغذ سنگ را می‌پوشاند 😀

حالا شاید بگویید پس چرا سنگ بودن کاغذ بررس نشده! خب واضح است که برابر بودن در ابتدای تابع بررسی شده است و نیازی نیست در هرکدام از آنها مجدد بررسی شود.

در نهایت نیز اگر هیچ‌کدام درست نبودند، که البته غیر ممکن است، یک مقدار WINNER_UNDEFINED به عنوان برنده‌ی نامشخص برگردانده شده است؛ که جنبه‌ی دکور بودن داشته و طبق الگوریتمی که نوشتیم، مطمئنیم که همچین چیزی رخ نمی‌دهد. 😀

کد نهایی

حالا کد نهایی شما بایستی به شکل زیر باشد.

# Rock-Paper-Scissors Game
# Author: Hadi Akbarzadeh

from random import randint

CHOICE_ROCK      = 'rock'
CHOICE_PAPER     = 'paper'
CHOICE_SCISSORS  = 'scissors'
CHOICE_EXIT      = 'exit'
CHOICEABLES      = [CHOICE_ROCK, CHOICE_PAPER, CHOICE_SCISSORS]

WINNER_UNDEFINED = -1;
WINNER_TIE       = 0
WINNER_PLAYER    = 1
WINNER_COMPUTER  = 2

def optimizeChoice(choice):
    choice = choice.lower()
    if choice == 'r':
        return CHOICE_ROCK
    if choice == 'p':
        return CHOICE_PAPER
    if choice == 's':
        return CHOICE_SCISSORS
    if choice == 'e':
        return CHOICE_EXIT
    return choice

def validateInput(choice):
    for coiceable in CHOICEABLES:
        if (choice == coiceable):
            return True
    return False

def generateComputerChoince():
    rand_int = randint(0, 2)
    if rand_int == 0:
        return CHOICE_ROCK
    elif rand_int == 1:
        return CHOICE_PAPER
    else:
        return CHOICE_SCISSORS

def getWinner(player, computer):
    if (player == computer):
        return WINNER_TIE
    if (player == CHOICE_ROCK):
        if (computer == CHOICE_SCISSORS):
            return WINNER_PLAYER
        else:
            return WINNER_COMPUTER
    if (player == CHOICE_PAPER):
        if (computer == CHOICE_ROCK):
            return WINNER_PLAYER
        else:
            return WINNER_COMPUTER
    if (player == CHOICE_SCISSORS):
        if (computer == CHOICE_PAPER):
            return WINNER_PLAYER
        else:
            return WINNER_COMPUTER
    return WINNER_UNDEFINED

# --------------------------------------

print("")
print("Let's play a Rock-Paper-Scissors Game...")
print("To left the game, just send exit or e")
print("")

choiceMessage = 'Rock Paper Scissors? '
while True:
    player = input(choiceMessage)
    player = optimizeChoice(player)

    if player == 'e' or player == 'exit':
        break
    
    if not validateInput(player):
        print('Your choice is not valid!!!!!')
        continue

    computer = generateComputerChoince()
    print(f"I choiced {computer}")

    winner = getWinner(player, computer);
    
    if winner == WINNER_PLAYER:
        print("Congratulation... You Win!!!!!")
    elif winner == WINNER_COMPUTER:
        print("Sorry... You lost!!!!!")
    elif winner == WINNER_TIE:
        print("Ops... That's a Tie!!!!!")
    else:
        print("Erro 404 Winner NOT Found!!!!")

    print("")
    print("Let's play again...")
    print("")


print('Bye... See ya later!!!!!')

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

هادی اکبرزاده

[ مدیر فول کده ]

یه کلاسِ تعریف نشده ... فقط برای ارتباط کاری تلگرام پیام بدید ...

پاسخ دهید

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

نظرات ثبت شده 3 دیدگاه

    1. مجید مالکی کاربر مهمان گفت:

      سلام
      ممنون عالی بود خیلی کامل مفصل و کاربردی
      شاد و پیروز و امیدوار و موفق باشید

      10
    2. علیرضا کاربر مهمان گفت:

      عالی بود دمت گرم

      20
      1. هادی اکبرزاده مدیر سایت گفت:

        خواهش می‌کنم 🙂

توضیحات پیشنهادی نظرات اشتراک