Ranlib, the Ultimate Random Library (WORLEY NOISE)

What is Ranlib?


Ranlib is a Random wrapper which includes new utilities for procedural generation. It serves to make randomness even more useful and convenient than ever before, grouping up many previously separate functionality from others, improving its design, as well as adding original ideas, making it distinct.

What can I use it for?


Ranlib allows generating more randomized complex objects, such as Enums, uniformly distributed points on a sphere, strings, etc. as well as providing commonly needed methods such as random selection and shuffling.

Documentation


Fields

Ranlib.Quantum
Quantum library for Ranlib.

Ranlib.Random
The Random object the wrapper is using.

Ranlib.State
The previous random output of the wrapper.

Ranlib.AntiRepetition = false
The previous random output of the wrapper.

Methods

Note: Arrays and Dictionaries are both tables, with the former having numerical indexes and the latter with non-numerical indexes.

Ranlib.new(seed: number): RanlibWrapper
Creates a new Random wrapper.

Ranlib.HashString(key: string || any): int32
Generates a hash using the given key. If the key is not a string, it will be converted into one using tostring().

Ranlib.OldHashString(key: string || any): int32
Generates a hash using the given key. If the key is not a string, it will be converted into one using tostring().

Ranlib.WorleyNoise2D(x: number, y: number, seed: number): number
Returns a worley noise value in 2D.

Ranlib.WorleyNoise3D(x: number, y: number, z: number, seed: number): number
Returns a worley noise value in 3D.

Ranlib:Clone(): RanlibWrapper
Creates a new Random wrapper with the same state.

Ranlib:SetSeed(newSeed: number): nil
Overwrite the seed of the wrapper

Ranlib:NextInteger(m: int?, n: int?): int
Gives the next integer using a and b as thresholds. if b is not specified, it will generate an integer between 0 and a. If both a and b are not specified, it will generate either a one or zero.

Ranlib:NextNumber(m: number?, n: number?): number
Gives the next number using a and b as thresholds. If b is not specified, it will generate a number between 0 and a. If both a and b are not specified, it will generate a number between one and zero.

Ranlib:NextTriangular(min: number, center: number, max: number): number
Gives the next random number in a triangular distribution using min and max as thresholds. The center is where the center of that distribution is located.

Ranlib:NextBoolean(): boolean
Gives the next boolean. Can either be true or false.

Ranlib:NextBiasedBoolean(percentTrue: number): boolean
Gives the next random boolean that is biased towards a certain outcome.

Ranlib:NextEnum(EnumTable: enum): Enum
Gives the next random Enum item inside an Enum.

Example:

local rand = Ranlib.new()
rand:NextEnum(Enum.KeyCode)

Returns a random key.

Ranlib:NextMaterial(): Enum.Material
Gives the next random Material.

Ranlib:NextColor(): Color3
Gives the next Color3.

Ranlib:NextBrickColor(): BrickColor
Gives the next BrickColor.

Ranlib:NextSphere(radius: number?, onlyUnit: boolean?): Vector3
Gives the next 3-D point on a sphere.

Ranlib:NextCircle(radius: number?, onlyUnit: boolean?): Vector2
Gives the next 2-D point on a circle.

Ranlib:NextBox(size: Vector3): Vector3
Gives the next 3-D point on a box.

Ranlib:NextAngle(): CFrame
Gives the next randomly rotated CFrame.

Ranlib:NextFlatAngle(): CFrame
Gives the next randomly rotated CFrame. The LookVector is parallel to the horizon.

Ranlib:NextAxis3D(flat: boolean): Vector3
Returns the next randomly chosen unit axial direction in 3 dimensions.

Ranlib:NextAxis2D(): Vector2
Returns the next randomly chosen unit axial direction in 2 dimensions.

Ranlib:NextSelect(array: array): any
Gives a random selection of an element in t.

Ranlib:NextKey(dictionary: dictionary, amount: int): any
Gives a random access key of a dictionary. The amount argument determines how many values (these are stored in an array; if this is not specified, it will return the key without being wrapped in an array) it returns.

Ranlib:NextShuffle(cards: table): table
Shuffles a copy of the table cards before returning the result.

Ranlib:NextChance(chanceDictionary: dictionary): any
Gives the next “chance” of a weighted table. For example, you could have a chance table that looks like this:

local chanceDictionary = {
	Normal = 80,
	Uncommon = 10,
	Rare = 5,
	Unique = 3,
	Legendary = 2,
}

The method would then have an 80% chance to give a Normal, 10% a Uncommon, 5% a Rare, and etc.

Ranlib:LoadNextChanceState(chanceDictionary: dictionary): ChanceState
Returns a ChanceState object

ChanceState:NextChance(): any

Ranlib:GetPercentages(chanceDictionary: dictionary): dictionary
Gives the probability of a weighted table’s outcome. This is to help obey laws in the EU.

Ranlib:NextString(length: int): string
Gives the next string.

Ranlib:NextName(length: int, markovChain: table): string
Generates the next random name using a markov chain. The length argument determines how many terms are in the final string. Markov chains in this module are constructed like this:

local chain = {
	a = {
		a = 50,
		b = 25,
		c = 25
	},
	
	b = {
		a = 25,
		b = 50,
		c = 25
	},
	
	c = {
		a = 25,
		b = 25,
		c = 50
	},
}

, where each term is listed in the dictionary, with chance tables for all future terms contained inside. If a markov chain is not specified, it will use the default one. The list of names the default chain can produce include but not limited to the following:

Anumizune
Ocolyaeses
Teb
Muso
Luretolyov
Lohas
Uxaumeiac
Azienal
Damememe

Results should be filtered before being shown to players.

Ranlib:LoadNextNameState(markovChain: table): NameState
Returns a NameState object

NameState:NextName(length: int): string

Quantum Library Methods

Ranlib.Quantum.NextNumber(min: number, max: number, requests: int): number | array | boolean, number
Requests the next quantum random numbers. Returns a random number and the time it took to request it. If requests is greater than 1, it will return an array of numbers instead.

Ranlib.Quantum.NextInteger(min: number, max: number, requests: int): number | array | boolean, number
Requests the next quantum random integers. Returns a random integer and the time it took to request it. If requests is greater than 1, it will return an array of integers instead.

Improvements


Roblox has announced that they are planning to adding a new method to their Random class called :NextUnitVector(), which I plan on incorporating into Ranlib’s current implementation.

Some methods could be further optimized by partially saving their local states, such as :NextEnum(), :NextName(), and :NextChance(), however, their current performance is adequate for release.

I am also considering adding more features such as more random variate generation, better anti-repetition abilities quasi-replacement capabilities, quantum/random.org true randomness, and smooth noise algorithms

Install Here


Roblox Model

33 Likes

good stuff,I love it,Would you mine giving example on the Ranlib:GetPercentages(table: chanceDictionary) ??

3 Likes

Sure thing!

--input
local chanceDictionary = {
    Common = 3,
    Uncommon = 1,
}

local percentages = Ranlib:GetPercentages(chanceDictionary)
print(percentages)
--output
{
    Common: 25 --25%
    Uncommon: 75 --75%
}

You can use this to display the probabilities of getting a certain result.

1 Like
function AddRandomFood(zone: BasePart)
    local Rand = RandomModule.new()
    local pos = Rand:NextBox(zone.Size)
    local randomPos = Rand:NextInteger(1, #Meshes)
    print(randomPos)
    print(Meshes[randomPos])
end
function Start()
    for _, v in pairs(CollectionService:GetTagged("Zones")) do
        for i = 1, math.random(20, 30) do
            AddRandomFood(v)
        end
    end
end

This keeps printing the same thing…

1 Like

You should use Knuth Float Random, it’s a great way to get pseudo-random numbers out of a seed you can specify, here’s an implementation:

local mod = math.fmod
local floor = math.floor
local abs = math.abs
local B =  4000000

function srandom( seedobj, fVal1, fVal2 )
	local ma = seedobj.ma
	local seed = seedobj.seed
	local mj, mk
	if seed < 0 or not ma then
		ma = {}
		seedobj.ma = ma
		mj = abs( 1618033 - abs( seed ) )
		mj = mod( mj, B )
		ma[55] = mj
		mk = 1
		for i = 1, 54 do
			local ii = mod( 21 * i,  55 )
			ma[ii] = mk
			mk = mj - mk
			if mk < 0 then mk = mk + B end
			mj = ma[ii]
		end
		for k = 1, 4 do
			for i = 1, 55 do
				ma[i] = ma[i] - ma[ 1 + mod( i + 30,  55) ]
				if ma[i] < 0 then ma[i] = ma[i] + B end
			end
		end
		seedobj.inext = 0
		seedobj.inextp = 31
		seedobj.seed = 1
	end -- if
	local inext = seedobj.inext
	local inextp = seedobj.inextp
	inext = inext + 1
	if inext == 56 then inext = 1 end
	seedobj.inext = inext
	inextp = inextp + 1
	if inextp == 56 then inextp = 1 end
	seedobj.inextp = inextp
	mj = ma[ inext ] - ma[ inextp ]
	if mj < 0 then mj = mj + B end
	ma[ inext ] = mj
	local temp_rand = mj / B
	if fVal2 then
		return floor( fVal1 + 0.5 + temp_rand * ( fVal2 - fVal1 ) )
	elseif fVal1 then
		return floor( temp_rand * fVal1 ) + 1
	else
		return temp_rand
	end
end

-- Note: seedobj must be a table with a field named `seed`;
-- this field must be negative; after the first number has
-- been generated, the seedobj table will be populated with
-- additional state needed to generate numbers; changing its
-- `seed` field to a negative number will reinitialize the
-- generator and start a new pseudorandom sequence.
return srandom

1 Like

This is a bug. Just put the local Rand = RandomModule.new() outside the function for now. I should be able to fix this really soon.

The First Patch Has Arrived!

  • Fixed a bug where not specifying a seed would default to the same seed
  • Ranlib now returns a pre-made wrapper rather than the library itself, allowing you to skip the hassle of creating the wrapper yourself if you just want random numbers quickly. Here’s an example:
--old code
local ranlib = require(path.to.Ranlib)
local rand = ranlib.new()

local x = rand:NextNumber()
--new code
local ranlib = require(path.to.Ranlib)
--local r = ranlib.new() --this still works!

local x = ranlib:NextNumber()

Update Ranlib by grabbing it from the toolbox.

Are there any benefits to using this as opposed to Random.new()?

Random is definetely better than math.random, but Im not sure the benefits of this. I suppose it’s another way to generate random numbers based on a seed?

New Feature, String Hashing!

  • Added a new static method: Ranlib.StringHash(key: any): int32, which generates a hash between 0 and the 32 bit integer limit using a string. If the key passed is not a string, it will call tostring() on it before generating the hash. This can be used for generating a seed out of non-integer values, such as tables, vectors, etc.

Examples:

print(Ranlib.StringHash("sus") --> 1486553088
print(Ranlib.StringHash("Sus") --> 1928435969
print(Ranlib.StringHash(Vector3.new(0, 0, 0)) --> 1419247873
print(Ranlib.StringHash(Vector3.new(0, 0, 1)) --> 601948417
print(Ranlib.StringHash(0) --> 1392846849
print(Ranlib.StringHash("hiaF7, {8nEFo+c3X,+X") --> 257

Update Ranlib by grabbing it from the toolbox.

1 Like

This Would Help Me With ALOT of things that my next module system can use!

1 Like

Anti-Repetition is Here!

  • Added simple anti-repetition functionality. It’s pretty basic for now and doesn’t affect every single method, but here are the ones that it does:

:NextInterger
:NextString
:NextName
These I want to add to the list in the near future
:NextEnum
:NextMaterial
:NextSelect
:NextKey

local x = Ranlib.Quantum.NextNumber(0, 10) --returns 1 real number between 0 and 10

Markov Speed-up

I wanted to take a little break after working on BytExecutor for months on end, so I had some free time to work on this little module again. I fix a few problems I found annoying, so here they are:


  • Significantly optimized :NextName() and :NextChance(). These optimizations can be accessed by calling
    :LoadNextNameState(markovChain: MarkovChain?): NameState
    and
    :LoadNextChanceState(chanceDictionary: {[string]: number}): ChanceState
    These behave as little “offshoots” of the main Ranlib object that store their state. Here’s an example if you’re confused by what I mean:
local Ranlib = require(path.to.Ranlib)
local rand = Ranlib.new()

local nameState = rand:LoadNextNameState()

--you can call :NextName on the NameState
local name = nameState:NextName(6)
local name2 = nameState:NextName(7)
  • Added even more randomness methods such as :NextTriangular(), :NextBiasedBoolean(), :NextAxis2D(), :NextAxis3D(), :NextFlatAngle(), and :NextCircle() which are more specialized and niche. I’ll explain these in more detail in the main post when I can.
  • Added some optimizations. Roblox has since added a new method to the Random object that Ranlib now uses.
  • Added a new method, :HashString(). This directly replaces the old :StringHash() that Ranlib once used. The old string hash function was home-made a frankly did more than what it was suppose to do (I had made sure that the output seemed random and unpredictable, but that was actually unnecessary, so that was a massive waste of time). This new function is less complex while still largely serving the same role the old one did.

P.S. StringHash is still usable, just deprecated

  • Added Luau typechecking.
  • Updated a few existing methods

This will be really useful in much of my games where I mostly use RNG for loot, thanks

Worley Noise

Worley

A visualization of Worley noise.


  • Added Worley Noise to Ranlib. There are two versions of Worley Noise provided, .WorleyNoise2D(x, y, seed) and .WorleyNoise3D(x, y, z, seed) which behave differently from each other
  • Added :NextBrickColor().
  • Restored the old method of hashing strings, which can be used by calling .OldHashString(key)

2 Likes

Did you make this through parts? or changing colors of frames?

I used parts. It was a demonstration for my 2D Worley noise implementation.