ভাগ্যনির্ভর খেলার জন্য এলোমেলোতার একটি উৎস দরকার। Factor-এর random ভোকাবুলারিতে আছে একটি জেনেরিক ওয়ার্ড, random, যা আপনি যা-ই দেন না কেন তার সঙ্গে খাপ খায়; সঙ্গে আছে শাফলিং ও স্যাম্পলিংয়ের জন্য কিছু সহায়ক ওয়ার্ড, আর টেস্টের জন্য এলোমেলোতাকে পুনরুৎপাদনযোগ্য করার একটি উপায়।
inline চিহ্নিত করাএই অনুশীলনীর কিছু কাজে এমন একটি ওয়ার্ড ডিফাইন করতে হয়, যা আর্গুমেন্ট হিসেবে একটি কোয়োটেশন (একটি [ … ] ব্লক) নেয় আর সেটি রান করে। এ বিষয়ে Factor-এর একটি অনড় নিয়ম আছে: আর্গুমেন্ট হিসেবে পাওয়া কোনো কোয়োটেশনকে যে ওয়ার্ড call করে, তাকে অবশ্যই inline ডিক্লেয়ার করতে হবে, আর সেটি লেখা হয় শেষ ;-এর ঠিক পরে inline বসিয়ে।
inline কম্পাইলারকে বলে, ওয়ার্ডটির বডি আলাদা করে একবার কম্পাইল না করে প্রতিটি কল সাইটে সেটি জুড়ে দিতে।
এখানে একটি ছোট ওয়ার্ড আছে, যা 10 পুশ করে তারপর তার হাতে দেওয়া কোয়োটেশনটি রান করে:
USING: kernel math prettyprint ;
: with-ten ( quot -- ) 10 swap call ; inline
এর স্ট্যাক ইফেক্ট ( quot -- ) কোনো আউটপুটের নাম বলে না, তবু ভিন্ন ইফেক্টের দুটি কোয়োটেশন দিয়ে এটি কল করলে ভিন্ন ফল আসে, আর সেগুলো সবই ফিরে যায় কলারের কাছে:
[ 1 + ] with-ten . ! => 11 (quotation ( n -- n ): one value back)
[ dup 2 * ] with-ten . . ! => 20
! => 10 (quotation ( n -- n n ): two values back)
random: একটি এলিমেন্টrandom (random-এ আছে) তার আর্গুমেন্টের ওপর জেনেরিক:
random ( obj -- elt )
n দিলে এটি [0, n) রেঞ্জের একটি এলোমেলো ইন্টিজার রিটার্ন করে:USING: random ;
6 random . ! 4 (a value from 0 to 5)
{ "rock" "paper" "scissors" } random . ! "paper"
সাধারণ ছক্কা গড়তে রেঞ্জটি এক ধাপ উপরে সরাতে হয়: 6-এর random দেয় 0 থেকে 5, তাই 6 random 1 + দেয় 1 থেকে 6।
নির্দিষ্ট সংখ্যক এলোমেলো ড্র জড়ো করতে replicate (sequences-এ আছে) দিয়ে একটি কোয়োটেশন বারবার চালান:
replicate ( n quot -- seq )
USING: random sequences ;
3 [ 6 random 1 + ] replicate . ! { 4 1 6 } (three dice)
randomize: একই জায়গায় শাফলrandomize (random-এ আছে) সিকোয়েন্সটির এলিমেন্টগুলো এলোমেলো ক্রমে সাজিয়ে সেটিই রিটার্ন করে:
randomize ( seq -- randomized )
{ 1 2 3 4 5 } randomize . ! { 3 1 5 2 4 }
এটি একই জায়গাতেই শাফল করে আর সেই একই সিকোয়েন্স রিটার্ন করে, তাই মূল ক্রমটা ধরে রাখতে চাইলে আগে clone করুন।
sample: কয়েকটি আলাদা এলিমেন্টsample (random-এ আছে) একটি সিকোয়েন্স থেকে nটি আলাদা এলিমেন্ট ড্র করে, ঠিক তাসের হাত বিলি করার মতো, যেখানে একই তাস দুবার আসে না:
sample ( seq n -- seq' )
{ 10 20 30 40 50 } 3 sample . ! { 40 10 30 }
সিকোয়েন্সে যত এলিমেন্ট আছে তার চেয়ে বেশি চাইলে সেটি এরর।
ডিফল্টভাবে random সিস্টেম ক্লক থেকে সিড নেওয়া একটি গ্লোবাল জেনারেটর থেকে ড্র করে, তাই প্রতিবার রান করলে ফল আলাদা আসে। টেস্টের জন্য, কিংবা যখনই আবার খেলা যায় এমন একটি গেম চান, তখন একটি নির্দিষ্ট সিড দিয়ে জেনারেটর বাইন্ড করুন।
<mersenne-twister> (random.mersenne-twister-এ আছে) একটি ইন্টিজার সিড থেকে জেনারেটর তৈরি করে, আর with-random (random-এ আছে) সেই জেনারেটরটি বসিয়ে একটি কোয়োটেশন রান করে:
<mersenne-twister> ( seed -- rnd )
with-random ( rnd quot -- )
USING: random random.mersenne-twister ;
42 <mersenne-twister> [ 6 random 1 + ] with-random .
! always the same value for seed 42
কোয়োটেশনের ভেতরের সবকিছু, অর্থাৎ random, randomize, sample, সিড দেওয়া জেনারেটর থেকেই ড্র করে, তাই একই সিড সবসময় একই ফল দেয়।
যে ওয়ার্ড আর্গুমেন্ট হিসেবে একটি কোয়োটেশন নেয় আর সেটি with-random দিয়ে রান করে, সেটি একটি ওয়ার্ডকে inline চিহ্নিত করা অংশের নিয়মের আওতায় পড়ে: শেষ পর্যন্ত with-random-ই ওই কোয়োটেশনটি call করে, তাই এমন র্যাপারকে অবশ্যই inline চিহ্নিত করতে হবে।
আপনি সমুদ্রতীরের বোর্ডওয়াক আর্কেডে ভাগ্যের খেলাগুলো চালান। খেলোয়াড়েরা পাশা গড়ায়, ক্ল মেশিন একটি পুরস্কার তুলে নেয়, আর কার্ড টেবিলের ডেক শাফল করা ও হাত ভাগ করা দরকার। এসবের সবকিছুই চলে র্যান্ডমনেসের জোরে। রাতের শেষে আপনার একটি "রিপ্লে" ফিচারও দরকার, যাতে বিতর্কিত কোনো খেলা একই সিড থেকে আবার চালানো যায়।
roll-die ডিফাইন করুন যাতে এটি বাহুর সংখ্যা নেয় এবং 1 থেকে sides রেঞ্জের (অন্তর্ভুক্ত) একটি রোল রিটার্ন করে।
6 roll-die .
! => 4 (some value from 1..6)
pick-prize ডিফাইন করুন যাতে এটি পুরস্কারের একটি সিকোয়েন্স নেয় এবং সেখান থেকে যেকোনো একটি র্যান্ডমভাবে রিটার্ন করে।
{ "teddy" "goldfish" "keyring" } pick-prize .
! => "goldfish"
shuffle-deck ডিফাইন করুন যাতে এটি একটি ডেক (একটি সিকোয়েন্স) নেয় এবং কার্ডগুলোকে র্যান্ডম ক্রমে সাজিয়ে সেটি রিটার্ন করে।
{ 1 2 3 4 5 } shuffle-deck .
! => { 3 1 5 2 4 }
deal-hand ডিফাইন করুন যাতে এটি একটি ডেক ও একটি সংখ্যা n নেয়, এবং ডেক থেকে nটি আলাদা কার্ড রিটার্ন করে।
{ 10 20 30 40 50 } 3 deal-hand .
! => { 40 10 30 }
play-seeded ডিফাইন করুন যাতে এটি একটি সিড ও একটি কোয়োটেশন নেয়, এবং ওই ইন্টিজার থেকে সিড করা একটি জেনারেটর দিয়ে কোয়োটেশনটি রান করে, ফলে একই সিড সবসময় একই ফলাফল আবার তৈরি করে। কোয়োটেশনের ফলাফলটি কলকারীকে রিটার্ন করা উচিত।
42 [ 6 roll-die ] play-seeded .
! => the same value every time for seed 42
! Same seed, same game:
99 [ 5 deal-hand ] play-seeded 99 [ 5 deal-hand ] play-seeded = .
! => t
Exercism-এ সাইন আপ করুন, Factor ট্র্যাকের 47টি কনসেপ্ট163টি অনুশীলনী আর সত্যিকারের মানুষের মেন্টরিং দিয়ে শিখুন ও দক্ষ হয়ে উঠুন, সম্পূর্ণ বিনামূল্যে।