View Single Post
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