JavaScript scope issue/error - javascript

I got at brainteaser in my mailbox, it is supposed to take 20 minutes but apparently, I got stuck at scope that I crashed Chrome. The idea is that a string is provided to you. You then use the string to generate random sentences akin to lorum ipsum.
var words = "The sky above the port was the color of television, tuned to a
dead channel. All this happened, more or less. I had the story, bit by bit,
from various people, and, as generally happens in such cases, each time it
was a different story. It was a pleasure to burn.";
var wordList = words.split(' ');
var numWords = getRandomInt(2, 8);
var numSentinces = getRandomInt(8, 40);
var sentinces = [];
var sentince = [];
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function genSentinces() {
while (numWords > 0) {
sentince.push(wordList[getRandomInt(0, wordList.length)]);
numWords--;
}
sentince = sentince.join(' ');
console.log(sentince)
return sentince;
}
genSentinces();
genSentinces();
I am assuming that the scope of the sentence variable is wrong as it runs the first time but not the second time. I think I need to add a this somewhere.
Any help would be appreciated, as I can read code that has this in it but I apparently can't write code with this yet.

The main mistake is that you forget, that if you will modify global variable (all variables outside your functions can be called "global" regarding to this functions), it will not take the original value without your intervention. For example, if you declare new variable outside the function like var x = 0;, and then modify this variable from within the function like x = 1, this variable will be equal to 1 now.
You init sentince variable as array (var sentince = [];), but after the first execution of genSentinces function, this variable will be a string (because you're doing sentince = words.join(' ')). For this reason, I declared new array words inside the function, and I push words to it instead of pushing to global sentince array.
You use numWords-- to decrease the counter on every loop iteration, but numWords is a global variable and it will still equal to 0 after the first function invocation (it's why I added numWords = getRandomInt(2, 8) after the loop).
Here is the working example, feel free to ask, if anything isn't clear:
var words = "The sky above the port was the color of television, tuned to a dead channel. All this happened, more or less. I had the story, bit by bit, from various people, and, as generally happens in such cases, each time it was a different story. It was a pleasure to burn.";
var wordList = words.split(' ');
var numWords = getRandomInt(2, 8);
var numSentinces = getRandomInt(8, 40);
var sentinces = [];
var sentince = [];
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function genSentinces() {
var words = [];
while (numWords > 0) {
words.push(wordList[getRandomInt(0, wordList.length)]);
numWords--;
}
numWords = getRandomInt(2, 8);
sentince = words.join(' ');
console.log(sentince)
return sentince;
}
genSentinces();
genSentinces();

You changed variable 'sentince' from array to string and when you call function second time you call 'sentince.push(...' to string type and variable variable 'numWords' equal to 0 after first call.

Related

Can't get stable result with copying random values from array to an object

So I'm in process of creating a bot for a tournament and I got stuck on the part where I want to split players in pairs for play-off-style tournament. I just want to take 2 random players, get them from an array and write it as a value to a key as a round id for an object. Also I should not use those players again in the pair, so need to delete them or smth.
Here's the code:
var users = inc.funcs.getDatabase() //Getting a raw array of users (using my func that's basically a simplified fs.readFileSync func)
var tournamentPairs = new Object() //Object initialization
var id = 1
for (var i = 0; i < 16; i = i + 2) {
var first = Math.floor(Math.random() * (users.length + 1)) //Randomizing 2 indexes
var second = Math.floor(Math.random() * (users.length + 1))
var player1 = client.users.get(users[first]) //Getting the players by id
var player2 = client.users.get(users[second])
tournamentPairs[id++] = [player1.id, player2.id] //Writing to the object
users.splice(first, 1) //Deleting user's indexes from the array to not use them anymore.
users.splice(second, 1)
}
console.log(tournamentPairs)
It works perfectly on the outside, but has a bad habit of duplicating users and I once could have a gamergod98 vs gamergod98 for example. I tried console.log this crap but it often get an error when trying to console.log player2 because it's undefined for some reason. If I try to print users[second] I get undefined though it never happened for the first player. So I tried different ways to prevent situations like this: first == second. Long story short it didn't help much.
I have 9 days 'till tournament starts, any ideas on how to improve this code?
You are getting undefined because you are going out of bounds of your users list. For a list of length the last element is list[length-1], but you are generating random numbers up to length.
To fix duplicate users, remove the first selected user from the list before selecting the second one (or for a less destructive approach, mark already selected users).
var id = 1
for (var i = 0; i < 16; i = i + 2) {
var first = Math.floor(Math.random() * users.length)
var player1 = client.users.get(users[first])
users.splice(first, 1)
var second = Math.floor(Math.random() * users.length)
var player2 = client.users.get(users[second])
users.splice(second, 1)
tournamentPairs[id++] = [player1.id, player2.id]
}
Create a collection of used indexes and then if first or second are in used indexes then continue
var usedIndices = [] ;
if (usedIndices.indexOf(first) >= 0 ||
usedIndices.indexOf(second) >= 0) {
continue;
} else {
usedIndices.push(first);
usedIndices.push(second);
}
Put the usedIndices variable before for loop and the if else block inside loop after second

Array removing, "undefined" and JavaScript

first sorry my english.
Im making a little program to sort football players into two teams, A and B.
6 players, 3 for A and 3 for B. With a random number generator of course.
In Java i have no problem, i made this program and runs perfect, but i dont know much about JS and array item removings seems a little diferent here.
My code:
function hola(){
var primero = document.getElementById("1").value;
var segundo = document.getElementById("2").value;
var tercero = document.getElementById("3").value;
var cuarto = document.getElementById("4").value;
var quinto = document.getElementById("5").value;
var sexto = document.getElementById("6").value;
var jugadores = [primero,segundo,tercero,cuarto,quinto,sexto];
var eq1=[];
var eq2=[];
while (jugadores.length > 0){
var largoArray = jugadores.length;
var rand = Math.round(Math.random()* largoArray);
console.log("before the if, array jugadores haves ",jugadores.toString() ," and his size is ",jugadores.length);
if (eq1.length < 3){
eq1.push(jugadores[rand]);
remove(jugadores,jugadores[rand]);
}else {
eq2.push(jugadores[rand]);
remove(jugadores,jugadores[rand]);
}
}
document.getElementById("resultado").innerHTML= eq1 + " y el equipo B: " + eq2;
console.log("equipo 1 ", eq1);
console.log("equipo 2", eq2);
}
function remove(array, element) {
const index = array.indexOf(element);
if (index !== -1) {
array.splice(index, 1);
}
}
and it return to me:
"equipo 1 (3) [undefined, "iniesta", "ronaldo"]
script2.js:35 equipo 2 (4) ["messi", "ronaldinho", "maradona", "pele"]"
also the console logs i made to depurate seems to work fine...
The array is 1 element shorter each cicle, and array.lenght match the desired sizes.
What am doing wrong?
The problem is on the line:
Math.round(Math.random() * largoArray)
Since that will sometimes return an index that is beyond the bounds of the array. When that happens, this code:
eq1.push(jugadores[rand]);
remove(jugadores,jugadores[rand]);
Won't work, since jugadores[rand] is undefined, so you end up pushing undefined into one of your arrays, without removing anything from the original jugadores array.
To fix this, use the Math.floor function instead, changing the line to:
Math.floor(Math.random() * largoArray)
Arrays (like Java) start with the index 0.
The range of random numbers you are generating varies from 0 to 6 (array has only 6 elements).
var rand = Math.round(Math.random()* largoArray);
Instead use,
var rand = Math.round((Math.random()* largoArray)-1);

Attempt to filter array items that were recently used

Array.prototype.spil = function (x,max) {
if (this.length===max) {
this.shift();
this.push(x);
} else {
this.push(x);
}
return this;
}
var heard = [0],
freash = [];
$('#speak').bind('touchstart', function() {
var sounds = [
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,
21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40
];
var temp = sounds;
for (var i=0; i<heard.length; i++) {
temp.splice(temp.indexOf(heard[i]), 1);
}
freash = temp;
var say = Math.floor(Math.random() * freash.length+1) + 1;
heard.spil(say,10);
say = document.getElementById('c'+say); // audio element
// use the sound...
});
My attempt to make the sound that plays 'an un-recent one' is not working! I want to make the last sound that played not play again for 10 button clicks.
heard is the array of sounds that you have already heard, this has a Array.spil function which will fill the array via push until it reaches its max length of ten when it will shift then push instead.
freash is the array of sounds with no members of the heard array present.
You can see that heard and freash are declared outside of the click (touchstart) scope.
If I click/tap over-and-over sometimes I am hearing sounds that have been played already much sooner than I am suppose to, often following each other.
This has been bothering me for days but, I can't see the problem in my logic. Can you?
I think this line
var say = Math.floor(Math.random() * freash.length+1) + 1;
should be
var say = freash[Math.floor(Math.random() * freash.length)];
Also consider the shortcut
var say = freash[Math.random() * freash.length | 0];

how to create a loop in a function with another function?

I'm new to Java and I'm doing a uni course. I've been asked to design three functions.I have to find the difference between each adjacent numbers in an array, another to total the array and the last one to calculate the difference using the other functions then write a programme. I'm totally lost on the last function and my tutor has gone away on hols. Here is the code I have done so far. I don't want people doing the code for me but if anyone can advice me what I need to do I would appreciate your advice. I'm not sure how to loop the difference function into the array and store it into the new array I have made. If anyone could explain where I am going wrong I would love to hear from you!
var numberArray = [10,9,3,12];
// function difference will find the highest value of the two numbers,find the difference between them and return the value.
function difference(firstNumber, secondNumber)
{
if (firstNumber > secondNumber)
{
return (firstNumber - secondNumber);
}
else
{
return (secondNumber - firstNumber);
}
}
// function sum will add the total numbers in the array and return the sum of numbers.
function sum(numberArray)
{
numberTotal = 0
for (var total = 0; total < numberArray.length; total = total + 1)
{
numberTotal = numberTotal + numberArray[total]
}
{
return numberTotal
}
/*code the process that calculates a new array containing the differences between all the pairs
of adjacent numbers, using the difference() function you have already written.
This function should be named calculateDifferences() and should accept an array numberArray.
The function should first create a new empty array of the same size as numberArray
It should then calculate the differences between the pairs of adjacent numbers,
using the difference() function, and store them in the new array. Finally, the function should return the new array.
The calculation of the differences should be done in a loop, at each step finding the difference between each
array element and the next one along in the array, all except for the last difference,
which must be dealt with as a special case, because after the last element we have to wrap round to the start again.
So the final difference is between the last and first elements in the array.*/
function calculateDifferences()
var createArray = new Array (numberArray.length);
{
createArray = 0;
for (var c = 0; c < numberArray.length; c = c + 1)
{
createArray = difference(numberArray[c]);
}
{
return createArray
}
}
your implementation of function "calculateDifferences" is not correct.
this function should look like this:
function calculateDifferences()
{
var createArray = new Array (numberArray.length);
for (var c = 0; c < numberArray.length - 1 ; c = c + 1)
{
/*
because of the function "difference" has two parameters (firstNumber, secondNumber) in its declaration, we should give two arguments. (that are adjacent elements in array)
*/
createArray[c] = difference(numberArray[c],numberArray[c+1]);
}
/ *
calculating difference of first and last element of array and
assign it to returning array's last element.
*/
createArray[numberArray.length - 1] = difference(numberArray[0],numberArray[numberArray.length - 1]);
return createArray;
}
You should index createArray the same way you already do with numberArray[c].

Can anyone see what is wrong with my Javascript?

I have written the following:
var pages=["[www.google.co.uk] This is the WWW. ","[www.yahoo.co.uk] This is also the WWW. "];
function findScoresC(s){
var scores=[];
var words=[];
var wordScore;
var indexScore=[];
s=s.toLowerCase();
for(i=0;i<pages.length; i++){
var lowerCaseContents=(pages[i].substring(pages[i].indexOf("]")+1,pages[i].lastIndexOf(" "))).toLowerCase();
words=lowerCaseContents.split(" ");
for(i=0;i<words.length;i++){
if(words[i].match(s)){
wordScore=1;
indexScore[i]=indexScore[i]+1};
scores[i] =indexScore[i]}};
return scores;
}
alert(findScoresC("w"));
The function aims to return an array ("scores") where each index of the array is the number of times the string s is found in each index of the "pages" array, excluding what is inside the square brackets - however, only finding the string s once within each word. So ideally, the first index of scores would be 1, because I have called the function with the letter w, and i would only like it to find the first w of "WWW" in the first index of pages - if this makes sense.
I have confused myself pretty epically in getting this far, so I have no idea why the function is returning ",,,," rather than numerical values for each index of scores - any ideas?
Thanks
When your for loop exits, i is equal to words.length, which is one greater than the last index of indexScore. You are assigning nothing at all to scores[i] each time through.
It might be because you have a nested for loop with the same index variable.
var pages=["[www.google.co.uk] This is the WWW. ","[www.yahoo.co.uk] This is also the WWW. ";
function findScoresC(s){
var scores=[];
var words=[];
s=s.toLowerCase();
for(i=0;i<pages.length; i++)
{
scores[i]=0;
var lowerCaseContents=(pages[i].substring(pages[i].indexOf("]")+1,pages[i].lastIndexOf(" "))).toLowerCase();
words=lowerCaseContents.split(" ");
for(j=0;j<words.length;j++)
{
if(words[j].match(s))
{
scores[i] += 1;
}
}
}
return scores;
}
alert(findScoresC("w"));
There were a few things. I replaced "i" with "j" for the inner index. You don't require a semicolon after a closing paren. You should have a semicolon after instructions (a couple were missing).
Probably the main issue (after the "i" issue) was that scores[i] should have been set outside the inner loop. This would have been clearer if the cosing parens had been separated out onto separate lines, instead of like "scores[i] =indexScore[i]}};".
It turned out that the variable indexScore was not required. That allowed me to bring scores[i] inside the inner loop to accumulate word hits directly.
Finally, I would prefer to communicate the pages variable to the function as an argument than to assume that it is available in the global space. I tend to avoid globals if I can.
var pages = [...];
function findScoresC(pages, s)
{
...
}
alert(findScoresC(pages, "w"));
Here's you're function fixed. It returns [1,1] which appears to be what you were going for. My notes are in the code.
var pages=["[www.google.co.uk] This is the WWW. ","[www.yahoo.co.uk] This is also the WWW. "];
function findScoresC(s){
var scores = [],
words = [],
wordScore;
// indexScore = [] <- this doesn't seem necessary
s = s.toLowerCase();
// Make sure to use `var i` and not just `i`; otherwise, you are creating a global variable.
for ( var i=0; i<pages.length; i++ ) {
// Initialize me!
scores.push(0);
var lowerCaseContents = pages[i].substring(
pages[i].indexOf("]") + 1, pages[i].lastIndexOf(" ")
).toLowerCase();
words = lowerCaseContents.split(" ");
// You were using `i` for this loop as well. No can do.
for ( var j=0; j<words.length; j++) {
if ( words[j].match(s) ) {
// wordScore = 1; <- I don't know what you're using this for
scores[i]++;
}
}
};
return scores;
}
console.log(findScoresC("w"));
here's a small function that counts how many times substring "subStr" occurs in "str", not counting [...]
function substrCount(str, subStr) {
var str = str.replace(/\[.+?\]/g, "");
var del = str.toLowerCase().split(subStr.toLowerCase()).join("");
return (str.length - del.length) / subStr.length;
}
the rest is obvious ;)
// edit: this is how you apply this function to an array
var someArray = ["whatever", "something", "else" ];
var counter = [];
for(var i = 0; i < someArray; i++)
counter[i] = substrCount(someArray[i], "something");
// or, to count only one match, i.e. just to test if a substring is present
counter[i] = substrCount(someArray[i], "something") > 0;

Categories

Resources