Could you just use two digits for every letter?
00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
I wrote a module script for this. The module has conversion functions for converting the number code to different data types so you can use the module regardless of whether the number code is originally defined as a single number, a string or an array containing the number code of each letter.
You can safely use it even with player-inputted number codes because the functions return not only the result but also a success boolean. If the success boolean is false, the code was invalid (and thus the returned result shouldn’t be used).
The module:
--!strict
local AlphabetNumberCodeModule = {}
local alphabetString: string = "zabcdefghijklmnopqrstuvwxy"
local alphabetArray: {string} = table.create(26)
for i: number = 1, 26 do
alphabetArray[i] = string.sub(alphabetString, i, i)
end
--== validation functions
function AlphabetNumberCodeModule.validateNumberCodeOfLetter(numberCodeOfLetter: number): boolean
if numberCodeOfLetter < 0 or numberCodeOfLetter > 25 or math.floor(numberCodeOfLetter) ~= numberCodeOfLetter then
return false
end
return true
end
function AlphabetNumberCodeModule.validateNumberCodesOfLetters(numberCodesOfLetters: {number}, numberOfLetters: number): boolean
if #numberCodesOfLetters ~= numberOfLetters then
--error(`Incorrect number of number codes of letters. Number of number codes: {#numberCodesOfLetters}; number of letters: {numberOfLetters}.`)
return false
end
for _, numberCodeOfLetter: number in numberCodesOfLetters do
local isNumberCodeOfLetterValid: boolean = AlphabetNumberCodeModule.validateNumberCodeOfLetter(numberCodeOfLetter)
if not isNumberCodeOfLetterValid then
return false
end
end
return true
end
function AlphabetNumberCodeModule.validateNumberCodeDefinedAsSingleNumber(numberCodeAsSingleNumber: number, numberOfLetters: number): boolean
if numberCodeAsSingleNumber < 0 or numberCodeAsSingleNumber >= 10^(2 * numberOfLetters) or numberCodeAsSingleNumber ~= math.floor(numberCodeAsSingleNumber) then
return false
end
for i: number = numberOfLetters, 1, -1 do
-- Remainder when dividing by 100.
-- This gives a number with the last two digits of numberCode
-- without having to do string operations
local numberCodeOfLetter: number = numberCodeAsSingleNumber % 100
local isNumberCodeOfLetterValid: boolean = AlphabetNumberCodeModule.validateNumberCodeOfLetter(numberCodeOfLetter)
if not isNumberCodeOfLetterValid then
return false
end
-- floor division by 100 (so for example if numberCode was 1125, it would be 11 after this operation)
-- This cuts of the last two digits (that were used to get the letter of this iteration) of the number
-- without having to do string operations
numberCodeAsSingleNumber //= 100
end
return true
end
function AlphabetNumberCodeModule.validateNumberCodeDefinedAsString(numberCodeAsString: string, numberOfLetters: number): boolean
if #numberCodeAsString ~= 2 * numberOfLetters then
--error("invalid code length")
return false
end
if string.match(numberCodeAsString, "%d+") ~= numberCodeAsString then
--error("The code contains something else than just digit characters.")
return false
end
local numberCodeAsSingleNumber: number = tonumber(numberCodeAsString) :: number
local isNumberCodeAsSingleNumberValid: boolean = AlphabetNumberCodeModule.validateNumberCodeDefinedAsSingleNumber(numberCodeAsSingleNumber, numberOfLetters)
if not isNumberCodeAsSingleNumberValid then
return false
end
return true
end
--== A function for splitting a number code defined as a single number to an array containing number codes of letters
function AlphabetNumberCodeModule.splitNumberCodeIntoNumberCodesOfLetters(numberCode: number, numberOfLetters: number): (boolean, {number})
local isNumberCodeValid: boolean = AlphabetNumberCodeModule.validateNumberCodeDefinedAsSingleNumber(numberCode, numberOfLetters)
if not isNumberCodeValid then
return false, {}
end
local numberCodesOfLetters: {number} = table.create(numberOfLetters)
for i: number = numberOfLetters, 1, -1 do
-- There's explanation for this math in validateNumberCodeDefinedAsSingleNumber.
local numberCodeOfLetter: number = numberCode % 100
numberCodesOfLetters[i] = numberCodeOfLetter
numberCode //= 100
end
return true, numberCodesOfLetters
end
--== Functions for converting number code to different data types
-- This function adds a zeros to the start if necessary so that the length of the string is 2 * numberOfLetters.
function AlphabetNumberCodeModule.convertNumberCodeDefinedAsSingleNumberToString(numberCodeAsSingleNumber: number, numberOfLetters: number): (boolean, string)
local isNumberCodeAsSingleNumberValid: boolean = AlphabetNumberCodeModule.validateNumberCodeDefinedAsSingleNumber(numberCodeAsSingleNumber, numberOfLetters)
if not isNumberCodeAsSingleNumberValid then
return false, ""
end
return true, string.format(`%0{2 * numberOfLetters}i`, numberCodeAsSingleNumber)
end
-- This function is pretty much tonumber with custom validation
function AlphabetNumberCodeModule.convertNumberCodeDefinedAsStringToSingleNumber(numberCodeAsString: string, numberOfLetters: number): (boolean, number)
local isNumberCodeAsStringValid: boolean = AlphabetNumberCodeModule.validateNumberCodeDefinedAsString(numberCodeAsString, numberOfLetters)
if not isNumberCodeAsStringValid then
return false, -1
end
local numberCodeAsSingleNumber: number = tonumber(numberCodeAsString) :: number
return true, numberCodeAsSingleNumber
end
function AlphabetNumberCodeModule.convertNumberCodeDefinedAsArrayOfNumberCodesOfLettersToSingleNumber(numberCodesOfLetters: {number}, numberOfLetters: number): (boolean, number)
local isArrayOfNumberCodesOfLettersValid: boolean = AlphabetNumberCodeModule.validateNumberCodesOfLetters(numberCodesOfLetters, numberOfLetters)
if not isArrayOfNumberCodesOfLettersValid then
return false, -1
end
local number: number = 0
for i: number, numberCodeOfLetter: number in numberCodesOfLetters do
number += numberCodeOfLetter * 10^(2 * (numberOfLetters - i))
end
return true, number
end
--== Functions for Converting number code to letter code.
function AlphabetNumberCodeModule.convertNumberCodesOfLettersToLetterCode(numberCodesOfLetters: {number}, numberOfLetters: number): (boolean, string)
local isArrayOfNumberCodesOfLettersValid: boolean = AlphabetNumberCodeModule.validateNumberCodesOfLetters(numberCodesOfLetters, numberOfLetters)
if not isArrayOfNumberCodesOfLettersValid then
return false, ""
end
local letters: {string} = table.create(numberOfLetters)
for i: number, numberCodeOfLetter: number in numberCodesOfLetters do
local letter: string = alphabetArray[numberCodeOfLetter + 1]
letters[i] = letter
end
local letterCode: string = table.concat(letters)
return true, letterCode
end
function AlphabetNumberCodeModule.convertNumberCodeDefinedAsSingleNumberToLetterCode(numberCode: number, numberOfLetters: number): (boolean, string)
local splitSuccess: boolean, numberCodesOfLetters: {number} = AlphabetNumberCodeModule.splitNumberCodeIntoNumberCodesOfLetters(numberCode, numberOfLetters)
if not splitSuccess then
return false, ""
end
return AlphabetNumberCodeModule.convertNumberCodesOfLettersToLetterCode(numberCodesOfLetters, numberOfLetters)
end
function AlphabetNumberCodeModule.convertNumberCodeDefinedAsStringToLetterCode(numberCodeAsString: string, numberOfLetters: number): (boolean, string)
local conversionSuccess: boolean, numberCodeAsSingleNumber: number = AlphabetNumberCodeModule.convertNumberCodeDefinedAsStringToSingleNumber(numberCodeAsString, numberOfLetters)
if not conversionSuccess then
return false, ""
end
return AlphabetNumberCodeModule.convertNumberCodeDefinedAsSingleNumberToLetterCode(numberCodeAsSingleNumber, numberOfLetters)
end
return AlphabetNumberCodeModule
A test script
--!strict
local AlphabetNumberCodeModule = require(script.Parent.AlphabetNumberCodeModule)
local numberOfLetters: number = 3
-- You could write these without the leading zeros.
-- The leading zeros won't affect the bytecode.
local exampleNumberCodesAsSingleNumbers: {number} = {
000010,
101100,
040326 -- invalid (26 > 25)
}
local exampleNumberCodesAsStrings: {string} = {
"01a213", -- invalid (unallowed character "a")
"", -- invalid (invalid length)
"031221"
}
local exampleNumberCodesAsArraysOfNumberCodesOfLetters: {{number}} = {
{00, 08, 11},
{65, 10, 13}, -- invalid (65 > 25)
{12, 00, 00}
}
print("--== Examples defined as single numbers:")
for _, exampleNumberCodeAsSingleNumber: number in exampleNumberCodesAsSingleNumbers do
local successOfConvertingToString: boolean, exampleNumberCodeAsString: string = AlphabetNumberCodeModule.convertNumberCodeDefinedAsSingleNumberToString(exampleNumberCodeAsSingleNumber, numberOfLetters)
if not successOfConvertingToString then
print(`{exampleNumberCodeAsSingleNumber}: ERROR.`)
continue
end
local _, letterCode: string = AlphabetNumberCodeModule.convertNumberCodeDefinedAsSingleNumberToLetterCode(exampleNumberCodeAsSingleNumber, numberOfLetters)
print(`{exampleNumberCodeAsString}: {letterCode}`)
end
print("--== Examples defined as strings:")
for _, exampleNumberCodeAsString: string in exampleNumberCodesAsStrings do
local successOfConversionToLetterCode: boolean, letterCode: string = AlphabetNumberCodeModule.convertNumberCodeDefinedAsStringToLetterCode(exampleNumberCodeAsString, numberOfLetters)
if not successOfConversionToLetterCode then
print(`{exampleNumberCodeAsString}: ERROR.`)
continue
end
print(`{exampleNumberCodeAsString}: {letterCode}`)
end
local function convertArrayOfNumberCodesOfLettersToString(numberCodesOfLetters: {number}): string
local letterNumberCodeStrings: {string} = table.create(#numberCodesOfLetters)
for i: number, numberCodeOfLetter: number in numberCodesOfLetters do
letterNumberCodeStrings[i] = string.format("%02i", numberCodeOfLetter)
end
local arrayString: string = table.concat(letterNumberCodeStrings, ", ")
return arrayString
end
print("--== Examples defined as arrays of number codes of letters:")
for _, exampleNumberCodeAsArrayOfNumberCodesOfLetters: {number} in exampleNumberCodesAsArraysOfNumberCodesOfLetters do
local arrayString: string = convertArrayOfNumberCodesOfLettersToString(exampleNumberCodeAsArrayOfNumberCodesOfLetters)
local successOfConversionToLetterCode: boolean, letterCode: string = AlphabetNumberCodeModule.convertNumberCodesOfLettersToLetterCode(exampleNumberCodeAsArrayOfNumberCodesOfLetters, numberOfLetters)
if not successOfConversionToLetterCode then
print(`{arrayString}: ERROR.`)
continue
end
print(`{arrayString}: {letterCode}`)
end
print("--== Conversion tests")
local numberToStringSuccess: boolean, numberCodeAsString: string = AlphabetNumberCodeModule.convertNumberCodeDefinedAsSingleNumberToString(000123, numberOfLetters)
print(`number to string: {if numberToStringSuccess then numberCodeAsString else "ERROR"}`)
local stringToNumberSuccess: boolean, stringCodeAsNumber: number = AlphabetNumberCodeModule.convertNumberCodeDefinedAsStringToSingleNumber("000123", numberOfLetters)
print(`string to number: {if stringToNumberSuccess then stringCodeAsNumber else "ERROR"}`)
local arrayToNumberSuccess: boolean, arrayCodeAsNumber: number = AlphabetNumberCodeModule.convertNumberCodeDefinedAsArrayOfNumberCodesOfLettersToSingleNumber({23, 00, 14}, numberOfLetters)
print(`array to number: {if arrayToNumberSuccess then arrayCodeAsNumber else "ERROR"}`)