'How to filter vowel and consonant letters generated from a random string

I am making a word game that picks 8 random letters from the alphabet and the player must find words that use these letters. I must find out a way to make the letters picked always contain 3 vowels and 5 consonants. I would appreciate your help

Here is the code I am using to pick the random letters for the game

function makeid(length) {
  var result           = '';
  var characters       = 'aaabcdeeefghiiijklmnooopqrstuuuvwxyz';
  var charactersLength = characters.length;
  for (var i = 0; i < length; i++) {
    let letter = characters.charAt(Math.floor(Math.random() * charactersLength));
    while (result.match(letter)) {
      letter = characters.charAt(Math.floor(Math.random() * charactersLength));
    }
    result += letter;
  }
  return result;
}

console.log("Id of 8 characters", makeid(8))


Solution 1:[1]

@Lars answer is almost perfect, the only problem is that the final string is not truly shuffled.

I suggest you just create two arrays: random vowels and random consonants and then just shuffle them using Fisher-Yates' algorithm.

function getRandomCharsFromString(str, length) {
    return Array.from({length}, () => {
      return str[Math.floor(Math.random() *  str.length)]
    });
}

function shuffle(str) {
  var a = str.split(""),
    n = a.length;

  for (var i = n - 1; i > 0; i--) {
    var j = Math.floor(Math.random() * (i + 1));
    // Swap them with ES6 destructuring magic
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a.join("");
}

function getRandomString() {
  const vowels = 'aeiou';
  const consonants = 'bcdfghjklmnpqrstvwxyz';

  const randomVowels = getRandomCharsFromString(vowels, 3);
  const randomConsonants = getRandomCharsFromString(consonants, 5);
  
  const randomWord = [...randomVowels, ...randomConsonants].join('')
  return shuffle(randomWord)
}


console.log('random string:', getRandomString())

No repeated letters

You mentioned you don't want repeated letters; many words in English have duplicate letters. Why is that a requirement?

You can shuffle the vowels and consonants and get the first x characters from that string.

// This version makes sure characters are not repeated
function getRandomCharsFromString(str, length) {
    return shuffle(str).slice(0, length);
}

function shuffle(str) {
  var a = str.split(''),
    n = a.length;

  for (var i = n - 1; i > 0; i--) {
    var j = Math.floor(Math.random() * (i + 1));
    // Swap them with ES6 destructuring magic
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

function getRandomString() {
  const vowels = 'aeiou';
  const consonants = 'bcdfghjklmnpqrstvwxyz';

  const randomVowels = getRandomCharsFromString(vowels, 3);
  const randomConsonants = getRandomCharsFromString(consonants, 5);
  
  const randomWord = [...randomVowels, ...randomConsonants].join('')
  return shuffle(randomWord).join('')
}


console.log('random string:', getRandomString())

Solution 2:[2]

It's a lot of code, but this works for me.

The function begins with a for-loop, which generates 8 different letters. inside of that loop, Math.random() makes it a 37.5% chance that a vowel will be added to the randomArray, and 62.5% that a consonant will be added (8 characters from which 3 are vowels, so 3 / 8 = 0.375).

when that is done 8 times (cuz of the for loop), the array will be turned into a string, and the function will return the string (which is by then an 8-digit letter code with 3 vowels and 5 consonants).

I hope this explanation helps(;

function getRandomString() {
  const vowels = 'aeiou'
  const consonants = 'bcdfghjklmnpqrstvwxyz'
  let randomArray = []
  let amountOfVowels = 0
  let amountOfConsonants = 0

  for (let i = 0; i < 8; i++) {
    if (Math.random() < 0.375 && amountOfVowels < 3) addVowel()
    else if (amountOfConsonants < 5) addConsonant()
    else addVowel()
  }

  function addVowel() {
    randomArray.push(vowels[Math.floor(Math.random() *
      vowels.length)])
    amountOfVowels++
  }

  function addConsonant() {
    randomArray.push(consonants[Math.floor(Math.random() *
      consonants.length)])
    amountOfConsonants++
  }
  let finalString = ''
  for (let i = 0; i < 8; i++) {
    finalString += randomArray[i]
  }
  return finalString;
}

console.log('random string:', getRandomString())

Solution 3:[3]

  1. Have one array of consonants and one array for vowels.

  2. Use a shuffling function, here's a terse one liner:

    const shuffle = array => array.sort(() => Math.random() - 0.5);
    
  3. The function above will return a given array in a random order, so you'll need to shorten each array by 5 (consonants) and 3 (vowels):

    let C = shuffle(consonants);
    let V = shuffle(vowels); 
    
    C.length = 5;
    V.length = 3;
    

    Easy ?

// Utility Function (optional)
const log = data => console.log(JSON.stringify(data));

const consonants = ["B", "C", "D", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "V", "W", "X", "Y", "Z"];
const vowels = ["A", "E", "I", "O", "U"];

const shuffle = array => array.sort(() => Math.random() - 0.5);

let C = shuffle(consonants);
let V = shuffle(vowels); 

C.length = 5;
V.length = 3;

const result = shuffle(V.concat(C));

log(result);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3