تصویر آموزشی دستهٔ اجرایی کارت؛ مرتبط با موضوع نوشته

از تعریف دسته تا دستهٔ زنده

مسئله‌ای که باید حل می‌کردم

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

پیاده‌سازی در نسخهٔ فعلی

RuntimeDeck ابتدا DeckDefinition را اعتبارسنجی می‌کنه. Reset نمونه‌های تازه می‌سازد و دو فهرست DrawPile و DrawnCards را خالی می‌کنه؛ Draw کارت اول را به فهرست کارت‌های کشیده‌شده منتقل می‌کنه.

تصمیم و هزینهٔ طراحی

Draw خطا را صریح پرتاب می‌کنه، ولی TryDraw برای دستهٔ خالی false می‌دهد. این دو مسیر اجازه می‌دهند جریان عادی بازی را از نقض قرارداد برنامه جدا کنم.

مرزهای فعلی

DrawMany پیش از برداشت تعداد را بررسی می‌کنه، اما حذف از ابتدای List جابه‌جایی عناصر داره. از وجود این کد نمی‌توانم بهینه‌بودن آن برای دسته‌های خیلی بزرگ را نتیجه بگیرم.

شروع دوباره و حساب کارت‌های کشیده‌شده

فرض کن یک دست تمام شده و بازیکن گزینهٔ شروع دوباره را می‌زند. Reset در RuntimeDeck فقط فهرست کارت‌های باقی‌مانده را پر نمی‌کنه؛ DrawnCards را نیز خالی می‌کنه و از DeckDefinition نمونه‌های تازه می‌گیرد. این تفاوت مهم هست، چون کارت‌های مسابقهٔ قبلی نباید در شمارش مسابقهٔ بعد حضور داشته باشند. در عین حال، Reset خودش Shuffle را صدا نمی‌زند. ترتیب تازه از تعریف دسته می‌آید و تصمیم دربارهٔ بر زدن همچنان با فراخواننده هست؛ شروع دوباره و تصادفی‌کردن دو عملیات مستقل باقی می‌مونن.

DrawMany پیش از اولین برداشت، هم مثبت بودن مقدار و هم کافی بودن RemainingCount را بررسی می‌کنه. اگر ده کارت بخواهیم و تنها نه کارت باقی مانده باشد، این مسیر قبل از خالی کردن بخشی از دسته خطا می‌دهد. چنین رفتاری برای تقسیم کارت قابل فهم‌تر از یک دست نیمه‌کاره هست. با این حال، این پیش‌بررسی یک تراکنش عمومی نیست: DrawMany همچنان پشت سر هم Draw را اجرا می‌کنه و دربارهٔ خطای احتمالی مصرف‌کننده‌ای که بعداً کارت‌ها را به دست بازیکن اضافه می‌کنه مسئولیتی نداره.

نام DrawnCards ممکنه خواننده را به اشتباه بیندازد: این مجموعه تاریخچهٔ خروج کارت از دسته هست، نه جای فعلی همهٔ کارت‌ها روی میز. کارت کشیده‌شده می‌تواند بعداً در دست بازیکن، مرکز میز یا مجموعهٔ کارت‌های جمع‌شده باشد و این کلاس آن جابه‌جایی‌ها را دنبال نمی‌کنه. IReadOnlyList نیز دسترسی خواندنی ارائه می‌دهد، اما snapshot جداگانه نمی‌سازد؛ فهرست با برداشت بعدی تغییر می‌کنه. برای گزارش پایدار از یک لحظه، مصرف‌کننده باید کپی مورد نیاز خود را بگیرد و معنای گزارش را روشن نگه داره.

چیزی که از این مرحله یاد گرفتم

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

معرفی بازی دلو

مثال عملی دستهٔ اجرایی کارت

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

خطای رایج و علت آن

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

چطور نتیجه را بررسی کنیم؟

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

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

پرسش‌های کاربردی دربارهٔ دستهٔ اجرایی کارت

از کجا شروع کنم؟

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

چه زمانی می‌توانم بگویم این بخش درست کار می‌کند؟

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

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

آخرین دولاگ‌ها

تصویر آموزشی تله‌متری ورود پاسور؛ مرتبط با موضوع نوشته

ورود و تله‌متری پاسور در ساختار مشترک

اضافه‌شدن پاسور باید هم حالت انتخاب‌شده را درست منتقل کند و هم رویداد عمومی معتبر بسازد. من ورود پرداخت‌شده و تله‌متری را ادامهٔ ساختار مشترک دیدم، با حفظ اعتبار کار هم‌تیمی‌ام.

ادامهٔ مطلب
تصویر آموزشی انیمیشن جمع‌کردن پاسور؛ مرتبط با موضوع نوشته

نمایش انتخاب و جمع‌کردن پاسور

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

ادامهٔ مطلب
تصویر آموزشی ربات پاسور؛ مرتبط با موضوع نوشته

تصمیم ربات پاسور از روی گزینه‌های جمع‌کردن

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

ادامهٔ مطلب
Dalo