র্যান্ডম নাম্বার সাধারণত যাকে আমরা ‘ইউনিফর্ম ডিস্ট্রিবিউশন’ বলি সেটি ফলো করে, অর্থাৎ যেকোনো নাম্বার পিক হওয়ার সমান চান্স থাকে।
কিন্তু আপনি যদি চান কিছু নাম্বার অন্যগুলোর চেয়ে বেশি বার পিক হোক তবে আপনাকে ভিন্ন একটি কৌশল লাগবে: একটি ওয়েটেড র্যান্ডম নাম্বার জেনারেটর।
কয়েকটি প্র্যাকটিক্যাল অ্যাপ্লিকেশন:
- ভিডিও গেমের লুট টেবিল, যেখানে শত্রুরা ভিন্ন ভিন্ন ড্রপ রেটের সাথে আলাদা আলাদা আইটেম ড্রপ করে।
- একটি রাফল, যেখানে বেশি টিকিট কিনে যারা আছে তাদের বেশি চান্স থাকে জেতার।
সিম্পল কৌশল
রাফল উদাহরণটি ভাবলে আপনি একটি স্পষ্ট সমাধান পাবেন: একটি অ্যারে তৈরি করুন যেটিতে প্রতিটি ‘টিকিট’ এর জন্য আইটেমটির একটি কপি থাকবে।
উদাহরণস্বরূপ, যদি জন ৪টি রাফল টিকিট কিনে এবং ডেভিড শুধু ১টি কিনে, তবে জনের জেতার চান্স ডেভিডের চেয়ে ৪ গুন বেশি থাকবে।
এখানে একটি ওয়ার্কিং ইমপ্লিমেন্টেশন:
users = { john: 4, david: 1 } raffle = [] users.map do |name, tickets| tickets.times { raffle << name } end p raffle # [:john, :john, :john, :john, :david] p raffle.sample # :john
আমি প্রতিটি টিকিটের জন্য ব্যক্তির নামটি একবার করে যোগ করছি, এবং তারপর সেই লিস্ট থেকে একটি র্যান্ডম নাম পিক করছি। লিস্টে বেশিবার থাকার কারণে সেই নামটি পিক হওয়ার চান্স বেড়ে যায়।
মुझे এই পদ্ধতি পছন্দ কারণ এটি খুব সিম্পল এবং একবার লিস্ট তৈরি হলে উইনার পিক করা খুব ফাস্ট।
ওয়েটের সমষ্টি (Sum of Weights)
এটি করার আরেকটি পদ্ধতি আছে যা মেমরি-এফিশিয়েন্ট, কিন্তু ট্রেড-অফ হল র্যান্ডম ভ্যালু পিক করা স্লো।
আইডিয়া হল: ১ থেকে সকল ওয়েটের সমষ্টি পর্যন্ত একটি র্যান্ডম নাম্বার পিক করুন, এবং তারপর লুপ চালিয়ে এমন একটি ওয়েট খুঁজুন যা এই নাম্বারের চেয়ে কম বা সমান।
কোডটি এখানে:
def random_weighted(weighted) max = sum_of_weights(weighted) target = rand(1..max) weighted.each do |item, weight| return item if target <= weight target -= weight end end def sum_of_weights(weighted) weighted.inject(0) { |sum, (item, weight)| sum + weight } end
এই কোডটি একটি হ্যাশ নেয় যেখানে কীগুলো হল আইটেম এবং ভ্যালুগুলো হল ওয়েট। আপনি এই মেথডকে এভাবে কল করতে পারেন:
random_weighted(cats: 5, dogs: 1) # :cats
আপনি এটি অনেকবার রান করে রেজাল্টের ডিস্ট্রিবিউশন দেখে চেক করতে পারেন যে এটি প্রত্যাশা অনুযায়ী কাজ করছে কিনা।
এখানে একটি উদাহরণ:
counts = Hash.new(0) def pick_number random_weighted(cats: 2, dogs: 1) end 1000.times { counts[pick_number] += 1 } p counts
এটি কয়েকবার রান করুন এবং আউটপুট দেখুন যে রেশিও ঠিক আছে কিনা।
উপসংহার
আরও উন্নত অ্যালগরিদম থাকলেও, এই দুটি আপনার জন্য যথেষ্ট। আশা করি আর্টিকেলটি উপকারী লাগলো, দয়া করে আপনার বন্ধুদের সাথে শেয়ার করুন যাতে আমি আরও লিখতে পারি!