Reputation: 11
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
}
Upvotes: 0
Views: 118
Reputation: 43853
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'));
Upvotes: 1
Reputation: 28196
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()
.
Upvotes: 0
Reputation: 15510
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
Upvotes: 1
Reputation: 342
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;
}
Upvotes: 1