Raised This Month: $12 Target: $400
 3% 

[INC] alias method random


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
arthurdead
Senior Member
Join Date: Jul 2013
Old 04-20-2021 , 19:41   [INC] alias method random
Reply With Quote #1

i needed a way the get a random idx from a array based on weights and i found this blog post by some random dude:
https://blog.bruce-hill.com/a-faster...-random-choice
and ported the alias method to sourcepawn

include:
https://github.com/arthurdead/sm-plu...liasrandom.inc

seems to work good enough for me:


Code:
#include <sourcemod>
#include <aliasrandom>

public void OnPluginStart()
{
	ArrayList randomnames = new ArrayList(ByteCountToCells(64));
	randomnames.PushString("test0");
	randomnames.PushString("test1");
	randomnames.PushString("test3");
	randomnames.PushString("test4");
	randomnames.PushString("test5");

	int len = randomnames.Length;
	ArrayList weights = new ArrayList(1, len);
	weights.Set(0, 15.0);
	weights.Set(1, 2.0);
	weights.Set(2, 70.5);
	weights.Set(3, 40.0);
	weights.Set(4, 5.0);

	AliasRandom test = new AliasRandom(weights);

	int attempts = 500;

	len = randomnames.Length;
	ArrayList nums = new ArrayList(1, len);
	for(int i = 0; i < len; ++i) {
		nums.Set(i, 0);
	}

	int fail = 0;

	char name[64];
	if(test != null) {
		for(int i = 0; i < attempts; ++i) {
			int idx = test.Get();
			if(idx == -1) {
				++fail;
				continue;
			}

			int num = nums.Get(idx);
			++num;
			nums.Set(idx, num);
		}
	}

	PrintToServer("ran %i times %i failed:", attempts, fail);

	for(int i = 0; i < len; ++i) {
		int num = nums.Get(i);
		randomnames.GetString(i, name, sizeof(name));
		float weight = weights.Get(i);
		PrintToServer("  got %s %i times (weight was %.1f)", name, num, weight);
	}

	delete nums;
	delete test;
	delete weights;
}
arthurdead is offline
eyal282
Veteran Member
Join Date: Aug 2011
Old 04-22-2021 , 00:30   Re: [INC] alias method random
Reply With Quote #2

Duck duck go my store jackpot plugin. I think mine is more efficient, and I doubt arraylists are necessary.
__________________
I am available to make plugins for pay.

Discord: Eyal282#1334
eyal282 is offline
Lux
Veteran Member
Join Date: Jan 2015
Location: Cat
Old 04-23-2021 , 08:02   Re: [INC] alias method random
Reply With Quote #3

Quote:
Originally Posted by eyal282 View Post
Duck duck go my store jackpot plugin. I think mine is more efficient, and I doubt arraylists are necessary.
-Post link to whatever code you are talking about.
-Perf test it whatever you are talking about and show results.
-Why not contribute with the more efficient code so everyone benefits using this include.


EDIT:I'v never used a weighting system tbh the blog was interesting, thanks for the include i will use it
__________________
Connect
My Plugins: KlickME
[My GitHub]

Commission me for L4D

Last edited by Lux; 04-23-2021 at 08:07.
Lux is offline
Desktop
AlliedModders Donor
Join Date: Sep 2009
Location: C:\Users\Default\
Old 04-23-2021 , 14:14   Re: [INC] alias method random
Reply With Quote #4

Quote:
Originally Posted by eyal282 View Post
Duck duck go my store jackpot plugin. I think mine is more efficient, and I doubt arraylists are necessary.

Yeah, if you could submit the code, it would be really nice, since these funcs are not often seen here and they're very useful
__________________
Massive Infection:: Piu-Games
Desktop is offline
eyal282
Veteran Member
Join Date: Aug 2011
Old 05-11-2021 , 12:25   Re: [INC] alias method random
Reply With Quote #5

Quote:
Originally Posted by Desktop View Post
Yeah, if you could submit the code, it would be really nice, since these funcs are not often seen here and they're very useful
https://github.com/eyal282/Alliedmod...ore-jackpot.sp
__________________
I am available to make plugins for pay.

Discord: Eyal282#1334
eyal282 is offline
Localia
New Member
Join Date: Sep 2020
Old 05-18-2023 , 06:36   Re: [INC] alias method random
Reply With Quote #6

I got an error at 'target.Push(i)' .
I guess in extreme cases, the result of "GetRandomFloat (-1.0,1.0) " can be 0.0, so the 'ArrayList target' will remain as "null",which can cause error when "target.Push(i)"


Code:
	ArrayList smalls = new ArrayList(2);
	ArrayList bigs = new ArrayList(2);

	int small_i = 0;
	int big_i = 0;

	for(int i = 0; i < len; ++i) {
		float weight = weights.Get(i);

		if(weight == avg) 
		{
			weight += GetRandomFloat(-1.0, 1.0);
		}

		bool is_small = (weight < avg);
		bool is_big = (weight > avg);

		ArrayList target = null;
		int target_i = -1;
		if(is_small) 
		{
			target = smalls;
			target_i = small_i;
		} 
		else if(is_big) 
		{
			target = bigs;
			target_i = big_i;
		}

		target.Push(i);
		if(weight > 0.0 && avg > 0.0) {
			weight = weight/avg;
		} else {
			weight = 0.0;
		}
		target.Set(target_i, weight, 1);

		if(is_small) {
			++small_i;
		} else if(is_big) {
			++big_i;
		}
	}

I made a simple fix.
Code:
	if(weight == avg) 
	{
		weight += GetRandomInt(0,99) < 50? 0.00001:-0.00001;
	}

Last edited by Localia; 05-18-2023 at 07:06.
Localia is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 00:55.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode