কয়েক সপ্তাহের অপেক্ষার পর, আপনি আর আপনার বন্ধুরা একসঙ্গে জড়ো হলেন আপনার জীবনের প্রথম Dungeons & Dragons (D&D) গেম খেলতে। যেহেতু এটি গেমটির প্রথম সেশন, তাই প্রত্যেক খেলোয়াড়কে খেলার জন্য একটি চরিত্র বানাতে হবে। চরিত্রের ক্ষমতাগুলো নির্ধারিত হয় ছয় দিকের পাশা গড়ে, কিন্তু পাশাগুলো কোথায়? আচমকা ধাক্কা খেয়ে আপনি বুঝতে পারেন, আপনার বন্ধুরা অপেক্ষা করছে আপনিই পাশা বানিয়ে আনবেন বলে; D&D খেলার আইডিয়াটা তো আপনারই ছিল! আতঙ্কিত হয়ে আপনি বুঝতে পারেন যে আপনি পাশা আনতে ভুলে গেছেন, যার মানে D&D গেম হবে না। যেহেতু আপনার প্রাথমিক প্রোগ্রামিং দক্ষতা আছে, তাই আপনি দ্রুত একটি সমাধান বের করেন: পাশা গড়ানো সিমুলেট করার জন্য একটি প্রোগ্রাম লিখবেন।
একটি Dungeons & Dragons গেমে প্রতিটি খেলোয়াড় প্রথমে নিজের খেলার জন্য একটি ক্যারেক্টার তৈরি করে। অন্যান্য বিষয়ের পাশাপাশি এই ক্যারেক্টারের থাকে ছয়টি অ্যাবিলিটি: strength, dexterity, constitution, intelligence, wisdom এবং charisma. এই ছয়টি অ্যাবিলিটির স্কোর ঠিক করা হয় র্যান্ডমভাবে। এটি করার জন্য আপনি ছয় দিকের চারটি পাশা গড়িয়ে সবচেয়ে বড় তিনটি পাশার যোগফল লিখে রাখেন। এভাবে আপনি ছয়বার এটি করেন, প্রতিটি অ্যাবিলিটির জন্য একবার।
আপনার ক্যারেক্টারের শুরুর হিটপয়েন্ট হলো 10 + আপনার ক্যারেক্টারের constitution মডিফায়ার। আপনার ক্যারেক্টারের constitution থেকে 10 বিয়োগ করে, 2 দিয়ে ভাগ করে এবং নিচের দিকে রাউন্ড করে আপনি constitution মডিফায়ার বের করেন।
উপরের নিয়মগুলো মেনে একটি র্যান্ডম ক্যারেক্টার জেনারেটর লিখুন।
উদাহরণ হিসেবে, চারটি পাশা ছোড়ার ছয়টি ফল এমন হতে পারে:
যেহেতু constitution 3, তাই constitution মডিফায়ার হয় -4 এবং হিটপয়েন্ট হয় 6।
বেশিরভাগ প্রোগ্রামিং ভাষাতেই (সিউডো-)র্যান্ডম জেনারেটর থাকে, কিন্তু পাশা ছোড়ার জন্য তৈরি প্রোগ্রামিং ভাষা খুব কমই আছে। এমন একটি ভাষা হলো Troll.
ফাংশনাল ভাষায় বেশিরভাগ ফাংশনই পিউর। এর মানে হলো, একই সেট আর্গুমেন্টের জন্য তারা সবসময় একই আউটপুট রিটার্ন করে, এর বাইরে আর কিছুই করে না। অন্যভাবে বললে, পিউর ফাংশন ডিটারমিনিস্টিক।
কিন্তু সংজ্ঞা অনুযায়ীই একটি র্যান্ডম মান অনির্দেশ্য এবং নন-ডিটারমিনিস্টিক। এমনকি সিউডোর্যান্ডমনেস, অর্থাৎ এমন এক সিকোয়েন্স রিটার্ন করা যার সংখ্যাগুলো দেখতে র্যান্ডম মনে হয়, পিউর প্রেক্ষাপটে সহজে অর্জনযোগ্য নয়। এর কারণ হলো, সিকোয়েন্সের পরের সংখ্যাটি রিটার্ন করার জন্য একটি সিউডোর্যান্ডম নাম্বার জেনারেটর (PRNG) নিজের ইন্টারনাল স্টেটের হিসাব রাখে।
এই সমস্যা সমাধানের জন্য Lean দুটি সম্ভাব্য পথ দেয়:
এমন একটি মোনাড ব্যবহার করুন, যার সাহায্যে একটি PRNG-এর ইন্টারনাল স্টেট বদলানো সম্ভব।
এর জন্য সহজলভ্য একটি ফাংশন রয়েছে, IO.rand, যা ঠিক এই কাজটিই করে।
এমন পিউর ফাংশন ব্যবহার করুন, যেগুলো আর্গুমেন্ট হিসেবে একটি জেনারেটর নেয় এবং শুধু উৎপন্ন সিউডোর্যান্ডম মানই নয়, সিকোয়েন্সের পরের সংখ্যার জন্য "প্রস্তুত" একটি হালনাগাদ জেনারেটরও রিটার্ন করে।
এই অনুশীলনীতে দ্বিতীয় পদ্ধতিটি ব্যবহার করা হয়েছে। যে ফাংশনেরই একটি সিউডোর্যান্ডম মান তৈরি করা উচিত, তাকে একটি জেনারেটর পাঠানো হয়, আর ওই ফাংশনের কাছ থেকে আশা করা হয় যে সে মানটি এবং একটি হালনাগাদ জেনারেটর, দুটোই রিটার্ন করবে।
মনে রাখবেন, একটি নির্দিষ্ট জেনারেটর ডিটারমিনিস্টিক, অর্থাৎ এটি সবসময় একই মান তৈরি করে। সিকোয়েন্সে পরের সিউডোর্যান্ডম মানটি তৈরি করতে হলে হালনাগাদ জেনারেটরটি ব্যবহার করা প্রয়োজন।
এই অনুশীলনীতে র্যান্ডমনেস যাচাই করা হয় একটি চি-স্কয়ার্ড টেস্ট দিয়ে, যেখানে সিগনিফিকেন্স লেভেল হলো p < 0.0001।
এর মানে হলো, নির্দেশনা অনুযায়ী যদি একটি অ্যাবিলিটি স্কোর তৈরি করা হয়, তাহলে একটি সঠিক ইমপ্লিমেন্টেশন শুধু কাকতালীয় র্যান্ডম কারণেই টেস্টে ফেল করার সম্ভাবনা ০.০১%-এরও কম।
মনে রাখবেন, নির্দেশনা অনুযায়ী একটি অ্যাবিলিটি স্কোর হলো একটি নিরপেক্ষ d6 (ছয় তলের পাশা)-এর চারটি রোলের মধ্যে তিনটি বৃহত্তম ফলাফলের যোগফল।
Exercism-এ সাইন আপ করুন, Lean ট্র্যাকের 100টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।
আমরা দেখব কীভাবে (আপাতদৃষ্টিতে) এলোমেলো ডাইস রোল তৈরি করা যায়। আপনি সিড, সিউডো র্যান্ডম সংখ্যা আর কিছু কমন বিপদ সম্পর্কে জানতে পারবেন। শেষে দেখব, র্যান্ডম মান রিটার্ন করা ফাংশন টেস্ট করার জন্য প্রপার্টি-বেজড টেস্টিং কতটা দারুণ।