پس از هفتهها انتظار، شما و دوستانتان برای نخستین بازی Dungeons & Dragons (D&D) گرد هم میآیید. چون این اولین جلسهی بازی است، هر بازیکن باید شخصیتی بسازد که با آن بازی کند. تواناییهای شخصیت با ریختن تاسهای ششوجهی مشخص میشود، اما تاسها کجا هستند؟ با بهت متوجه میشوید که دوستانتان منتظرند شما تاسها را تهیه کنید؛ بالاخره شما بودید که ایدهی بازی D&D را دادید! با دستپاچگی متوجه میشوید که آوردن تاسها را فراموش کردهاید و این یعنی دیگر بازی D&D در کار نیست. چون مهارتهای پایهی برنامهنویسی دارید، سریع راهحلی پیدا میکنید: برنامهای مینویسید که ریختن تاس را شبیهسازی کند.
برای یک بازی Dungeons & Dragons، هر بازیکن با ساختن شخصیتی که بتواند با آن بازی کند کار خود را شروع میکند. این شخصیت، در کنار موارد دیگر، شش ویژگی دارد: قدرت، چابکی، استقامت، هوش، خرد و جذابیت. امتیاز این شش ویژگی بهصورت تصادفی تعیین میشود. این کار را با ریختن چهار تاس ششوجهی و ثبت مجموع سه تاس بزرگتر انجام میدهید. این کار را شش بار انجام میدهید، یک بار برای هر ویژگی.
امتیاز جان اولیهی شخصیت شما برابر است با ۱۰ + تعدیلکنندهی استقامت شخصیت شما. تعدیلکنندهی استقامت شخصیتتان را با کم کردن ۱۰ از استقامت او، تقسیم نتیجه بر ۲ و گرد کردن آن به پایین به دست میآورید.
یک تولیدکنندهی شخصیت تصادفی بنویسید که قواعد بالا را رعایت کند.
برای مثال، شش پرتاب چهار تاس میتواند چنین باشد:
چون استقامت ۳ است، تعدیلکنندهی استقامت منفی ۴ و امتیاز جان ۶ است.
بیشتر زبانهای برنامهنویسی تولیدکنندههای (شبه)تصادفی دارند، اما کمتر زبان برنامهنویسیای برای ریختن تاس طراحی شده است. یکی از این زبانها Troll است.
در زبانهای تابعی، بیشتر توابع خالص هستند. یعنی همیشه برای مجموعهی یکسانی از ورودیها خروجی یکسانی برمیگردانند و کار دیگری انجام نمیدهند. به بیان دیگر، توابع خالص قطعی هستند.
اما طبق تعریف، یک مقدار تصادفی غیرقابلپیشبینی و غیرقطعی است. حتی شبهتصادفی بودن، یعنی برگرداندن دنبالهای از اعداد که تصادفی به نظر میرسند، در یک بافت خالص چندان آسان نیست. دلیلش این است که یک مولد اعداد شبهتصادفی (PRNG) برای برگرداندن عدد بعدی دنباله باید حالت داخلی خود را پیگیری کند.
Lean دو رویکرد ممکن برای این مسئله ارائه میدهد:
۱. استفاده از یک «موناد» که امکان تغییر حالت داخلی یک PRNG را فراهم میکند.
تابع آمادهای به اسم IO.rand وجود دارد که دقیقاً همین کار را میکند.
۲. استفاده از توابع خالصی که یک مولد را به عنوان ورودی میگیرند و نه فقط مقدار شبهتصادفی تولیدشده، بلکه یک مولد بهروزرسانیشده را هم برمیگردانند که برای عدد بعدی دنباله «آماده» شده است.
این تمرین از رویکرد دوم استفاده میکند. به هر تابعی که باید یک مقدار شبهتصادفی تولید کند، یک مولد داده میشود و انتظار میرود که تابع هم مقدار و هم یک مولد بهروزرسانیشده را برگرداند.
توجه کنید که یک مولد مشخص قطعی است؛ یعنی همیشه مقدار یکسانی تولید میکند. برای تولید مقدار شبهتصادفی بعدی در یک دنباله، باید از مولد بهروزرسانیشده استفاده کرد.
در این تمرین، تصادفی بودن با یک آزمون خیدو در سطح معناداری p < 0.0001 بررسی میشود.
یعنی اگر یک امتیاز توانایی طبق دستورالعملها تولید شود، احتمال اینکه یک پیادهسازی درست به دلیل شانس تصادفی در آزمون رد شود کمتر از ۰٫۰۱٪ است.
توجه کنید که طبق دستورالعملها، امتیاز توانایی مجموع سه نتیجهی بزرگتر از چهار بار پرتاب یک تاس ششوجهی بدون سوگیری (d6) است.
در Exercism ثبتنام کنید تا Lean را همراه با 100 تمرین و مربیگری انسانی واقعی یاد بگیرید و در آن استاد شوید، همهی اینها رایگان.
بررسی میکنیم که چگونه تاسهای (بهظاهر) تصادفی تولید کنیم. با دانهها، اعداد شبهتصادفی و چند دام رایج آشنا میشوید. در پایان میبینیم که تست مبتنی بر ویژگی برای تست توابعی که مقادیر تصادفی برمیگردانند چقدر عالی است.