بلک‌جک

بلک‌جک

تمرین یادگیری

مقدمه

Case (که در زبان‌های دیگر اغلب به آن switch می‌گویند) گونه‌ای از عبارت کنترلی است، مانند if-else. Case امکان زنجیره‌کردن چندین دستور if-else-if را می‌دهد و در عین حال که کنترل جریان را فراهم می‌کند، می‌تواند خواناتر باشد.

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

ابتدا عبارت case ارزیابی می‌شود و سپس با هر یک از عبارت‌های when مقایسه می‌شود. این مقایسه با عملگر تساوی case (===) انجام می‌شود.

value = 1
case value
when 1
  "One"
when 2
  "Two"
else
  "Other"
end

# This is the same as:
value = 1
if 1 === value
  "One"
elsif 2 === value
  "Two"
else
  "Other"
end

عملگر تساوی case (===)

عملگر تساوی case (===) کمی با عملگر برابری (==) تفاوت دارد. این عملگر بررسی می‌کند که آیا سمت راست عضوی از مجموعه‌ای است که سمت چپ توصیف می‌کند. یعنی جای هر عملوند اهمیت دارد. نحوه‌ی کار آن به نوع سمت چپ بستگی دارد؛ برای مثال، Range بررسی می‌کند که آیا سمت راست درون آن بازه قرار دارد و Object بررسی می‌کند که آیا سمت راست نمونه‌ای از Object است.

(1..3) == 1  # => false
(1..3) === 1 # => true

String == "foo"  # => false
String === "foo" # => true

Case با چند عبارت

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

case var
when 1, 2
  "One or two"
else
  "Other"
end

Case با بازه‌ها

Case می‌تواند بررسی کند که آیا یک مقدار در یک بازه قرار دارد. این کار با قرار دادن یک بازه به عنوان عبارت when انجام می‌شود.

case var
when 1..3
  puts "One to three"
else
  puts "Other"
end

Case بدون عبارت case

وقتی نیازی به عبارت case نباشد، می‌توان آن را حذف کرد. با این کار هر عبارت case از نظر درست بودن ارزیابی می‌شود. و باعث می‌شود مانند دستورهای if-else-if رفتار کنند.

case
when 1 == 1
  "One is equal to one"
when 1 > 2
  "One is greater than two"
else
  "Other"
end

when تک‌خطی

Ruby امکان نوشتن دستورهای case در یک خط را فراهم می‌کند. این زمانی به کار می‌آید که یک دستور ساده‌ی تک‌خطی دارید. دستور when تک‌خطی به شکل when <expression> then <statement> نوشته می‌شود. و اگر در دستور else به کار برود، به شکل else <statement> نوشته می‌شود.

case var
when 1 then "One"
when 2 then "Two"
else "Other"
end

Case با نوع‌ها

Case امکان مطابقت با نوع‌ها را هم می‌دهد. این زمانی مفید است که بخواهید بسته به نوع یک متغیر رفتار متفاوتی داشته باشید.

case var
when Integer
  "Integer"
when String
  "String"
else
  "Other"
end

دستورالعمل‌ها

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

1. محاسبه‌ی ارزش هر کارت داده‌شده.

شما دو کارت دریافت می‌کنید و می‌توانید کارت روی‌شده‌ی دیلر را ببینید. همه‌ی کارت‌ها با رشته‌ای مانند «ace»، «king»، «three»، «two» و غیره نمایش داده می‌شوند. ارزش هر کارت از این قرار است:

کارت ارزش کارت ارزش
ace 11 eight 8
two 2 nine 9
three 3 ten 10
four 4 jack 10
five 5 queen 10
six 6 king 10
seven 7 other 0
Note

معمولاً کارت‌های «ace» می‌توانند ارزش ۱ یا ۱۱ داشته باشند، اما برای سادگی فرض می‌کنیم که تنها ارزش ۱۱ را می‌گیرند.

متد Blackjack.parse_card را پیاده‌سازی کنید که یک کارت را به‌صورت رشته به عنوان ورودی می‌گیرد. این متد باید ارزش کارت را به‌صورت یک عدد صحیح برگرداند.

Blackjack.parse_card("ace")
# => 11

2. نام‌گذاری بازه‌های ارزش.

امتیاز بازیکن باید در قالب بازه‌هایی از ارزش‌ها دسته‌بندی شود. امتیاز بازیکن با جمع زدن ارزش دو کارت بازیکن به دست می‌آید. بازه‌هایی که به کار می‌روند عبارت‌اند از:

بازه ارزش
low [۴، ۱۱]
mid [۱۲، ۱۶]
high [۱۷، ۲۰]
blackjack [۲۱]

متد Blackjack.card_range را پیاده‌سازی کنید که دو کارت را به‌صورت رشته به عنوان ورودی می‌گیرد. این متد باید نام بازه‌ای را برگرداند که دو کارت در آن قرار می‌گیرند.

Blackjack.card_range("ten", "king")
# => "high"

3. پیاده‌سازی منطق تصمیم‌گیری برای دور اول.

بسته به دو کارت شما و کارت دیلر، برای دور اول بازی استراتژی‌ای وجود دارد که در آن این گزینه‌ها را دارید:

  • ایستادن (S)
  • کارت گرفتن (H)
  • تقسیم کردن (P)
  • برد خودکار (W)

هرچند هنوز بهینه نیست، اما استراتژی‌ای را دنبال می‌کنید که دوستتان الکس در حال توسعه‌ی آن بوده است؛ این استراتژی از این قرار است:

  • اگر جفت شما از دو کارت «ace» تشکیل شده باشد، باید همیشه آن‌ها را تقسیم کنید.
  • اگر بلک‌جک داشته باشید (دو کارتی که مجموعشان ۲۱ می‌شود) و دیلر «ace»، کارت تصویری یا «ten» نداشته باشد، به‌طور خودکار برنده می‌شوید. اگر دیلر هر یک از این کارت‌ها را داشته باشد، باید بایستید و منتظر بمانید تا کارت دیگر رو شود.
  • اگر مجموع کارت‌هایتان در بازه‌ی [۱۷، ۲۰] باشد، باید همیشه بایستید.
  • اگر مجموع کارت‌هایتان در بازه‌ی [۱۲، ۱۶] باشد، باید همیشه بایستید، مگر اینکه دیلر ۷ یا بالاتر داشته باشد؛ در این صورت باید همیشه کارت بگیرید.
  • اگر مجموع کارت‌هایتان ۱۱ یا کمتر باشد، باید همیشه کارت بگیرید.

متد Blackjack.first_turn را پیاده‌سازی کنید که سه کارت را به‌صورت رشته به عنوان ورودی می‌گیرد. این متد باید تصمیمی را که باید بگیرید به‌صورت رشته برگرداند.

Blackjack.first_turn("ace", "ace", "two")
# => "P"
ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
Ruby Exercism

آماده‌اید بلک‌جک را شروع کنید؟

در Exercism ثبت‌نام کنید تا Ruby را همراه با 21 مفهوم121 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.