stopping random choose existing option - javascript

In my game, when the "next-question" button is clicked, it should choose a new word in the grid for the user to spell. It does this, but the problem is that instead of going to another word, sometimes the randomization brings it back to the word it is already on. I need to make it so that it chooses any other than the one its on.
//Next question click event
$('.next-question').on('click', function () {
$('td').removeClass('highlight-problem');
var r = rndWord;
while (r == rndWord) {
rndWord = Math.floor(Math.random() * (listOfWords.length));
}
//Adds and removes nesesary classes
$('td[data-word="' + listOfWords[rndWord].name + '"]').addClass('highlight-problem');
$('td[data-word=' + word + ']').removeClass('wrong-letter').removeClass('wrong-word').removeClass('right-letter');
var spellSpace = $('td[data-word="' + listOfWords[rndWord].name + '"]').hasClass('right-word');
if (spellSpace) {
$(".next-question").eq(($(".next-question").index($(this)) + 1) %$(".next-question").length).trigger("click");
} else {
$("#hintSound").attr('src', listOfWords[rndWord].audio);
hintSound.play();
$("#hintPic").attr('src', listOfWords[rndWord].pic);
$('#hintPicTitle').attr('title', listOfWords[rndWord].hint);
}
});

What's the value of rndWord before your while loop? It looks like a scoping issue - you either need to declare rndWord outside your function so it's preserved between calls or pass it in every time.
var rndWord;
function() {
//Next question click event
....
var r = rndWord;
while (r == rndWord) {
rndWord = Math.floor(Math.random() * (listOfWords.length));
}
After further clarification:
var currentWord;
function ClickEventHere() {
r = currentWord;
while (r == currentWord) {
nextIndex = Math.floor(Math.random() * (listOfWords.length));
currentWord = listOfWords[nextIndex];
}
...
}
There's no point in comparing an integer r with an array as you're doing in your while statement - you can either store the index or the word itself in a global and then check to make sure it's not being reused.
After this loop, currentWord will contain the next, different word

Find random word, compare to last found if the same find another. Provided you have a decent number of words it should be enough.

Related

Generating an array with 3 unique numbers

I'm trying to create an array with three unique random numbers between 1 and 14. I've found similar questions on Stackoverflow and used the code to help me create my existing code.
It works well most of the time, but occasionaly it will create an array with two of the same numbers. Here is the offending code:
function noDuplicates (sideRandom) {
sideArray.splice(sideRandom, 1);
let sideRandom2 = Math.floor(Math.random() * 14) + 1;
sideArray.push(sideRandom2);
console.log("I've had to add " + sideRandom2)
}
function sortNumbers(array) {
array.sort(function(a, b) {
return a - b;
});
}
document.getElementById("randomiser").addEventListener("click", function () {
for (let i = 0; sideArray.length <3; i++) {
let sideRandom = Math.floor(Math.random() * 14) + 1;
console.log(sideRandom);
if (sideArray.includes(sideRandom) === false) {
sideArray.push(sideRandom);
} else {
noDuplicates(sideRandom);
};
}
console.log(sideArray);
});
I suspect the issue is that sometimes the noDuplicates function generates the same random number as sideRandom, but I can't see a way around it. can you help?
Use set with while loop to make sure we got required number of unique random numbers
// Get unique random indexes
const random = (num, count) => {
const set = new Set();
while (set.size < count) {
set.add(Math.floor(Math.random() * num) + 1);
}
return [...set];
};
document.getElementById("randomiser").addEventListener("click", function () {
console.log(random(14, 3));
});
<button id="randomiser"> Get 3 random </button>
I take a look at your code: If there is a double you call noDuplicates and try to get a non double number but there you make some mistakes.
Why using Array#splice method? It will return the array without the first element (you don't user this result) and leave the original unchanged. So this line does anything. By the way why you want to delete the first element, youz didn't add the double random-number so there is anything do delete.
Afterwards you build another new randomnumber and push it to your array without checking. By this you get your dublettes.
Better way: If you finf a double set a flag on true and when you next add a number by this you can add your hint and reset the flag to false. So everything is one function.
document.getElementById("randomiser").addEventListener("click", function () {
let sideArray = [];
let double = false;
for (let i= 0; sideArray.length <3; i++) {
let sideRandom = Math.floor(Math.random() * 14) + 1;
console.log(sideRandom);
if (sideArray.includes(sideRandom) === false) {
if (double) {
double = false;
console.log("I've had to add " + sideRandom);
}
sideArray.push(sideRandom);
} else {
double = true;
}
}
console.log(sideArray.toString());
});
<button id='randomiser'>Click</button>
You can do this pretty easily with rando.js and slice. Plus, it's human-readable and cryptographically secure. randoSequence(1, 14) creates a shuffled array of all numbers from 1 through 14, and slice(0, 3) slices out the first three values from that shuffled array.
console.log(randoSequence(1, 14).slice(0, 3));
<script src="https://randojs.com/2.0.0.js"></script>

javascript: clicking numerical boxes - increment not working

using the code below, I've created a grid of buttons, 5x5, with random 1-25 numbers assigned to each button. They are to be clicked in numerical order, each's background turns red when clicked in the correct order. I can't use a global variable for this prompt. Without a global variable, I can't figure out how to increment the correctNumbers function which checks whether the right number is clicked each time. I think I'm missing something, a js function or something that would enable an incrementing variable declared within the incrementing function. I'm not looking for the whole explanation, just tips on functions i might not know about, and whether or not what i'm trying to do just isn't logicly possible.
<div id="numbers" class="hidden"></div>
<div id="youWon" class="hidden">You Won!</div>
The relevant JS:
... /**
* Gives the numbers a random order
* the "Fisher-Yates shuffle" found at: https://www.frankmitchell.org/2015/01/fisher-yates/
* #param {*} array
*/
const shuffle = (array) => {
let i = 0,
j = 0,
temp = null
for (i = array.length - 1; i > 0; i -= 1) {
j = Math.floor(Math.random() * (i + 1))
temp = array[i]
array[i] = array[j]
array[j] = temp
}
}
/**
* Generates an array of numbers 1-25
*/
const generateNums = () => {
document.getElementById("youWon").classList.toggle("hidden", "visible");
const numberArray = [];
for (let a = 1; a <= 25; a++) {
numberArray.push(a);
}
shuffle(numberArray);
let numEl = document.getElementById('numbers'); //write into html div id "numbers"
for (let b = 0; b <= 24; b++) { //loop to create button array
let newBtn = document.createElement('button'); //create buttons
newBtn.className = 'number'; //assign newBtns 'number' class
newBtn.innerText = numberArray[b]; //assign numbers to each button
numEl.appendChild(newBtn); //match with number elements in "numbers" array
newBtn.addEventListener("click", onNumberClick) //create function trigger
}
}
/**
* Creates a function to decide correct and incorrect clicks
* When a user clicks a number, if it is the next number in order, then it turns a different color for the remainder of the test
* If it is the wrong number, nothing happens
* #param {*} event
*/
const incrementNum = (correctNumber) => {
correctNumber++;
}
const onNumberClick = (event) => {
let correctNumber = 1; //start at 1
let numberVal = event.target; //apply it to clicks on the numbers
if (Number(numberVal.innerHTML) + 1 == incrementNum(correctNumber)) {
incrementNum(correctNumber);
numberVal.classList.add("red");
}
if (correctNumber == 26) {
document.getElementById("youWon").classList.toggle("visible"); //show win message if 25 is the last button and gets clicked
}
}
I would suggest that you count the number of elements in the DOM that have the class "red" and add 1... checking if the innerHTML is equal to that number to get the sequence right. So, instead of this:
if (Number(numberVal.innerHTML) + 1 == incrementNum(correctNumber)) {
incrementNum(correctNumber);
numberVal.classList.add("red");
}
You can have something like this:
if(Number(numberVal.innerHTML) == document.getElementsByClassName('red').length + 1) {
numberVal.classList.add("red");
}

Generating Two Numbers With a Specific Sum

I'm trying to generate two numbers with a specific sum. Here is my proposed method:
Edited: http://jsfiddle.net/KDmwn/274/
$(document).ready(function () {
function GenerateRandomNumber() {
var min = -13, max = 13;
var random = Math.floor(Math.random() * (max - min + 1)) + min;
return random;
}
var x = GenerateRandomNumber();
function GenerateRandomNumber2() {
var min2 = -13, max2 = 13;
var random2 = Math.floor(Math.random() * (max2 - min2 + 1)) + min2;
if ((random2 + x) == 0){
return random2};
}
var xx = GenerateRandomNumber2();
There's something wrong with the if ((random2 + x) = 0) line, as the code runs perfectly fine when it's removed. How can I modify this line so that the sum of the two numbers is 0? It would be most helpful if someone could modify the Jsfiddle that I've included. Thanks!
This is invalid:
if ((random2 + x) = 0){
You cannot assign something to an expression.
You probably meant to use the comparison operator (==), like this:
if ((random2 + x) == 0){
Are you trying to make it only output a second number that, when added to the first, equals 0? Because it actually already does that - but only if it gets it on the first try (try hitting refresh at least 30 times.) You need to tell it to keep re-choosing (looping) the second random number while the sum isn't 0:
function GenerateRandomNumber2() {
var min2 = -13,
max2 = 13;
var random2;
while ((random2 + x) !== 0) {
random2 = Math.floor(Math.random() * (max2 - min2 + 1)) + min2;
}
return random2;
}
http://jsfiddle.net/vL77hjp0/
To take this one step further, if I'm reading this right (if not ignore this) it looks like you might want to eventually choose a random sum and have it determine the required second number to be added. To do this, we would replace the 0 in our "while" loop with 'sum'. And 'sum' would have to be defined as a random number with a "max=x+13" and "min=x-13" (otherwise the random number may be too high/low for random2 to ever reach, causing the browser to crash.) [Or just remove the limits from random2.]
http://jsfiddle.net/fkuo54hc/
First, your GenerateRandomNumbers2 function returns undefined value other than in your if statement. So you need to return a value. I updated your fiddle and refactor some of your code.

How can I us a single var for multiple values?

I am trying to get random values, getting random array elements.
The problem that when i generate them, they are the same.
This may be a stupid question, but how can I get a random value for each instance.
my HTML looks like this
Our Array consists of:<br>
<span id="massParts"></span><br><br>
Generating a word from syllables:<br>
<span id="oneWord"></span><br><br>
Generating a sentence from several words<br>
<span id="oneSentence"></span>
What I am trying to achieve is getting a sentence of randomly generated words. I seethe only solution to create multiple words and then putting them together. But this is not the solution for a bigger text.
my script is:
<script>
// creating an array of syllables
var parts = ["ing", "er", "a", "on", "po", "i", "re", "tion"];
var partsAsString = parts.join(', ');
// display syllables array elements
document.getElementById("massParts").innerHTML = partsAsString;
// getting random element from an array
var a = Math.floor(Math.random() * parts.length);
var b = Math.floor(Math.random() * parts.length);
var c = Math.floor(Math.random() * parts.length);
// making a word with one, two and three syllables
var oneSylWord = parts[a];
var twoSylWord = parts[a]+parts[b];
var threeSylWord = parts[a]+parts[b]+parts[c];
//putting three words into an array
var newWord = [oneSylWord, twoSylWord, threeSylWord];
// taking one of those free words fron the new array
var randWord = newWord[Math.floor(Math.random() * newWord.length)];
// display a random 1,2,3 syllable word
document.getElementById("oneWord").innerHTML = randWord;
// generating a sentence
var sentence = randWord + " " + randWord + " " + randWord + ".";
document.getElementById("oneSentence").innerHTML = sentence;
</script>
I understand that I display the same var randWord and that causes the repetition. but how can I avoid using multiple variables for it.
Thank you.
here is a jsfiddle https://jsfiddle.net/2j9jpcoo/
Put the code into a function and call it multiple times to get a (potentially) different value every time it is called:
function getRandomValue(arr);
return arr[Math.floor(Math.random() * arr.length)];
}
var sentence = getRandomValue(newWord) + " " + getRandomValue(newWord) + " " + getRandomValue(newWord) + ".";
Functions allow you to organize and reuse code. From the above link:
Functions are the bread and butter of JavaScript programming. The concept of wrapping a piece of program in a value has many uses. It is a tool to structure larger programs, to reduce repetition, to associate names with subprograms, and to isolate these subprograms from each other.
I liked the following algorithm in generating random numbers, according to this article where it mentions it is even better in performance but to be honest I did not benchmark it but you could check this in jsfiddle demo, just run it and see the benchmark results
// the initial seed
Math.seed = 6;
// in order to work 'Math.seed' must NOT be undefined,
// so in any case, you HAVE to provide a Math.seed
Math.seededRandom = function(max, min) {
max = max || 1;
min = min || 0;
Math.seed = (Math.seed * 9301 + 49297) % 233280;
var rnd = Math.seed / 233280;
return min + rnd * (max - min);
}
I re-organized your code a bit and created some re-usable functions to get a different random word each time. In this case we can skip the variable and use the return value from the function directly:
// creating an array of syllables
var a, b, c, newWord;
var parts = ["ing", "er", "a", "on", "po", "i", "re", "tion", "con", "de", "sta"];
var partsAsString = parts.join(', ');
// display syllables array elements
document.getElementById("massParts").innerHTML = partsAsString;
function shuffleLetters() {
// getting random element from an array
a = Math.floor(Math.random() * parts.length);
b = Math.floor(Math.random() * parts.length);
c = Math.floor(Math.random() * parts.length);
var oneSylWord = parts[a];
var twoSylWord = parts[a]+parts[b];
var threeSylWord = parts[a]+parts[b]+parts[c];
//putting three words into an array
newWord = [oneSylWord, twoSylWord, threeSylWord];
}
function getRandomWord() {
shuffleLetters();
// taking one of those free words fron the new array
return newWord[Math.floor(Math.random() * newWord.length)];
}
// making a word with one, two and three syllables
shuffleLetters();
// display a random 1,2,3 syllable word
document.getElementById("oneWord").innerHTML = getRandomWord();
// generating a sentence
var sentence = getRandomWord() + " " + getRandomWord() + " " + getRandomWord() + ".";
document.getElementById("oneSentence").innerHTML = sentence;

do something when function executes Jquery

So I have a function that is recursive for inverting colors. Here is the code:
function invert(id,what){
var color = $(id).css(what);
var matchColors = /rgb\((\d{1,3}), (\d{1,3}), (\d{1,3})\)/;
var match = matchColors.exec(color);
var r = (255 - match[1]).toString() + ",";
var g = (255 - match[2]).toString() + ",";
var b = (255 - match[3]).toString();
answer = 'rgb(' + r + g + b + ')' ;
$(id).css(what,answer);
};
So essentially I have a function that can be called in many instances (clicks of specific ids, hover on specific classes, etc.) and I do not know them all. But I need to know every single time this function gets called. How can I have an outside line of code that sets a variable equal to the amount of times the function has been called?
Wrap your function.
var wrapped = (function wrapper(present) {
function wrapping() {
++wrapping.count; // increment invocation count
return present.apply(this, arguments);
}
wrapping.count = 0; // counter, avaliable from outside too
return wrapping;
}(invert));
If you need to call it invert too, re-assign invert after.
invert = wrapped;
invert.count; // 0
invert();
invert.count; // 1
invert();
invert.count; // 2
I am not sure what your exact scenario is, but maybe you could override the function with a wrapper:
var invertOriginal = invert;
var counter = 0;
var invert = function(id, what, max) {
invertOriginal(id, what, max);
// do counter stuff here, e.g.
counter++;
};

Categories

Resources