Precise Anagram Module

This is an Anagram Module. It can calculate the amount of permutations of ANY given word.
Some pros:

  • its mindbogglingly fast (few microseconds per word)
  • it supports words that are very long (even above 150 or 170)
  • it can calculate permutation amounts up until 10^308 (ieee 754 limit)
  • you can add in numbers and other special symbols to it if you’d like lol

its not case sensitive btw

--!nocheck
local Anagrams = {}
local ReplicatedStorage = game:GetService("ReplicatedStorage")

-- @ Anagrams.new(...) --> {...}
-- @ constructs a new object to handle anagram calculations on a given word
-- @ word: string
-- ### NOT CASE SENSITIVE ###
function Anagrams.new(word: string) : {}
	local self = {}

	--> Validate the word
	if typeof(word) ~= "string" then
		return error(`Expected type 'string' for Argument 1, got type '{typeof(word)}'`)
	end

	word = word:lower()

	-- # Set up the object
	self.Word = word
	self.PermutationAmount = 0
	self.Size = #word
	self.Characters = string.split(word, "")

	--> Factorial function for further calculation
	local function fat(number: number)
		if typeof(number) ~= "number" then
			return error(`Expected type 'number' for Argument 1, got type '{typeof(number)}'`)
		end 

		local product = 1
		for anc = 1, number do
			product *= anc
		end

		return product
	end

	--> Returns new object with precise permutation amount
	function self:Calculate()
		local TIME_ELAPSED = os.clock()

		-- !x and denominator (temporary 1)
		local FRAC_N = fat(self.Size)
		local FRAC_D = 1

		--> Adjust a frequency map for each character
		local FREQUENCY_MAP = {}

		for _, Character in ipairs(self.Characters) do
			FREQUENCY_MAP[Character] = (FREQUENCY_MAP[Character] or 0) + 1
		end

		for _, Count in pairs(FREQUENCY_MAP) do
			FRAC_D *= fat(Count)
		end

		--> x! / (a!b!...y!z!)
		self.PermutationAmount = FRAC_N / FRAC_D

		--> Debug: Returns ellapsed time
		self.TimeElapsedForLastCalculation = os.clock() - TIME_ELAPSED

		return self
	end

	--> Extra function for displaying any further information
	function self:DisplayInfo()
		local CanConvertToAString, _ = pcall(function()
			return tostring(self.PermutationAmount)
		end)

		if self.PermutationAmount > 10^308 or not CanConvertToAString then
			return `The permutation amount surpasses IEEE 754 \n (100 Uncentillion or Googol*Googol*Googol*10^8)`
		end
		return `The word is '{word}' \n The word size is {self.Size} \n The permutation amount is {self.PermutationAmount})}\n Time elapsed: ` .. self.TimeElapsedForLastCalculation
	end

	return self
end

return Anagrams

Theres also an implementation of it in this uncopylocked game here

7 Likes

(While theres not much utility to it I felt like it would be very insightful to share it)