مسئلهای که باید حل میکردم
بر زدن را نمیخواستم داخل پخش کارت پنهان کنم. اگر بعداً یک بازی پخش محدودشده بخواهد، باید بتوانم روش چینش را عوض کنم و بقیهٔ هسته را نگه دارم.
پیادهسازی در نسخهٔ فعلی
FisherYatesShuffleStrategy قرارداد IShuffleStrategy را پیاده میکنه. حلقه از آخر فهرست جلو میآید، از بازهٔ صفر تا اندیس فعلی یک موقعیت انتخاب میکنه و دو عنصر را جابهجا میکنه.
تصمیم و هزینهٔ طراحی
سازنده seed اختیاری داره. برای بازسازی یک مسیر منطقی این قابلیت مفید هست؛ استفاده از System.Random را با تضمین تصادف رمزنگاریشده یا ضدتقلب یکسان نمیدانم.
مرزهای فعلی
قابل تکرار بودن فقط به seed محدود نیست؛ ترتیب ورودی و تعداد فراخوانیها هم مهماند. بدون ثابت نگهداشتن آنها، دو اجرای ظاهراً مشابه میتوانند چینش متفاوتی بسازند.
بازسازی یک ترتیب برای بررسی خطا
برای بررسی یک ایراد در تقسیم کارت، فقط گفتن اینکه دسته بر زده شده کافی نیست. باید ترتیب ورودی و وضعیت مولد تصادفی را هم بشناسیم. سازندهٔ FisherYatesShuffleStrategy یک seed اختیاری میگیرد و Random را همانجا میسازد. اگر دو نمونهٔ تازه با seed یکسان روی ورودیهای یکسان اجرا بشن، میشود دربارهٔ تکرار همان مسیر منطقی تحقیق کرد. این قابلیت بیشتر برای ساخت سناریوی قابل توضیح مفید هست؛ من از روی آن نتیجه نمیگیرم که گزارشهای اجرای واقعی یا ذخیرهٔ مسابقه در دلو کامل هستند.
خود حلقه از آخر فهرست به سمت ابتدا میآید و random.Next(i + 1) را اجرا میکنه. اضافه شدن یک به i باعث میشود موقعیت فعلی نیز یکی از انتخابهای مجاز باشد؛ گاهی کارت همانجا میماند و این بخشی از الگوریتم هست. جابهجایی روی همان IList انجام میشود و خروجی تازهای برگردانده نمیشود. بنابراین فراخواننده باید انتظار تغییر ورودی را داشته باشد. اگر همزمان نسخهٔ اولیهٔ ترتیب برای مقایسه لازم هست، آن نسخه را باید پیش از Shuffle جدا نگه داشت، نه بعد از تغییر فهرست.
استراتژی فقط برای کارت نوشته نشده؛ متد Shuffle پارامتر نوع عمومی داره. همین استقلال اجازه میدهد ترتیب هر مجموعهٔ قابل جابهجایی با همان قرارداد مدیریت بشه. هزینهاش این هست که هیچ قاعدهای دربارهٔ دست آغازین جوکر یا معتبر بودن ترکیب دسته داخل آن وجود نداره. همچنین استفادهٔ دوباره از همان نمونهٔ استراتژی، مولد Random را از نقطهٔ قبلی ادامه میدهد. seed ثابت به معنای بازنشانی خودکار پس از هر فراخوانی نیست؛ برای بازسازی یک مشکل باید تعداد و ترتیب فراخوانیها نیز در سناریو ثبت بشن.
چیزی که از این مرحله یاد گرفتم
این قرارداد بعداً برای جوکر معنی پیدا کرد: پخش بدون جفت آغازین یک مسئلهٔ دیگر بود. روش عادی بر زدن باقی ماند و قانون خاص بازی مجبور نشد داخل آن جا بگیرد.
مثال عملی بر زدن کارت
یک روش کاربردی برای بررسی بر زدن کارت این است که به جای چند تغییر همزمان، تنها یک مسیر کوتاه بسازی. یک دستهٔ مشخص را با بذر تصادفی معلوم بر بزن و نتیجه را دوباره با همان ورودی اجرا کن. سپس وضعیت قبل و بعد را کنار هم قرار بده. چه بخشی از داده تغییر کرده و کدام بخش فقط ظاهر تازهای پیدا کرده است؟ پاسخ باید از همان تعریف موضوع بیاید. این موقعیت یک مثال آموزشی است و آمار واقعی محصول یا وعدهٔ قابلیت جدید محسوب نمیشود.
خطای رایج و علت آن
انتخاب مکرر دو اندیس تصادفی بهتنهایی تضمین توزیع یکنواخت همهٔ جایگشتها نیست. این خطا معمولاً وقتی پنهان میماند که فقط مسیر موفق و ظاهر نهایی را ببینیم. برای پیدا کردن علت، آخرین وضعیت درست را از نخستین وضعیت نادرست جدا کن و ببین تغییر دقیقاً در کدام مرز رخ داده است. بذر ثابت برای عیبیابی مفید است، ولی پیشبینیپذیری در بازی رقابتی موضوع جداگانهای است. اگر این تفاوت در قرارداد مشخص نباشد، اصلاح یک نشانه ممکن است همان مسئله را در بخش دیگری دوباره ایجاد کند.
چطور نتیجه را بررسی کنیم؟
علاوه بر تکرارپذیری، یکتایی کارتها و حفظ تعداد پیش و پس از بر زدن را بررسی کن. اجرای یکباره برای نتیجهگیری کافی نیست؛ یک بار مسیر معمول و بار دیگر همان موقعیت را با ورودی مرزی یا تکرار اقدام بررسی کن. اگر نتیجه فرق دارد، ورودی و شرایط اجرا را همراه خروجی نگه دار تا مقایسه قابل بازسازی باشد. جدول زیر خلاصهٔ مشخصات همین سناریو است و برای ثبت نتیجهٔ بررسی به کار میآید.
| بخش بررسی | آنچه باید ثبت شود |
|---|---|
| موقعیت آزمایشی | یک دستهٔ مشخص را با بذر تصادفی معلوم بر بزن و نتیجه را دوباره با همان ورودی اجرا کن. |
| ریسک اصلی | انتخاب مکرر دو اندیس تصادفی بهتنهایی تضمین توزیع یکنواخت همهٔ جایگشتها نیست. |
| روش بررسی | علاوه بر تکرارپذیری، یکتایی کارتها و حفظ تعداد پیش و پس از بر زدن را بررسی کن. |
| مرز نتیجهگیری | بذر ثابت برای عیبیابی مفید است، ولی پیشبینیپذیری در بازی رقابتی موضوع جداگانهای است. |
پرسشهای کاربردی دربارهٔ بر زدن کارت
از کجا شروع کنم؟
از همان موقعیت محدود این مطلب شروع کن: یک دستهٔ مشخص را با بذر تصادفی معلوم بر بزن و نتیجه را دوباره با همان ورودی اجرا کن. ابتدا نتیجهٔ مورد انتظار را مشخص کن و بعد سراغ پیادهسازی یا ابزار برو. وقتی مسیر پایه قابل توضیح و بررسی شد، میتوان حالتهای بیشتری اضافه کرد. ساخت همهٔ حالتها از ابتدا، فهم علت خطا را سختتر میکند.
چه زمانی میتوانم بگویم این بخش درست کار میکند؟
زمانی که رفتار در موقعیت تعریفشده با قرارداد سازگار باشد و محدودیتهای آن روشن بمانند. علاوه بر تکرارپذیری، یکتایی کارتها و حفظ تعداد پیش و پس از بر زدن را بررسی کن. موفقیت در این آزمون دربارهٔ همان سناریو شاهد میدهد؛ از آن نمیتوان بدون بررسی دربارهٔ همهٔ دستگاهها، همهٔ قوانین محلی یا همهٔ حجمهای داده نتیجه گرفت. بذر ثابت برای عیبیابی مفید است، ولی پیشبینیپذیری در بازی رقابتی موضوع جداگانهای است.
برای ادامهٔ همین موضوع، هستهٔ مشترک دلو؛ یک میز برای چند بازی و بازی دلو را ببین. زمینهٔ ساخت این پروژهها و معرفی سازنده در صفحهٔ کیان پاک نعمت آمده است.




