Understanding a function with modulo in Javascript - javascript

I had this code written by a user here yesterday and I'm having trouble understanding it. I understand all by line 9 of the deal function, it creates a random card out of 52 numbers but on the next line I don't understand what this does. Could somebody please explain what this code does so I could modify it and expand on it?
//Creates the deck
var Ace = 1;
var Face = 10;
var deck = [Ace, 2, 3, 4, 5, 6, 7, 8, 9, 10, Face, Face, Face];
/*Creates a deal function that can deal cards to each player.
Use object_name.property_name = deal() to call this function.*/
var deal = function () {
var randomcard = Math.ceil(Math.random() * 52) + 1;
return deck[Math.floor(randomcard % 13)];
};

Well, first let's correct the code. The original code does give you a working result, but it does it in a confusing way. It doesn't pick a value between 0 and 51 which would be the natural thing to do, it picks a value between 2 and 53. (The result is still useful for getting a value between 0 and 12 to use for a value, but getting the suit for the card is not very straight forward.)
var randomcard = Math.floor(Math.random() * 52);
return deck[randomcard % 13];
The modulo operator gets the reminder from a division, so the result from the expression would get the value for the card. Up to 12 it returns the number itself, then at 13 it starts over at 0 again.
To get the index for the suit for the card, you would use Math.floor(randomcard / 13). With the original random value (2 to 53) you would have needed to use (Math.floor(randomcard / 13) % 4) instead.

There are 52 cards in the deck. 13 different values with 4 different suit( clubs/diamonds...). Note 4 * 13 = 52. The modulus 13 is just there to assure that one of the values from in the deck variables gets picked, and the suit is ignored.

You have an array of only 13 items -- the cards. 0 through 12.
If you take any number and % 13 it, you will always get a value between 0 and 12 -- the remainder of a division of that number by 13. The deck of 52 then % 13 basically reduces the deck from suit + card to just card.
This could have equally been written as Math.ceil(Math.random() * 13) + 1 instead of 52. However if the code needs to be expanded to also have a suit, then you might likely

The code is only half-valid. The modulo is poorly selecting the type of card to draw out of the deck, but not the suit the card is. In addition, the code doesn't account for having already dealt out a specific card (it's never removed from the deck), so multiple players could have identical cards.
See this page for information on how deck structure looks in JavaScript:
http://www.brainjar.com/js/cards/default2.asp

Related

JS function that creates a range of numbers (inclusive beginning and end) with a limit on range items

You are given a starting number and ending number and the max number of output elements allowed. How would you create an output array with as even a distribution as possible, while still including the first and last points in the output?
Function signature
function generatePoints(startingNumber, endingNumber, maxPoints) {}
Function desired output
generatePoints(0, 8, 5) // [0, 2, 4, 6, 8]
Here's what I tried so far
function generatePoints(startingNumber, endingNumber, maxPoints) {
const interval = Math.round((endingNumber - startingNumber) / maxPoints)
let count = 0
let counter = 0
let points = []
while(count < maxPoints - 1) {
points.push(counter)
counter+=interval
count++
}
points.push(endingNumber)
return points
}
Technically this creates the correct output for the simple case, but falls short when up against most other edge cases due to the fact that I'm stopping one iteration early and then adding the final point. I'm thinking that the better way to do this (to create a better distribution) is to build from the center of the array outwards, versus building from the start of the array and then stopping one element early and appending the endingNumber.
Note this:
0 2 4 6 8
+-----+ +-----+ +-----+ +-----+
A B C D
Splitting our range into intervals with 5 points including the endpoints, we have only four intervals. It will always be one fewer than the number of points. We can divide our range up evenly into these smaller ranges, simply by continually adding the width of one interval, which is just (endingNumber - startingNumber) / (maxPoints - 1). We can do it like this:
const generatePoints = (startingNumber, endingNumber, maxPoints) => Array .from (
{length: maxPoints},
(_, i) => startingNumber + i * (endingNumber - startingNumber) / (maxPoints - 1)
)
console .log (generatePoints (0, 8, 5))
We just build an array of the right length, using the index parameter to count the number of smaller intervals we're using.
We do no error-checking here, and if maxPoints were just 1, we might have an issue. But that's easy enough to handle how you like.
But there is a concern here. Why is the parameter called maxPoints instead of points? If the number of points allowed is variable, I think we need further requirements.
Do not Math.round(interval). Instead Math.round(counter) at that last moment.
The reason why is that if you've added k intervals, the error in what you're going can be as much as 0.5*k. But if you round at the last minute, the error is never more than 0.5.

js, if number is divisible and not decimal

I'm working on a code that counts the meters some dogs have travelled. It's just a gif constantly in loop. Now I wanted to show an image every 50 meters for like 3 seconds.
That's how I have tried it:
if (i % Number.isInteger(50)) {
document.getElementById("orange").style.display = "block";
}
That's how I've tried it but it doesn't work.
Can someone help me with that?
Thanks!
You can use FLOOR:
let frames = Math.floor(i / 50)
That will be 0 until 1==50, then it'll be 1 until i==100.
So 1234 steps will give you 24 frames played.
Then you have to decide how many images you have, lets say 5 images:
let currentImageIndex = itterations % 5;
That'll make it it go 0,1,2,3,4,0,...
That means in our example: 24%5 = 4, display the 5th image (because 0 is the first, that makes 4 the fifth image).
document.getElementById("my-image").src = `frame${currentImageIndex}.png`;
If the person would take a few steps more, 1251 steps, divided by 50 = 25 frames, modulo 5 -> currentImageIndex==0.
Note: this is untested, but should give you something to build off of
Note: Your current solution isnt working because Number.isInteger(50) always returns true because 50 is an integer. It doesnt convert anything, it just tests of it is an integer.

leetcode house robber incorrect output

I was doing this leetcode question: https://leetcode.com/problems/house-robber/
The question is
You are a professional robber planning to rob houses along a street.
Each house has a certain amount of money stashed, the only constraint
stopping you from robbing each of them is that adjacent houses have
security system connected and it will automatically contact the police
if two adjacent houses were broken into on the same night.
Given a list of non-negative integers representing the amount of money
of each house, determine the maximum amount of money you can rob
tonight without alerting the police.
With following example
Input: nums = [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.
I wrote the following code for this
/**
* #param {number[]} nums
* #return {number}
*/
var rob = function(nums) {
if (nums.length === 0) return 0
let output = i = 0
while (i < nums.length) {
const currentHouse = nums[i]
i = i + 2
output += currentHouse
}
return output
};
console.log(rob([1, 2]));
console.log(rob([1, 2, 3, 1]));
but it fails for this particular
Input:
[1,2]
Output:
1
Expected:
2
I am not sure why the output should be 2 for the above test?
Your algorithm just takes the houses at even indexes without taking into account that you have different options.
For instance when there are 5 houses (numbered 0 to 4) you can consider the following alternatives:
rob house 0, 2 and 4
rob house 0 and 3
rob house 1 and 3
rob house 1 and 4
Each of these could be the optimal strategy for the robber... it all depends on the amounts of money in the houses. For instance:
When input is [1,1,1,1,1] then strategy 1 is optimal and your program produces the correct output (3)
When input is [2,1,1,3,1] then strategy 2 is optimal (5), while your program will output 4.
When input is [1,2,1,3,1] then strategy 3 is optimal (5), while your program will output 3.
When input is [1,3,1,1,2] then strategy 4 is optimal (5), while your program will output 4.
Once you realise you need to look at different patterns, you can see that sometimes you need skip a house even if it was not adjacent to a previously robbed house. It is also not guaranteed that robbing the first house is optimal. On the other hand, it is never optimal to skip 3 houses in row, as you then might as well rob the middle of those, as it is not adjacent to another robbed house.
You can have an algorithm that progressively adds a house to the problem, and keeps track what was the best for the two previous sub problems (so with 2 or 1 fewer houses).
We can then look at the situation where we rob the newly added house or not. If we rob it, we should add the money to the money we got from the problem with 2 fewer houses. If we don't rob it, we should just copy what we got from the problem with 1 fewer houses.
This is a so-called bottom up approach:
function rob(nums) {
// Represent the optimal amount we get from a problem with fewer houses:
let sumTwoHousesLess = 0;
let sumOneHouseLess = 0;
let sum = 0; // The amount for a problem without any houses.
for (let money of nums) { // Add a house to the problem in each iteration
// See what is best: rob this house or not:
sum = Math.max(money + sumTwoHousesLess, sumOneHouseLess);
// Shift the information we have, as we are about to go to the next house
sumTwoHousesLess = sumOneHouseLess;
sumOneHouseLess = sum;
}
return sum;
}
console.log(rob([1,2])); // 2
console.log(rob([1,1,1,1,1])); // 3
console.log(rob([2,1,1,3,1])); // 5
console.log(rob([1,2,1,3,1])); // 5
console.log(rob([1,3,1,1,2])); // 5

Logic for my land size calculator application

I'm making this acres and karats calculator for my uncle to help him in his work.
I'll explain the whole idea of this thing with this example. So if you add 3.22 + 2.2 it should be = 5.42 but in this calculator 3.22 + 2.2 should = 6, because 3 acres + 2 acres = 5 acres and 22 karats + 2 karats = 1 acre, so the total would be 6 acres.
The way I'm doing it in the code is that I'm splitting a number like 3.22 to two, 3 and 22 and the other number to 2 and 2 and I add the whole numbers together and the fractions together and if the fractions are >= 24 I add one to the whole numbers and if there're fractions left from the whole calculation I leave it. For example 3.15 + 2.15 = 6.6, but I'm stuck on how I can add the numbers, there's also an error in there that I don't know how to resolve.
Anyway here's the code
function getValue(v) {
return +v.toString().match(/\.(\d*)/)[1] || 0;
}
function getTotal() {
d += Math.floor(num);
p += getValue(num);
if (p >= 24) {
p -= 24;
++d;
}
total = d + p / 100;
ptag.textContent = total;
}
I added the part of the code where I'm stuck.
Note: I'm trying to make the thing able to add multiple numbers not only two. Also I'm trying to add subtraction but I have no idea how to start working on the subtraction because I haven't even finished the addition.
If the error you are talking about is something like this:
Uncaught TypeError: Cannot read property '1' of null
It is because of your getValue function.
My suggestion is, instead of using something as complicated as
function getValue(v) {
return +v.toString().match(/\.(\d*)/)[1] || 0;
}
use
function getValue(v) {
return floor((v % 1) * 100);
}
This has the same effect as the code you wrote. Which for example, from input 3.13, returns 13.
But there are few other problems.
First, you should update your num variable every now and often, otherwise, it is always going to stay as an empty string (you only defined it on line 20, and you didn't update it after that).
Second, you should clear the d and p variable after you use. As of right now, both of these variables just keeps on increasing every time you run the getTotal function
For your question of how you can add two numbers, I suggest you to create a variable where you can store the first number that the user typed.
For example, when the user typed in 4.19 and pressed the plus button, save that 4.19 into a variable (let's say firstNum).
Then when the user pressed equal button, add the number from the current input field with the firstNum variable.
On how exactly you are going to add two different numbers, break two numbers you want to add into Acres part and Karats parts. Then add them separately, then use your getTotal.
So if the number is 3.21 and 5.18, add 3 and 5, add 21 and 18, then add both of them.
you'll get 8.39. Finally, convert 8.39 into 9.15.
Sorry if my calculation is not correct. It is my first time with this concept!
But I believe this is the way to go.

Order of operations for Math.floor(Math.random() * 5 + 1)?

In the Code Academy JS course, Dragon Slayer 2/6, the following text is used in the hint to describe the order of operations for the code I included in the title.
How does this code work?
Math.floor(Math.random() * 5 + 1);
First we use Math.random() to create a random number from 0 up to 1. For example, 0.5
Then we multiply by 5 to make the random number from 0 up to 5. For >example, 0.5 * 5 = 2.5
Next we use Math.floor() to round down to a whole number. For example, >Math.floor( 2.5 ) = 2
Finally we add 1 to change the range from between 0 and 4 to between 1 and >5 (up to and including 5)
I've looked this up in several different places (here and here), and a majority of them either focus on the range that Math.random() produces (which I understand) or confirm the order of operations outlined in the hint, wherein "Math.floor" acts upon "Math.random()*5" prior to the "+1" being added.
It seems to me however that, according to the order of operations that I learned in school, the last two steps should be flipped. Would that not be the case since "Math.random()*5" and the "+ 1" are both within the parenthesis?
While the difference between these two might not make a difference in the value returned from this particular code, I could see a fundamental change in the order of operation like the one outlined here would cause me some frustration further down the road if I didn't know it.
Math.floor() will work on whatever is inside the brackets, after it has been calculated.
Math.floor(Math.random() * 5 + 1)
is the same as
var i = Math.random() * 5;
i += 1;
Math.floor(i);
You are correct that the wording on the page is wrong. The last thing that will happen is the floor call. Everything in the parenthesis will be processed first.
Honestly, I think they mixed up here, and you're right. According to PEMDAS and any mathematics I've ever learned, the +1 comes before the Math.floor function.
The Math.random() function returns a random number in the range [0, 1) that is, from 0 (inclusive) up to but not including 1 (exclusive). It can be any thing like 0,.34,.42 etc.
if you want random number between 0-5.
you will used Math.Random()*5. This will give you any number like 0,4.43.4.34 but not five.
Then we add 1 like this Math.random() * 5 + 1. Now the chances is you will get a number which is between 0 and 6. But you don't want number above 5. so
you apply floor method which will return largest integer less than or equal to a given number.

Categories