I'm having trouble finishing a simple JS math game - javascript

I got my onclick function working, but the issue is that jQuery wasn't working for me for some reason, so I took it out, but I don't know how to disable the onclick without using jQuery: how can I disable the button's onclick and have it stay disabled if it is correct (and reset if it isn't correct? I also need to make it so that numOne and numTwo recalculate another random number if it is equal to the id of a disabled button, so I'm guessing I have change the do while loop I have to make sure that numTwo never equals numOne, but I'm not sure how to do all that.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Lemon Squares - Grade 1 Edition</title>
</head>
<body id="bodyId">
<script type="text/javascript">
var button = new Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16);
var numbers = new Array();
for (var i=0; i<16; i++)
{
var randomNumber = Math.floor(Math.random()*9);
numbers[i] = document.createElement("button");
numbers[i].innerHTML = button[randomNumber];
numbers[i].setAttribute("type", "button");
numbers[i].setAttribute("id", button[i]);
numbers[i].setAttribute("onclick", "onClick('" + button[randomNumber] + "')");
numbers[i].setAttribute("value", button[randomNumber]);
document.getElementById("bodyId").appendChild(numbers[i]);
if (i == 3 || i == 7 || i == 11)
{
document.write("<br>");
}
}
var numOne = (Math.ceil(Math.random()*15)).toString();
var numTwo = (Math.ceil(Math.random()*15)).toString();
do
{
numTwo = Math.ceil(Math.random()*15).toString();
}
while (numTwo == numOne);
var numberOne = document.getElementById(numOne).value;
var numberTwo = document.getElementById(numTwo).value;
var answer = parseInt(numberOne) + parseInt(numberTwo);
var total = 0
function onClick(x)
{
x = parseInt(x);
total += x;
if (total > answer)
{
alert("Sorry, try again.")
total = 0
}
else if(total == answer)
{
alert("Congratulations, you did it!");
total = 0
}
}
document.write("<br> Pick two numbers that add up to: " + answer);
</script>
</body>
</html>

i think you are going about this the wrong way.
the logic of the game is (if i understand correctly):
pick "1 to n"(n is the count of all available buttons/items) number of items randomly
get the sum of the selected items value and show to user
record and add up the user selected values until the goal is reached and keep track of the selected items by user is an a array
if the selected items sum is correct disable the selected (just add disabled attribute to the button) items and reaped from step 1 where n is the number of remaining items
so for your problem :
on every button click take these steps :
add the value to a array
get the sum of values in the array
compare the sum with the answer
if the sum is less than the answer do nothing and wait for the next click
if the sum is equal to the answer
disable the buttons in the array
clear the selected items array
create a new answer
if the sum is more than the answer clear the selected items array and start over
i hope this helps .

Related

Changing a variable value/re referencing it with SetIncrement

I have a timer I use to count how many masks are made in a production environment. I use a variable value that is user input when the page is started - it is called SAMS, basically how many masks 1 person can make in an hour would be what I would input depending on how many people I have working. IE. 2 people may be 18, 1 may be 9 etc. The problem I have with my current build is that I cannot change the SAMS value if I have someone leave for the day. So then what I use that value to calculate is off (I use it to show a GOAL value that increments based on the value).
Here is the relevant code for the processes I've described.
var SAMSINPUT = input;
console.log(SAMSINPUT);
document.getElementById('output').innerHTML = SAMSINPUT;
var goal = 0;
var output2 = document.getElementById('output2');
setInterval(function doIncrement() {
if (clear == false) {
goal += 1;
output2.innerHTML = goal.toString();
}
}, SAMSINPUT * 1000);
I also have START/STOP/RESET buttons on the page for the timer itself. I tried putting the SAMSINPUT input into the stop button, because if I could stop it, put in a new SAMSINPUT - and have the increment adjusted to the new value, that would solve this for me. However, that doesn't seem to change the actual value that SetInterval references, if I start with a 5, then change it to a 10 that way, it still increments at 5.
Would this work? Let me know if you have any problems/issues.
var SAMSINPUT = 1;
document.getElementById('output').innerHTML = SAMSINPUT;
var goal = 0;
var output2 = document.getElementById('output2');
function doIncrement() {
goal += 1;
output2.innerHTML = goal.toString();
}
var inter = setInterval(doIncrement, SAMSINPUT * 1000);
function changeAmount() {
var newVal = document.getElementById('newval').value
clearInterval(inter);
var a = setInterval(doIncrement, newVal * 1000);
}
<div id='output'>
</div>
<div id='output2'>
</div>
<input type="number" id="newval">
<button onclick='changeAmount()'>new SAMSINPUT</button>

How to get the last N objects before a certain object in a Javascript array?

I'm trying to implement the endless loading of items in Javascript. Like the effect you get when you scroll through your messages in your favorite messaging application. I have a big array like this (+1000 objects):
var array = [
{ id : 1, text: "First"},
{ id : 2, text: "Second"},
{ id : 3, text: "Third"},
{ id : 4, text: "Forth"},
{ id : 5, text: "Fifth"},
{ id : 6, text: "Sixth"},
{ id : 7, text: "Seventh"},
...
];
Now I want to load only 10 items at a time. For example I'm showing only the items with the id of 30 to 39. Now the user wants to see the items before 30. What is the best way to select last 10 items before that object with the id of 30? As mentioned before, the array's size is big so performance does matter here.
EDIT
The example above is just one case. I should be able to filter my array 10 items at a time as many times as needed.
What I'm trying to achieve is loading a big array but not all at once. I want to load 10 items at a time. I'm keeping track of the first object in my filtered array (e.g 30) and then I want to get the last 10 objects before that particular object.
EDIT 2
This is my View:
<div ng-repeat="message in messages" class="message-wrapper">
// Show content of message
</div>
Now initially i'm showing the last 10 items in messages
$scope.init = function(){
var messages = Database.AllMessages(); // This function returns all my messages
$scope.messages = messages.length > 10 ? messages.slice(-10) : messages;
}
Now let's say the items returned by this function are the items with the Id of 30 to 39. The user scrolls up and wants to see the messages prior to 30. So how can i filter the whole array returned by AllMessages() to get 10 last items before the 30 message?
Thanks in advance for any insights.
You want to query your data source as efficient as possible. Make sure the array is sorted by id first:
array.sort(function(a, b) {
if (a.id === b.id) return 0;
if (a.id > b.id) return 1;
return -1;
});
Then, binary search can be performed to find the index of the element you're looking for:
var search = function(arr, val) {
if (arr.length === 0) {
return -1;
}
var max = arr.length - 1, min = 0;
while (max !== min) {
var index = Math.floor((max + min) / 2);
if (arr[index].id === val) {
return index;
}
else if (arr[index].id < val) {
min = index;
}
else {
max = index;
}
}
return arr[index].id === val ? index : -1;
}
// find index of element with desired id.
var index = search(array, 30);
Once we know the index, we simply have to select the elements before/after the index:
var rangeMin = index - 10; // Inclusive. 10 is the maximum number of elements you want to render.
var rangeMax = index; // Not inclusive.
if (rangeMin < 0) { rangeMin = 0; }
if (rangeMax > array.length) { rangeMax = array.length; }
var elementsToRender = array.slice(rangeMin, rangeMax);
elementsToRender will now contain all the elements you want to render.
Now let's say the items returned by this function are the items with the Id of 30 to 39. The user scrolls up and wants to see the messages prior to 30. So how can i filter the whole array returned by AllMessages() to get 10 last items before the 30 message?
(...) my view should show the items 20 to 39
Suppose allMessages contains all messages (very large array).
Suppose ctrl is a controller instance
Suppose ctrl.messages contains the items currently displayed.
Suppose currentIndex is 30
Suppose stepSize is 10
Then the following code will extend messages to contain items 20 to 39 and will set currentIndex to 20:
currentIndex -= stepSize; // the new first message will have index 20
var extraItems = allMessages.slice(currentIndex, currentIndex+stepSize);
Array.prototype.push.apply(extraItems, ctrl.messages); // append ctrl.messages to extraItems
ctrl.messages = extraItems;
For more information about Array.prototype.push.apply, see Mozilla (scroll down to 'Merging two arrays').
Here is small app to demonstrate it (you'll have to add logic to protect the user to cross the array boundaries):
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.min.js"></script>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('MyController', function() {
var ctrl = this;
var allMessages = Database.AllMessages();
var stepSize = 10;
var currentIndex = allMessages.length - stepSize;
// show the last 10 messages
ctrl.messages = allMessages.length > 10 ? allMessages.slice(-10) : allMessages;
// show ten more messages
ctrl.showMore = function () {
currentIndex -= stepSize;
var extraItems = allMessages.slice(currentIndex, currentIndex+stepSize);
Array.prototype.push.apply(extraItems, ctrl.messages);
ctrl.messages = extraItems;
};
});
</script>
</head>
<body ng-app="myApp">
<div ng-controller="MyController as ctrl">
<table>
<tr ng-repeat="message in ctrl.messages"><td>{{message.text}}</td></tr>
</table>
<button ng-click="ctrl.showMore();">show more</button>
</div>
</body>
</html>
You can try this to get the object with id 30 without a loop using the following code:
var array = [
{ id : 1, text: "First"},
{ id : 2, text: "Second"},
{ id : 3, text: "Third"},
{ id : 4, text: "Forth"},
{ id : 5, text: "Fifth"},
{ id : 6, text: "Sixth"},
{ id : 7, text: "Seventh"}
];
var result = $.grep(array, function(e){ return e.id == 5; });
console.log(result);
What is the best way to select last 10 items before that object with the id of 30?
var index = 30;
var count = 10;
// 10 items before 30 :
array.slice(index-count, index);
I knew this thing I made could be helpful to somebody. Here's the relevant piece:
$('button.getResult').on('click', function(e) {
e.preventDefault();
var limit = $('input.getResult').val();
if (limit != '' && !isNaN(limit)) {
var dots = $('ul li');
if (dots.length > limit) {
//show the limit as group
var foundSelected = false;
var counter = 0;
for (var i = dots.length - 1; i >= 0; i--) {
dots.eq(i).addClass('group');
dots.eq(i + parseInt(limit)).removeClass('group');
counter++;
if (i == $('li.selected').index()) {
foundSelected = true;
};
if (foundSelected && counter >= limit) {
i = -1;
};
};
} else {
//show all as group
dots.addClass('group');
};
};
return false;
});
dots is basically your array and the first conditional is just checking to make sure the number of results you want is smaller than the length of the array. Then a loop is performed through the array (backwards in my case) checking for the important item. If I find it, I change the boolean to true.
Additionally, I mark each as selected as I iterate and if the selected index is outside of the limit of pagination, then I remove the selected mark (to keep the pagination). Once I've both found the important item and have marked the correct number of items past the important one, I stop the loop.
Of course, you might not be able to mark things in your case but I figure you could look at this for some inspiration.

When number reaches every nth value inside nested loop

Purpose: A user can choose a Product Type and variation of that Product Type. I need to track every Product Type added and how many variations were added. For Example,
item 1: Shirt > Long Sleeve (1)
item 2: Shirt > V neck (3)
item 3: Pants > Jeans (1)
The total amount pertains to the variation of the product. I'd like to have something happen whenever a user selects 4th variation of the same type. For this example, I want something to happen to the Product type Shirt, as currently long sleeve + v neck = 4
I have two nested loops. First one is looping through each product type, and inner loop should loop through each variation and get the sum.
This is a good starting point but I can't seem to get passed the for loop to check for every nth value of the total # of variations.
jQuery('.product').each(function(i, objP){
var sum = 0,
min = 4,
max = 5;
jQuery(objP).find('.product-variation-quantity').each(function(ii, objC){
sum += parseInt(jQuery(objC).text());
return sum;
for ( var x = 0; x < min * max; x += min) {
if ( sum == x ) {
var sum_id = jQuery(objP).attr('id');
console.log(sum_id);
//product quantity has reached min to pass
}
else {
//has not reached min
}
}
});
});
Any help?
note: objP and objC are used to track the contextual this
note2: to clarify: on every 4th, 8th, 12th etc value, something will happen, not every 4th, 5th, 6th
First of all, you have a bug in your code, it's where you return sum; in the nested loop. The for loop after this will never execute.
I suggest this code:
jQuery('.product').each(function(i, objP){
var sum = 0,
min = 4,
max = 5;
var ind = 1;
jQuery(objP).find('.product-variation-quantity').each(function(ii, objC){
sum = parseInt(jQuery(objC).text());
if (sum > 0 && sum % 4 == 0) {
// Do something
}
});
});
Here's codepen sample.
What about this: in case 8 items of the same variation are selected, the console will read
[id] has crossed 2x4 items
Code:
jQuery('.product').each(function(i, objP){
var min = 4,
max = 5,
sum_id;
jQuery(objP).find('.product-variation-quantity').each(function(ii, objC){
var count = parseInt(jQuery(objC).text());
if ( count < min ) {
//product quantity has not reached min
}
else {
// product quantity has reached min to pass
sum_id = jQuery(objP).attr('id');
console.log(sum_id + ' has crossed ' + min + 'x'
+ Math.floor(count/min) + ' items');
}
});
});

Random lottery number generator

What I'm trying to do is generate 6 random numbers, five in a range of 1-45 and one in a range of 1-25 for a Greek lottery game (Tzoker). The first 5 numbers should be unique. By pressing a button, I want to add these numbers to a div using jQuery (I have some working code for this part).
I thought it would be pretty easy using a loop, but I've found myself unable to check if the number generated already exists. The loop would only contain the first 5 numbers, because the last number can be equal to one of the other 5.
Let me propose you some simpler solution.
Make a list of all numbers from 1 to 45.
Sort the list using Math.random (plus minus something, read the docs of Array.sort to find out) as the comparison function. You will get the list in random order.
Take 5 first items from the list.
Then, when you already have the numbers, put them all into your div.
This way you don't mix your logic (getting the numbers) with your presentation (putting stuff into the DOM).
I leave the implementation as an exercise for the reader. :)
Like this?
$(function() {
$('button').on('click', function(e) {
e.preventDefault();
var numArray = [];
while( numArray.length < 5 ) {
var number = Math.floor((Math.random() * 45 ) + 1);
if( $.inArray( number, numArray ) == -1 ) {
numArray.push( number );
}
}
numArray.push( Math.floor((Math.random() * 25 ) + 1) );
$('div').html( numArray.join("<br />") );
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Generate</button>
<div></div>
While this might be not exactly what you were asking for, if you would use lodash, this would be as simple as:
_.sample(_.range(1, 46), 5) // the 5 numbers from 1..45
_.random(1, 26) // one more from 1..25
This is why functional programming is so cool. You can read for example Javascript Allonge to find out more.
http://jsfiddle.net/015d05uu/
var tzoker = $("#tzoker");
var results = $("#results");
tzoker.click(function() {
results.empty();
var properResults = [];
var rand = 0;
var contains = false;
for (i = 1; i < 7; i++) {
do
{
(rand = Math.floor((Math.random() * (i != 6 ? 45 : 25)) + 1));
contains = properResults.indexOf(rand) > -1;
} while(contains)
results.append("<br />", rand, "<br />");
properResults.push(rand);
}
});
Here is the main idea of a solution. You can define the max value as a parameter for the random.
Then, check the existence of the item in a simple array with only the data you want.
You may use a general function which generates random numbers from 1 to maxValue, and adds them to an array only if they don't exist. Then, to display, cycle through the array items and append them to #randomNumbers.
HTML
<div id="randomNumbers"></div>
JS (with jQuery)
var randomNumbersArray = [];
$(function() {
generateRandomNumbers();
displayRandomNumbers();
});
function generateRandomNumbers() {
for (i = 0; i < 5; i++) {
generateRandomNumberFrom1To(45);
}
generateRandomNumberFrom1To(25);
}
function generateRandomNumberFrom1To(maxValue) {
var randomNumber;
do {
randomNumber = Math.ceil(Math.random() * maxValue);
} while ($.inArray(randomNumber, randomNumbersArray) > -1);
randomNumbersArray.push(randomNumber);
}
function displayRandomNumbers() {
for (i in randomNumbersArray) {
$("#randomNumbers").append(randomNumbersArray[i] + "<br>");
}
}

Self adjusting random list

I have a grid of 9 columns by 3 rows (so each column has 3 slots). A minimum of one slot in every column must be marked and no more than 3 can be marked. A mark is represented by a 1,2 or 3 digit.
There must always be 15 marked slots in total. To achieve this I tried the following:
var valueLeft = 15;
while (valueLeft > 0)
{
var ranValue = utils.getRandomInt(1,3);
console.log('slots remaining: ' + (valueLeft - ranValue));
if (ranValue >= valueLeft)
{
ranValue = valueLeft;
}
valueList.push(ranValue);
valueLeft -= ranValue;
}
console.log(valueList);
But this often gives me an array of numbers with less than 9 elements inside. I can see that my logic is flawed but I am pulling my hair out trying to figure out how I can get it to always give a set of 9 elements which all add up to 15.
For example what I might end up with is:
[2, 1, 1, 1, 1, 2, 3, 1, 2, 1]
When what I need for example is:
[2, 2, 1, 1, 1, 1, 3, 2, 2]
or
[2, 2, 1, 2, 1, 1, 3, 2, 1]
and so on.
Any advice appreciated. Feel free to flame me for my poor sense of logic :)
This answer shows a similar approach to many of those already posted, but I feel as though they're making it too complicated. It can be very straightforward:
function pad(list, size) {
var total = list.length;
while (total != size) {
var i = utils.getRandomInt(0, 8);
if (list[i] < 3) {
list[i]++;
total++;
}
}
return list;
}
var valueList = pad(new Array(1,1,1,1,1,1,1,1,1), 15);
You don't need a lot of cases. Just -- as many others have already said -- init the array with 1's. Then, simply add one to random elements (whose value isn't already 3) until the total is 15.
why don't you do this:
start off with an array that looks like this: 1,1,1,1,1,1,1,1,1
then make a function that picks a random number between 0 and 8 6 times.
if the same number has been picked more than twice, skip it and pick a new one
then correlate those 6 numbers to the index of the array and add 1 for each time it picks that number.
var i; var valueList = new Array(1,1,1,1,1,1,1,1,1);
for(i=0;i<6;i++)
{
var ranNum = utils.getRandomInt(0,8);
if(valueList[ranNum]<3) valueList[ranNum]+=1;
else i--;
}
just tested it, changed <=6 to <6 and it's working for me. Good luck!
Following logic should work. You should select a random value (within 1-3) such that choosing that would not lead us to not able to select a random value for further slots.
var gridLeft = 9
var valueLeft = 15
while(gridLeft>0) {
var ranValue
while(true) {
ranValue = utils.getRandomInt(1,3);
if (valueLeft-ranValue > 3*(gridLeft-1))
continue;
else if (valueLeft-ranValue < 1*(gridLeft-1))
continue;
else
break;
}
valueList.push(ranValue);
valueLeft -= ranValue;
gridLeft -= 1
}

Categories

Resources