Skip to content

Instantly share code, notes, and snippets.

@jvgomg
Created April 28, 2025 07:16
Show Gist options
  • Save jvgomg/6fe46035103d6b7a7c9ebed1cea8c50f to your computer and use it in GitHub Desktop.
Save jvgomg/6fe46035103d6b7a7c9ebed1cea8c50f to your computer and use it in GitHub Desktop.
Generate a set of magic words using a Linear Congruential Generator
// Configurable LCG function
function lcg(seed: number, multiplier: number, increment: number, modulus: number) {
return function() {
seed = (multiplier * seed + increment) % modulus;
return seed;
};
}
export function generateWords(
words: string[],
seed: number,
wordsPerSet: number,
multiplier: number = Number(process.env.LCG_MULTIPLIER) || 1103515245,
increment: number = Number(process.env.LCG_INCREMENT) || 12345,
modulus: number = Number(process.env.LCG_MODULUS) || 2 ** 31
): string[] {
if (words.length === 0 || wordsPerSet <= 0) {
return [];
}
const totalCombinations = words.length ** wordsPerSet;
const requiredBits = Math.ceil(Math.log2(totalCombinations));
const random = lcg(seed, multiplier, increment, modulus);
const randomNumber = random() % totalCombinations;
let binaryString = randomNumber.toString(2).padStart(requiredBits, '0');
const splitSize = Math.floor(binaryString.length / wordsPerSet);
const selectedWords: string[] = [];
for (let i = 0; i < wordsPerSet; i++) {
const part = binaryString.slice(i * splitSize, (i + 1) * splitSize);
const index = parseInt(part, 2) % words.length;
selectedWords.push(words[index]);
}
return selectedWords;
}
export function wordsToSeed(
words: string[],
selectedWords: string[],
wordsPerSet: number
): number {
if (words.length === 0 || selectedWords.length !== wordsPerSet) {
throw new Error('Invalid input.');
}
const totalCombinations = words.length ** wordsPerSet;
const requiredBits = Math.ceil(Math.log2(totalCombinations));
const splitSize = Math.floor(requiredBits / wordsPerSet);
let binaryString = '';
for (const word of selectedWords) {
const index = words.indexOf(word);
if (index === -1) {
throw new Error(`Word '${word}' not found in the list.`);
}
let partBinary = index.toString(2).padStart(splitSize, '0');
binaryString += partBinary;
}
return parseInt(binaryString, 2);
}
// Example usage:
// const words = ['apple', 'banana', 'cherry', 'date', 'elderberry'];
// const seed = 42;
// const wordsPerSet = 2;
// const generatedWords = generateWords(words, seed, wordsPerSet);
// console.log(generatedWords);
// const reverseSeed = wordsToSeed(words, generatedWords, wordsPerSet);
// console.log(reverseSeed);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment