بلک‌جک

بلک‌جک

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

مقدمه

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

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

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

case 1
when 1
  puts "One"
when 2
  puts "Two"
else
  puts "Other"
end
# => One

# This is the same as:
tmp = 1
if 1 === tmp
  puts "One"
elsif 2 === tmp
  puts "Two"
else
  puts "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 1
when 1, 2
  puts "One or two"
else
  puts "Other"
end

case با بازه‌ها

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

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

case بدون عبارت case

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

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

when تک‌خطی

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

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

case با نوع‌ها

case امکان مطابقت با نوع‌ها را فراهم می‌کند. مقایسه از عملگر is_a? برای بررسی نوع متغیر استفاده می‌کند. برای نمونه، این امکان می‌دهد که در یک نوع union برای هر نوع یک شاخه داشته باشیم.

case var
when Int32
  puts "Int32"
when String
  puts "String"
else
  puts "Other"
end

شیء ضمنی

case امکان استفاده از یک شیء ضمنی را فراهم می‌کند. برای نمونه، این می‌تواند باعث شود یک عبارت when یک فراخوانی متد روی عبارت case باشد. بسته به اینکه متد مقداری «درست» یا «غلط» برگرداند، case مطابقت داده می‌شود یا نه.

case 1
when .odd?
  puts "Odd"
when .even?
  puts "Even"
end

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

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

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

شما دو کارت دریافت می‌کنید و می‌توانید کارت رو‌شده‌ی پخش‌کننده را ببینید. همه‌ی کارت‌ها با یک رشته نمایش داده می‌شوند؛ مثل ace، king، three، two و غیره. ارزش هر کارت به این صورت است:

کارت ارزش کارت ارزش
ace ۱۱ eight ۸
two ۲ nine ۹
three ۳ ten ۱۰
four ۴ jack ۱۰
five ۵ queen ۱۰
six ۶ king ۱۰
seven ۷ other ۰
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 این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
Crystal Exercism

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

در Exercism ثبت‌نام کنید تا Crystal را همراه با 26 مفهوم142 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.