JavaScript Random Function does not work - javascript

All I want to do is have the program select random questions (each question is within a function and fills a blank area in the HTML so all questions appear in the same area) but it does not work. Does anyone have any idea why? I am meant to click correct answer and it executes the correctFunction but nothing happens. Cheers!
var randomFunctions = [
"Question2", "Question3",
"Question4", "Question5",
"Question6", "Question7",
"Question8"
];
var rand = randomFunctions[Math.floor(Math.random() * randomFunctions.length)];
function correctFunction() {
rand();
}
correctFunction()

You must provide actual functions that can be invoked, not strings (which can't). So, your array will wind up holding references to existing functions or the actual functions themselves.
Based on your updated requirement that possible answers should also be shown along with the question, we need to rethink what you are storing in your array. Since a question will have associated possible answers, the best way to store each question with its answers is in an object. So, in the end, we will have an array of objects.
function q1(){ console.log("hello from q1"); }
function q2(){ console.log("hello from q2"); }
function q3(){ console.log("hello from q3"); }
function q4(){ console.log("hello from q4"); }
var randomFunctions = [q1, q2, q3, q4, function(){
console.log("hello from inline anonymous function.");
}];
var rand = randomFunctions[Math.floor(Math.random() * randomFunctions.length)];
rand();
Now, based on your use case, you really don't need or want to store an array of functions, you need to store an array of questions and then have one function that processes that randomly selected question. Like this:
// Get reference to HTML output area
var question = document.getElementById("questionArea");
var answer = document.getElementById("answerArea");
var btn = document.getElementById("btnGetQuestion");
// Set up button click event:
btn.addEventListener("click", showQuestion);
// Set up questions/answers array as an array of objects so that
// the questions and answers can be connected:
var qa = [
{
question:"What is your name?",
answers: ["Bob","Sally", "Mary", "Tim"]
},
{
question:"What is your favorite color?",
answers: ["Red","Green", "Blue", "Orange"]
},
{
question:"What is the average air speed of a laden swallow?",
answers: ["22 mph","18 mph", "17 kmh", "African or European?"]
}
];
// One function to process question:
function showQuestion(){
// Get a random number based on lenght of the questions array
var num = Math.floor(Math.random() * qa.length);
// Get a random object out of the array and extract the question from the object
question.textContent = qa[num].question;
// Loop over all the values in the "answers" object array
// and display them. Build up an output string as well
var html = "<form>";
qa[num].answers.forEach(function(answer, index){
html += "<input type='radio' name='q" + index + "' value='" + answer + "'>" + answer;
});
// close the string and display:
html += "</form>";
answer.innerHTML = html;
}
button {
margin:2em 0;
}
#answerArea {
margin: 1em 0 0 1em;
}
<div id="questionArea"></div>
<div id="answerArea"></div>
<button id="btnGetQuestion">Get A Question</button>

Related

get object.properties and place it random in dom element.Vanila Js

I'm creating quiz game.
I have separate .js file with array of objects for questions,like this:
var questions = [
{
ask: "question",
choice1: "answer",
choice2: "answer",
choice3: "answer",
correct: "correct answer"
},
];
then i get random object from array:
let random = questions[Math.floor(Math.random() * questions.length)];
then i can send these object.properties to dom like this:
question.innerHTML = random.ask
answer1.innerHTML = random.choice1;
answer2.innerHTML = random.choice2;
answer3.innerHTML = random.choice3;
answer4.innerHTML = random.correct;
And everything works fine but i need to randomize these answers.In ways like this every time the correct answer is on same place but i need answers and correct answer to take random place in dom.
I'm stuck in this problem,trying every solution i can find on google but no success.
You can use the same logic to randomize choices. One of the ways this can be done is as below:
var questions = [
{
ask: "question",
choice1: "answer 1",
choice2: "answer 2",
choice3: "answer 3",
correct: "correct answer"
},
];
let random = questions[Math.floor(Math.random() * questions.length)];
console.log(random);
// Make an array of choices key
let choices = [];
Object.keys(random).forEach((item, index) => {
if(key !== "ask") {
choices.push(random[item]);
}
});
console.log(choices);
function getRandomAnswer() {
// Get a random number
let randomNum = Math.floor(Math.random() * choices.length);
// Store random answer in a variable
let answer = choices[randomNum];
// Remove used up answer from choices array
choices.splice(randomNum, 1);
return answer;
}
console.log("Random Answer: ", getRandomAnswer());
console.log("Random Answer: ", getRandomAnswer());
console.log("Random Answer: ", getRandomAnswer());
console.log("Random Answer: ", getRandomAnswer());
I have made a jsFiddle of this as well. You can optimize this as per your needs.
Hope it helps!

How to find the position of all array items from a loop

I'm brand new to programming so I apologize if this is a simple question.
I had a unique practice problem that I'm not quite sure how to solve:
I'm dealing with two arrays, both arrays are pulled from HTML elements on the page, one array is representing a bunch of states, and the next array is representing their populations. The point of the problem is to print the name of the states and their less than average populations.
To find and print all of the populations that are less than the average I used this code:
function code6() {
// clears screen.
clr();
// both variables pull data from HTML elements with functions.
var pop = getData2();
var states = getData();
var sum = 0;
for( var i = 0; i < pop.length; i++ ){
sum += parseInt( pop[i], 10 );
var avg = sum/pop.length;
if (pop[i] < avg) {
println(pop[i]);
// other functions used in the code to get data, print, and clear the screen.
function getData() {
var dataSource = getElement("states");
var numberArray = dataSource.value.split('\n');
// Nothing to split returns ['']
if (numberArray[0].length > 0) {
return(numberArray);
} else {
return [];
}
}
// Get the data from second data column
function getData2() {
var dataSource = getElement("pops");
var numberArray = dataSource.value.split('\n');
// Nothing to split returns ['']
if (numberArray[0].length > 0) {
return(numberArray);
} else {
return [];
}
}
// Clear the 'output' text area
function clr() {
var out = getElement("output");
out.value = "";
}
// Print to the 'output' HTML element and ADDS the line break
function println(x) {
if (arguments.length === 0) x = '';
print(x + '\n');
}
Now I just need to know how to get the value of these positions within the array so I can pull out the same positions from my states array and display them both side by side. Both arrays have the identical amount of items.
I hope this makes sense and thanks in advance to anyone who has time to take a look at this.
Best regards,
-E
Its a little hard to tell what you are trying to accomplish, but I guess you are going for something like:
'use strict'
function code6() {
const populations = ['39000000', '28000000', '21000000'];
const stateNames = ['california', 'texas', 'florida'];
const states = populations.map((population, i) => ({
'name': stateNames[i],
'population': Number(population),
}));
const sum = states.reduce((sum, state) => sum + state.population, 0);
const average = sum / populations.length;
states
.filter(state => state.population < average)
.forEach(state => {
const name = state.name;
const population = state.population;
console.log(`state name: ${name}, population: ${population}`);
});
}
// run the code
code6();
// state name: texas, population: 28000000
// state name: florida, population: 21000000
I took the liberty of refactoring your code to be a little more modern (es6) and Idiomatic. I hope its not to confusing for you. Feel free to ask any questions about it.
In short you should use:
'use strict' at the top of your files
const/let
use map/filter/forEach/reduce to iterate lists.
use meaningfull names
, and you should avoid:
classic indexed for-loop
parseInt
, and pretty much never ever use:
var
If your states array is built with corresponding indices to your pop one, like this:
states; //=> ['Alabama', 'Alaska', 'Arizona', ...]
pop; //=> [4863300, 741894, 6931071, ...]
then you could simply update your print statement to take that into account:
if (pop[i] < avg) {
println(state[i] + ': ' + pop[i]);
}
Or some such.
However, working with shared indices can be a very fragile way to use data. Could you rethink your getData and getData2 functions and combine them into one that returns a structure more like this the following?
states; //=> [
// {name: 'Alabama', pop: 4863300}
// {name: 'Alaska', pop: 741894},
// {name: 'Arizona', pop: 6931071},
// ...]
This would entail changes to the code above to work with the pop property of these objects, but it's probably more robust.
If your pop and state looks like:
var state = ['state1', 'state2', ...];
var pop = ['state1 pop', 'state2 pop', ...];
Then first of all, avg is already wrong. sum's value is running along with the loop turning avg's formula into sum as of iteration / array length instead of sum of all pops / array length. You should calculate the average beforehand. array.reduce will be your friend.
var average = pop.reduce(function(sum, val){return sum + val;}, 0) / pop.length;
Now for your filter operation, you can:
Zip up both arrays to one array using array.map.
Filter the resulting array with array.filter.
Finally, loop through the resulting array using array.forEach
Here's sample code:
var states = ['Alabama', 'Alaska'];
var pop = [4863300, 741894];
var average = pop.reduce(function(sum, val){return sum + val;}) / pop.length;
console.log('Average: ' + average);
states.map(function(state, index) {
// Convert 2 arrays to an array of objects representing state info
return { name: state, population: pop[index] };
}).filter(function(stateInfo) {
console.log(stateInfo);
// Filter each item by returning true on items you want to include
return stateInfo.population < average;
}).forEach(function(stateInfo) {
// Lastly, loop through your results
console.log(stateInfo.name + ' has ' + stateInfo.population + ' people');
});

random quote without back to back

I'm trying to pull a random quote from an array. I need to display an initial quote and then get a new one, no same two quotes back to back. Here's what I got.
$(document).ready(function() {
var quoter = [{
quote: "I drink to make other people more interesting.",
author: "Ernest Hemingway"
}, {
quote: "Alcohol may be man's worst enemy, but the bible says love your enemy.",
author: "Frank Sinatra"
}, {
quote: "Reality is an illusion created by a lack of alcohol.",
author: "N.F. Simpson"
},{
quote: "Time is never wasted when you’re wasted all the time.",
author: "Catherine Zandonella"
},{
quote: "I feel bad for people who don’t drink. When they wake up in the morning, that’s as good as they’re going to feel all day.",
author: "Frank Sinatra"
}];
var randomQuote = Math.floor(Math.random() * quoter.length);
//$(function () {
//Set Original Quote
$('#quoteText').text(quoter[randomQuote].quote);
$('#authorText').text(quoter[randomQuote].author);
//});
$('#btnNew').click(function(evt) {
//prevent browser's default action
evt.preventDefault();
//getting a new random number to attach to a quote and setting a limit
var sourceLength = quoter.length;
var randomNumber = Math.floor(Math.random() * sourceLength);
//set a new quote
//while ( randomNumber <= sourceLength ) {
while (randomNumber === randomNumber){
var newQuoteText = quoter[randomNumber].quote;
var newQuoteGenius = quoter[randomNumber].author;
var timeAnimation = 500;
var quoteContainer = $('#quoteContainer');
//fade out animation with callback
quoteContainer.fadeOut(timeAnimation, function() {
//set text values
$('#quoteText').text(newQuoteText);
$('#authorText').text(newQuoteGenius);
//console.log(quoteText,authorText);
//fadein animation.
quoteContainer.fadeIn(timeAnimation);
});
break;
}; //end while loop
}); //end btnNew function
}); //end document ready
I need to do this by using a while loop. I can't figure out how to store the random quote (array value) and then compare it to the new random one to get a different random on if it's the same.
The HTML is here:
<div id="quoteContainer">
<p><span id="quoteText"></span><Br/></p>
—<span id="authorText"> </span>
</div>
You can have a simple variable store the previous value, then check to see if the random number is the same as the last time.
$(document).ready(function(){
//....your current above code
var lastQuote = randomQuote;
$(button).click(function(){
var thisQuote = Math.floor(Math.random() * sourceLength);
//This will only be entered if the two are equal
//The while loop ensures that if you get a new random number
//it won't be the same
while(thisQuote == lastQuote){
thisQuote = Math.floor(Math.random() * sourceLength);
}
//If you make it here a unique number has been found
lastQuote = thisQuote;
});
});
Your approach might result in an infinite loop. Won't happen, because the random-number generator is not perfect but it can be done easier:
Either shuffel the array and go down linearly (or construct a fancy generator if you want) or just delete every quote that has been shown already.

Search array for string - returning -1

I've been reading lots of StackOverflow answers which tell me that, in Javascript, the best way to search an array for a particular string is use indexOf(). I have been trying to make this work for a while now, and I need some help with it.
I am making a shop in a text-adventure game. These are the values I am using:
The array shopCosts:
shopCosts = [20, 25];
The array shopItems:
shopItems = [["Sword", "Shield"]];
I dynamically create radiobuttons by looping through shopItems:
for(var i = 0; i < array.length; i++)
{
// Create the list item:
var item = document.createElement('li');
// Set its contents:
item.appendChild(document.createTextNode(array[i] + " - " + shopCosts[i] + " Gold"));
// Add it to the list:
list.appendChild(item);
var label = document.createElement("label");
var radio = document.createElement("input");
var text = document.createTextNode(array[i]);
radio.type = "radio";
radio.name = "shop";
radio.value = array[i];
radio.onclick = function () { addValue(this.getAttribute("value"), shopCosts, shopItems) }
label.appendChild(radio);
label.appendChild(text);
document.body.appendChild(label);
}
This is the part in question:
radio.onclick = function () { addValue(this.getAttribute("value"), shopCosts, shopItems) }
My logic was basically to assign values to each dynamically created radiobutton, and if one was pressed, get the value (so, the name of the item you wanted to buy) and then search shopItems for that particular string for the index value. Once I had that, I would look in the same "parallel" list shopCosts to find the price.
I used console.log() to see what variables were in play. When I clicked on the radio button, this function is called:
function addValue(nameOfItem, shopCosts, shopItems)
{
var positionOfShopItem = shopItems.indexOf(nameOfItem);
console.log(positionOfShopItem);
console..log(nameOfItem);
console.log(shopItems);
}
Surely, the console.log() would return the position of the named item? To prove to myself I'm not going crazy, here's what the Dev Tools say:
-1
Sword
[Array[2]]
0: "Sword"
1: "Shield"
Sword is clearly in the array, in position 0, so why is indexOf() returning -1?
Any help appreciated!
As I alluded to in my comment, its because shopItems does not contain an array of strings, it contains a single element, where that one element is an array of strings. I suspect your code would work just fine if you removed the extra square braces
var shopItems = ["Sword", "Shield"];
I realize you've already fixed the bug, but I urge you to consider a different approach to the problem. These two principles will not only solve the problem in a cleaner way, but they also give you a new way to think about similar problems in the future:
Never use parallel arrays. Use a single array of objects instead.
In your main loop that appends the items, put the main body of the loop in a function.
If you follow these two ideas you gain several benefits. The code becomes much more straightforward, easier to maintain, and you don't have to do any array lookups at all!
Each shop item is packaged up as a single object in the array, like this:
var shopItems = [
{ name: 'Sword', cost: 20 },
{ name: 'Shield', cost: 25 }
];
So if you have a reference to the shop item as a whole, say in a variable called shopItem, then you automatically have all of its properties available: shopItem.name and shopItem.cost. This lets you also easily add more bits of data to a shop item, e.g.
var shopItems = [
{ name: 'Sword', cost: 20, dangerous: true },
{ name: 'Shield', cost: 25, dangerous: false }
];
and now shopItem.dangerous will give you the appropriate value. All without any array lookups.
Making the main loop body into a function adds a further benefit: Inside that function, its parameters and local variables are preserved each time you call the function (this is called a closure). So now you don't even have to fetch the list item value and look it up - you already have the appropriate shopItem available in the code.
Putting this together, the code might look like this:
var shopItems = [
{ name: 'Sword', cost: 20, dangerous: true },
{ name: 'Shield', cost: 25, dangerous: false }
];
var list = document.getElementById( 'list' );
for( var i = 0; i < shopItems.length; ++i ) {
appendShopItem( shopItems[i] );
}
// Alternatively, you could use .forEach() instead of the for loop.
// This will work in all browsers except very old versions of IE:
// shopItems.forEach( appendShopItem );
function appendShopItem( shopItem ) {
// Create the list item:
var item = document.createElement( 'li' );
// Set its contents:
item.appendChild( document.createTextNode(
shopItem.name + ' - ' + shopItem.cost + ' Gold'
) );
// Add it to the list:
list.appendChild( item );
var label = document.createElement( 'label' );
var radio = document.createElement( 'input' );
var text = document.createTextNode( shopItem.name );
radio.type = 'radio';
radio.name = 'shop';
radio.value = shopItem.name;
radio.onclick = function () {
addValue( shopItem );
};
label.appendChild( radio );
label.appendChild( text );
document.body.appendChild( label );
}
function addValue( shopItem ) {
console.log( shopItem );
alert(
shopItem.name +
' costs ' + shopItem.cost + ' and is ' +
( shopItem.dangerous ? 'dangerous' : 'not dangerous' )
);
}
New fiddle (with a tip of the hat to Jamiec for the original fiddle)
As you can see, this makes the code much easier to understand. If you have a shopItem, you automatically have its name, cost, and any other property you want to add. And most importantly, you never have to keep track of putting your values in the same order in two, three, or even more different arrays.
shopItems is an Array of Arrays. The 0 index of shopItems contains another array which contains:
["Sword", "Shield"]
So when you are trying to find the "Sword" item or "Shield" Item inside of shopItems it is returning -1 because it cannot find either inside of the array.
Change
shopItems = [["Sword", "Shield"]];
To
shopItems = ["Sword", "Shield"];
And that will fix your issue.
I've fixed it!
Removing the double square brackets resulted in this mess. So, as a workaround, I simply added [0] to var positionOfShopItem = shopItems.indexOf(nameOfItem); to get var positionOfShopItem = shopItems[0].indexOf(nameOfItem);
Thanks for everyone's help.

JavaScript database correlation

I've been trying to 'correlate' between user picked answers and an object property name so that if the two matches then it will display what is inside.
My program is a recipe finder that gives back a recipe that consists of the ingredients the user picked.
my code currently looks like:
//property are the ingredients and the value are the recipes that contain those ingredients. The map is automatically generated
``var map = {
"pork" : [recipe1, recipe2, ...],
"beef" : [],
"chicken" :[],
}
//this gets the user pick from the dom
var cucumber = specificVegetable[7];
var lemon = specificFruits[0];
//Then this code finds the intersection of the recipe(recipes that use more than one ingredients)
function intersect(array1, array2)
{
return array1.filter(function(n) {
return array2.indexOf(n) != -1
});
}
var recipiesWithLemon = map["lemon"]; **// makes the lemon object is map**
var recipiesWithCucumber = map["cucumber"]; **// makes the cucumber object in map**
//Here is where I am stuck
function check(){
var both = intersect(recipiesWithLemon, recipiesWithCucumber);
if ( cucumber.checked && lemon.checked){
for (var stuff in map){
if(stuff="cucumber" && stuff="lemon"){
return both;
}
}
}
}
check();
so basically what I tried to do was I made my intersect and then if user pick is lemon and cucumber then look at the properties in the map object. if the name of the property equals to the exact string then return both. That was the plan but the code does not work and I'm not sure how to fix it.
My plan is to write code for every possible outcome the user may makes so I need to find the correlation between the user pick and the map which stores the recipe. I realize this is not the most effective way but I'm stumped on how to do it another way.
Thanks for the help.
Im using the open source project jinqJs to simplify the process.
I also changed your map to an array of JSON objects. If you must have the map object not as an array, let me know. I will change the sample code.
var map = [
{"pork" : ['recipe1', 'recipe2']},
{"beef" : ['recipe3', 'recipe4']},
{"peach" :['recipe5', 'recipe6']},
{"carrot" :['recipe7', 'recipe8']}
];
var selectedFruit = 'peach';
var selectedVeggie = 'carrot';
var selections = [selectedFruit, selectedVeggie];
var result = jinqJs().from(map).where(function(row){
for(var f in row) {
if (selections.indexOf(f) > -1)
return true;
}
return false;
}).select();
document.body.innerHTML += '<pre>' + JSON.stringify(result, null, 2) + '</pre><br><br>';
<script src="https://rawgit.com/fordth/jinqJs/master/jinqjs.js"></script>

Categories

Resources