Line data Source code
1 : /// Random two-word name generator for new scripts.
2 : ///
3 : /// Instead of naming every new script "script", we compose a memorable "<adjective>_<animal>" base
4 : /// (e.g. "brave_otter") in the spirit of whimsical generated names. The two curated
5 : /// word lists give ADJECTIVES.length * ANIMALS.length combinations, so collisions on a single page
6 : /// are rare; when one does occur the caller's uniqueScriptBase still disambiguates with a "-2" suffix.
7 :
8 1 : const ADJECTIVES: readonly string[] = [
9 1 : 'amber', 'ancient', 'autumn', 'azure', 'bold', 'brave', 'breezy', 'bright',
10 1 : 'brisk', 'calm', 'clever', 'cosmic', 'crimson', 'crisp', 'curious', 'daring',
11 1 : 'dawn', 'deep', 'eager', 'electric', 'emerald', 'fancy', 'fearless', 'fierce',
12 1 : 'fluffy', 'frosty', 'gentle', 'gilded', 'golden', 'happy', 'hidden', 'humble',
13 1 : 'icy', 'indigo', 'jolly', 'keen', 'lively', 'lucid', 'lucky', 'mellow',
14 1 : 'merry', 'mighty', 'misty', 'nimble', 'noble', 'patient', 'placid', 'polished',
15 1 : 'proud', 'quiet', 'rapid', 'royal', 'rugged', 'rustic', 'scarlet', 'serene',
16 1 : 'silent', 'silver', 'sleek', 'snowy', 'solar', 'spry', 'stellar', 'sturdy',
17 1 : 'sunny', 'swift', 'tidy', 'tranquil', 'velvet', 'vivid', 'wandering', 'wise',
18 1 : 'witty', 'zesty',
19 1 : ];
20 :
21 1 : const ANIMALS: readonly string[] = [
22 1 : 'badger', 'bat', 'bear', 'beaver', 'bison', 'cheetah', 'cobra', 'condor',
23 1 : 'cougar', 'coyote', 'crane', 'cricket', 'dingo', 'dolphin', 'eagle', 'falcon',
24 1 : 'ferret', 'finch', 'fox', 'gazelle', 'gecko', 'gibbon', 'heron', 'ibex',
25 1 : 'iguana', 'impala', 'jackal', 'jaguar', 'kestrel', 'koala', 'lemur', 'leopard',
26 1 : 'lynx', 'magpie', 'mantis', 'marmot', 'marten', 'meerkat', 'mole', 'moose',
27 1 : 'narwhal', 'newt', 'ocelot', 'orca', 'osprey', 'otter', 'owl', 'panda',
28 1 : 'panther', 'pelican', 'penguin', 'puffin', 'puma', 'quail', 'rabbit', 'raccoon',
29 1 : 'raven', 'salmon', 'seal', 'shark', 'sparrow', 'stoat', 'stork', 'tapir',
30 1 : 'teal', 'tiger', 'toucan', 'turtle', 'viper', 'vole', 'walrus', 'weasel',
31 1 : 'wolf', 'wombat',
32 1 : ];
33 :
34 : /// How many random combinations to try before giving up on finding a collision-free one. With a few
35 : /// thousand combinations this practically never exhausts; the caller still de-duplicates afterwards.
36 1 : const MAX_ATTEMPTS = 32;
37 :
38 1 : function pick(list: readonly string[], rng: () => number): string {
39 1 : return list[Math.floor(rng() * list.length)];
40 1 : }
41 :
42 : /// Generate a random "<adjective>-<animal>" script base. If `taken` is given, retries a bounded number
43 : /// of times to avoid names already present; on exhaustion it returns a name regardless (the caller's
44 : /// uniqueScriptBase appends a numeric suffix to guarantee uniqueness). `rng` is injectable for tests.
45 1 : export function randomScriptName(taken?: ReadonlySet<string>, rng: () => number = Math.random): string {
46 1 : let candidate = `${pick(ADJECTIVES, rng)}_${pick(ANIMALS, rng)}`;
47 1 : if (!taken) return candidate;
48 1 : for (let attempt = 0; taken.has(candidate) && attempt < MAX_ATTEMPTS; ++attempt) {
49 1 : candidate = `${pick(ADJECTIVES, rng)}_${pick(ANIMALS, rng)}`;
50 : }
51 1 : return candidate;
52 1 : }
|