0

I'm building a word game. One of the functions I need is a function that receives a word and replaces several words with (_) and gives the incomplete word as output. I want the number of words to be replaced and the location of those words to be chosen randomly. The code I wrote, although it uses for, is only able to replace one word. What changes should I make in the for part of the code that has the ability to move several words? for example : "laptop" => "l_pt_p"

    function wordToIncomplete(word) {
    let randomNumber = Math.floor(Math.random() * 3) + 1
    let _randomNumber = Math.floor(Math.random() * word.length)
    let _word = ""; 
    
    for (let index = 0; index < randomNumber; index++) {
        
        _word = word.replace(word[_randomNumber], '_');
        
    }
    return _word 
   }
  • Each time through the loop you're doing the replacement on the original word, not the result of the previous replacement. You should do `word = word.replace(...)` – Barmar Mar 26 '22 at 09:05
  • 3
    It's really confusing that you have two variables with almost identical names: `randomNumber` and `_randomNumber`. Give them names that describe what they're used for. – Barmar Mar 26 '22 at 09:07
  • dont quiet understand... if you pass in an "aaaaa", the function will returns "_____". is this what you want?.. and what's the loop for? – yueyinqiu Mar 26 '22 at 09:08
  • "I want the number of words to be replaced /.../ for example : 'laptop' => 'l_pt_p'" - did you mean letters or actually words? What I quoted contradict each other. – Rickard Elimää Mar 26 '22 at 10:17

4 Answers4

1

I think your problem is you did not put your _randomNumber in the loop to re-generate your removed character index

function wordToIncomplete(word) {
  let randomNumber = Math.floor(Math.random() * 3) + 1
  let _word = word;

  for (let index = 0; index < randomNumber; index++) {
    let _randomNumber = Math.floor(Math.random() * _word.length)
    _word = _word.replace(_word[_randomNumber], '_');

  }
  return _word
}

const testingWords = "testing words"
console.log(wordToIncomplete(testingWords))

But with this solution, I think it will encounter another problem that it may check the same character which is already replaced earlier

Therefore, I modified your code a bit with while loop

function wordToIncomplete(word) {
  let randomNumber = Math.floor(Math.random() * 3) + 1
  let _word = word;

  let index = 0;
  while (index < randomNumber) {
    let _randomNumber = Math.floor(Math.random() * _word.length)
    if (_word[_randomNumber] === '_') { // we don't need to replace the checked words
      continue;
    }
    _word = _word.replace(_word[_randomNumber], '_');
    index++;
  }
  return _word
}

const testingWords = "testing words"
console.log(wordToIncomplete(testingWords))

By the way, you also did not assign value for _word, so I changed it to

let _word = word
Nick Vu
  • 14,512
  • 4
  • 21
  • 31
  • Could you check it again? I tried it here and modified my answer a bit https://jsfiddle.net/6gnh17a3/ @mehrankhalili – Nick Vu Mar 26 '22 at 09:27
1

Yes, as @Barmar mentioned, naming is important.


What changes should I make in the for part of the code that has the ability to move several words

The problem here is that _randomNumber is always same during the loop.

function wordToIncomplete(word) {
  const randomNumberOfCharactersToBeReplaced =
    Math.floor(Math.random() * word.length) + 1;

  let result = word;
  for (let i = 0; i < randomNumberOfCharactersToBeReplaced; i++) {
    // suppose we don't care about whether the character is already replaced or not.
    const randomIndexToBeReplaced = Math.floor(Math.random() * word.length);

    result[randomIndexToBeReplaced] = "_";
  }
  return result;
}
Ernest
  • 174
  • 7
1

The example returns an array of letters which is easier to work with, but if for some reason you want a string, do the following to the last line:

return chars.join('');

Note: this example actually adjusts dynamically the number of letters to be replaced which is from 30% to 60% of word.length.

Details are commented in example below

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

// Random integer range function
const randRng = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;

const fragWord = word => {
  /*
  The result of the following expressions is a random number that's 
  within the range of 30% to 60% of total length of >word<
  >word< string is converted into an array of letters called >chars<
  */
  const size = word.length;
  const lo = Math.ceil(0.3 * size);
  const hi = Math.ceil(0.6 * size);
  let qty = randRng(lo, hi);
  let chars = word.split('');

  /*
  At each iteration of >chars< a random index number is generated. 
  If there's a '_' at that index, the current iteration is skipped
  and qty increases by 1 to compensate.
  Otherwise the letter at that index is replaced with a '_'
  */
  skip:
    for (let i = 0; i < qty; i++) {
      let index = randRng(0, size - 1);
      let char = chars.at(index);
      if (char === '_') {
        qty = qty + 1;
        continue skip;
      }
      chars[index] = '_';
    }
  return chars;
};

log(fragWord('fragment'));
log(fragWord('appearance'));
log(fragWord('institutionalization'));
log(fragWord('institutionalization'));
zer00ne
  • 41,936
  • 6
  • 41
  • 68
0

Here is my take on it:

function shfl(array) { // Durstenfeld shuffle, based on Fisher-Yates
  for (let i = array.length - 1; i > 0; i--) {
   const j = Math.floor(Math.random() * (i + 1));
   [array[i],array[j]]=[array[j],array[i]];
  }
  return array;
}
function getWd(word) {
  const n=~~(Math.random()*3)+1, // 1...3
   wa=word.split(""), // word as char-array
   pos=shfl(wa.map((_,i)=>i))     
      .slice(0,n); // 1...3 character positions to be replaced by _
  pos.forEach(p=>wa[p]="_")
  return wa.join("");
}

console.log(
 "And here comes my supercalifragilisticexpialidocious word I want to process".split(" ")
 .map(getWd).join(" ")
);

I use the Durstenfeld shuffle to pick out random character positions of each word.

In getWd() I split the word into an array wa. This array is then the base for finding 1..3 positions (pos) to be replaced by _. After replacing the positions I join("") the characters in wa again and return them as the changed word.

Another expression I'd like to explain is

~~(Math.random()*3)+1

The ~ operator ("bitwise negation") will implicitly convert any number into an integer (similar to Math.floor()). By applying it twice (~~) the actual bitwise negation will be reversed and the result is thus a shorthand for Math.floor().

Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43