I trying to create a points calculating system with javascript, but the problem is with the mathematical part. I have saved on the server the points number, and based on that number I want to decide the level. Sorry for my bad english, I cant explain very well :D. I want something like: level 1 need 0 points
level 2 needs 100 points
level 3 needs 240 points
level 4 needs 420 points
level 5 needs 640 points
and so on....
I need a mathematical function to calculate each level with it. Something that if I know the level to calculate the points needed, and if I know only the points to calculate the level.
To generate the series you've provided use:
function getPoints(level)
{
return 20*(level-1)*(level+3);
}
To get the level from the points is a bit more tricky, you need to invert the above formula using the quadratic formula and then take the positive solution:
function getLevel(points)
{
var level = -1 + Math.sqrt(4 + points/20);
// Round down to nearest level
return Math.floor(level);
}
Also, in the future try and make your questions clearer. As you can see three people (at least) misunderstood your question - it wasn't clear that you set of levels was a mathematical series.
var levels = {
1: 0,
2: 100,
3: 240,
4: 420,
5: 640}
function get_level(points){
for (level in levels){
if (points < levels[level]){
return level - 1;
}
}
}
This simply takes the levels hash and itenerates through the levels, until the points is higher than the level's minimum, returning the last level.
ummm, I have a vague idea of what you're going for
var levels = [0, 100, 240, 420, 640];
function GetLevel(points)
{
for(i == levels.length - 1; i >= 0; i--)
{
if (points >= levels[i]) return i + 1;
}
}
points to next level
function PointsToNextLevel(currentPoints)
{
var level = GetLevel(currentPoints);
if (level == levels.length) return 0;
return levels[level - 1] - currentPoints;
}
this function should solve your problem and, to me, seems very easy to understand:
function getLevel(points)
{
var levels = [0,100, 240, 420, 640];
var maxLevel = levels.length;
var i;
for (i=0;i<maxLevel;i++) {
if (levels[i]>points) return i;
}
return maxLevel;
}
Related
I'm working on the stonewall exercise of codility. Getting 100% on the correctness tests, but failing all of the performance tests. I'm having trouble envisiging why my solution may be fine for smaller inputs but is going so wrong for larger inputs. Is anyone able to offer feedback about what might be wrong with my solution? I've found this one quite challenging. Taken me a few days of revisiting just to get to this stage! Thanks in advance.
The problem
You are going to build a stone wall. The wall should be straight and N
meters long, and its thickness should be constant; however, it should
have different heights in different places. The height of the wall is
specified by an array H of N positive integers. H[I] is the height of
the wall from I to I+1 meters to the right of its left end. In
particular, H[0] is the height of the wall's left end and H[N−1] is
the height of the wall's right end.
The wall should be built of cuboid stone blocks (that is, all sides of
such blocks are rectangular). Your task is to compute the minimum
number of blocks needed to build the wall.
Write a function:
function solution(H);
that, given an array H of N positive integers specifying the height of
the wall, returns the minimum number of blocks needed to build it.
For example, given array H containing N = 9 integers: H[0] = 8
H[1] = 8 H[2] = 5 H[3] = 7 H[4] = 9 H[5] = 8 H[6] = 7
H[7] = 4 H[8] = 8
the function should return 7. The figure shows one possible
arrangement of seven blocks.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
each element of array H is an integer within the range [1..1,000,000,000].
My solution
function solution(H) {
let stones = 0
let absoluteMinimum = Infinity;
let prevStones = []
for (let i = 0; i < H.length; i++) {
if (H[i] < absoluteMinimum) {
stones ++
absoluteMinimum = H[i]
prevStones = [H[i]]
} else if (prevStones.includes(H[i])) {
while (prevStones.includes(H[i])) {
prevStones.pop()
}
prevStones.push(H[i])
} else if (H[i] != H[i-1]) {
prevStones.push(H[i])
stones ++
}
}
return stones
}
Here is the summary of my attempt including test results.
https://app.codility.com/demo/results/training2V8Y42-AUQ/
Following #Teemu's comment, and noting that the code simply is searching prevStones for the existence of a specific height, suggest creating another array that holds the counts of the heights in prevStonesCount.
Eg, if setting prevStones = [ 8 ] then set prevStonesCount[ 8 ] = 1, as there is one stone in the prevStones array of height 8.
Now, rather than having to perform prevStones.includes( 8 ), simply check if 0 < prevStonesCount[ 8 ]. (That is, .includes() searches the entire prevStones array for a height of 8, whereas prevStonesCount[ 8 ] in one step indicates whether any stones of height 8 are in the prevStones array.)
Thus, anytime performing a prevStones.push( x ) or prevStones.pop( x ), make the corresponding adjustment of prevStonesCount[ x ] += 1 or prevStonesCount[ x ] -= 1, respectively.
Note also that within the first if where prevStones = [H[i]], that the prevStones array is essentially cleared and set to an initial value. This means that the prevStonesCount array will also need to be cleared, and then set prevStonesCount[ H[i] ] = 1.
I'm trying to make an animation recorder that records x,y positions into an array and allow the animation to be recalled. I specifically have p5.js in mind as the graphics lib, but any should work. since this is just array work.
in p5.js to return the value of Sin() or Cos() you can pass them an angle, that angle can be ever incrementing since 2PI == 4PI (in terms of the direction the rotation is facing) etc. I'm looking to replicate this kind of function but to return the data stored in an array.
so for example you've got an array like the following
let demo = ['297', '298', '299', '300']
It would be easy to loop over the array once since it has 4 items, but I'd like to write a function where if we passed in 4, it would return index 0, '297' or if we fed in 11, it would return '300' or if we fed in 22 it would return '299'
this way the function could continually be fed in an ever increasing value that moves up each frame we could return the values of the array in a loop.
let survey = 0;
let demo = ['297', '298', '299', '300']
//a rendering loop
function draw(){
survey ++
let xPos = getPosition(survey) //this getPosition function is the one in question
ellipse(xPos,100,50)
}
I feel like this is some modulo math, but I cant quite get it sorted.
thanks for taking a look!
The solution to your problem is the modulus (%) operator. This operator will return the remainder of the division.
E.g. 11 % 4 = 3
const positions = [297, 298, 299, 300];
function getPosition(positions, i) {
return positions[i % positions.length];
}
console.log(getPosition(positions, 4)); // 297
console.log(getPosition(positions, 11)); // 300
console.log(getPosition(positions, 22)); // 299
I am trying to solve the problem of finding the number of paths in a lattice (some grid) using recursion.
I wrote the following code which suppose to find total number of valid paths in a lattice/grid. In a valid path (to the bottom right corner of the grid), you can only move in one of two directions: right or down.
I'm not sure it is correct way of using recursion.
Is there any better way of solving this problem / using recursion to solve it?
Thanks
var array = [[0,0,0,0],[0,0,0,0],[0,0,0,0]];
var lastRowIndex=2;
var lastColIndex=3;
var count=0;
function pathCount(i,j){
if(!(array[i-1]==undefined) || !(array[i][j-1]==undefined)){
if(!(array[i-1]==undefined)){
--i;
pathCount(i,j);
i++;
}
if(!(array[i][j-1]==undefined)){
--j;
pathCount(i,j);
}
}else{
++count;
}
return count;
}
console.log(pathCount(lastRowIndex,lastColIndex));
Your code is fine. basically it does what it should.
Assuming a valid path is constructed only by moving down the grid or moving to the right,
notice you don't actually need the array, just a size parameter and a pointer to the current position traveled by your algorithm.
As any regression problem let us start by something simple, an induction basis.
First notice, in a linear grid (size 1xN or Nx1) there is only one valid path.
Now, if you are at the (i,j) square, you only have 2 possibilities of moving, hence
the total number of paths is a sum of two element:
The number of valid paths from square (i-1,j)
The number of valid paths from square (i,j-1)
(notice a validity check on these argument is needed, since they are bounded by the possible indices of the grid).
so a possible recursion is:
let size = 10;
let grid = {
width: size,
height: size
};
let currentPosition = {
x: size,
y: size
};
function validDecrement(value) {
return (value - 1 >= 1 ? value - 1 : 1);
}
function countValidPaths(gridObject, startingLocation) {
if (startingLocation.x === 1 || startingLocation.y === 1) {
return 1;
} else if (startingLocation.x > 1 && startingLocation.y > 1) {
return countValidPaths(gridObject, {
x: startingLocation.x,
y: validDecrement(startingLocation.y)
}) + countValidPaths(gridObject, {
x: validDecrement(startingLocation.x),
y: startingLocation.y
});
} else {
console.log(`invalid input: grid: ${gridObject}, startingLocation: ${startingLocation}`);
};
}
console.log(`Number of valid paths over a ${grid.height} by ${grid.width} grid is : ${countValidPaths(grid,currentPosition)}`);
Of course - there is a much better approach to solving this method rather than a recursion. the number you are seeking is simply the binomial coefficient C((grid.with-1)+(grid.height-1),(grid.width-1)) - lattice paths counting
TL;DR I want to display a long-running strip chart with Plotly.js. I don't know how to discard old points.
Details
The following updater from my CodePen at https://codepen.io/Michael-F-Ellis/pen/QvXPQr does almost what I want. It shows a set of 20 samples in 2 traces that update continuously at 500 msec intervals. At the end of the demo, it plots all the points to show they still exist.
var cnt = 0;
var interval = setInterval(function() {
// Add next point to each trace
Plotly.extendTraces('graph', {
y: [[rand()], [rand()]]
}, [0, 1])
// Display only 20 most recent points
Plotly.relayout('graph', { 'xaxis.range': [cnt-20, cnt]})
cnt = cnt+1;
if(cnt === 100) {
// Before ending the run, show all points
// to demonstrate they still exist in Plotly.
Plotly.relayout('graph', { 'xaxis.range': [0, cnt]});
clearInterval(interval);
}
}, 500);
The problem is that I do want to delete older points. The real application needs to run essentially forever on a system with limited memory. I'm looking for a Plotly call that will drop the oldest N trace points. It needs to be reasonably efficient as performance of the target system is also limited.
Thanks!
https://codepen.io/Michael-F-Ellis/pen/YxeEwm
The above seems workable from a behavioral standpoint. Here's the revised updating routine:
Plotly.plot('graph', data);
var cnt = 0;
var max = 20;
var interval = setInterval(function() {
// Add next point to each trace
Plotly.extendTraces('graph', {
y: [[rand()], [rand()]]
}, [0, 1])
// Keep only 'max' most recent points
if(cnt > max) {
data[0].y.shift();
data[1].y.shift();
}
cnt = cnt+1;
if(cnt === 100) {
// Before ending the run, show all points
// to demonstrate that only 'max' points
// still exist in Plotly.
Plotly.relayout('graph', { 'xaxis.range': [0, cnt]});
clearInterval(interval);
}
}, 500);
The solution is to keep the data object in a var outside of Plotly and use shift() to drop old points from the beginning of the array as new points are added.
I'm open to another solution, especially if there are known memory or performance problems with this approach.
With a lack of math neurons in my brain, i struggle a bit in finding my way around this.
I need to create a simple javascript function that will receive three parameters:
A one-dimensional, normal indexed Array with X elements (the values being unique IDs)
A target ID to select
An amount of elements to return
The third parameter would ask the function to return a set of elements, with the element having the target ID being either in the center of the result, or next to it.
The result of the function should be an array as well.
A few examples to make it a more visual explanation:
function([100,120,140,160,180,200], 120, 3)
// should return [100,120,140]
function([100,120,140,160,180,200], 160, 4)
// should return [140,160,180,200]
function([100,120,140,160,180,200], 180, 5)
// should return [140,160,180,200,100]
The case covered by the last example is what confuses me while writing the code, which i am currently attempting to, but i find myself writing strange conditions, numerous if-statements and code that generally seems like a work-around. Also the cases of parameter 3 being larger than the amount of elements in parameter 1 are a bit of an over-brainer for me.
I feel unsafe continuing with this code, because it feels buggy and simply not proper. Surely somebody with proper math skills could provide me with the theory i need to understand how to accomplish this in a more elegant fashion.
Theory or pseudo-code will suffice, but if someone has something like this ready at hand, please don't hesitate to share it.
Thank You!
(Here is what i have written so far - based on the prototype JS class implementation)
var CBasicMatrix=Class.create({
initialize: function(elementList){
this.elementList=elementList;
},
select: function(id, amount){
if(amount>this.elementList.length)
amount=this.elementList.length;
if(!this.elementList.length) return false;
var elementIndex=this.elementList.indexOf(id);
if(elementIndex==-1) return false;
var isRound=amount%2==0;
var amountHalf=isRound ? (amount/2) : (Math.ceil(amount/2)-1);
// [464,460,462,461,463]
var result=[];
if(elementIndex-amountHalf >= 0) {
var startIndex=(elementIndex-amountHalf);
for(i=startIndex;i<=startIndex+amount;i++){
result.push(this.elementList[i];
}
} else {
// more seemingly stupid iterative code coming here
}
}
});
Edit: In order to make this more understandable i will state the purpose. This code is supposed to be used for kind of a slideshow, in which multiple elements (parameter 3) are visible at the same time. Parameter 1 is the list of (the IDs of the) total elements in their correct order as they appear in the HTML declaration. Parameter 2 is the element that is currently selected and therefore should appear in the middle.
Here is my solution:
function method(arr, value, n) {
var result = [],
len = arr.length,
index = arr.indexOf(value);
for (var i = 0; index > -1 && i < n ; i++) {
result.push(arr[(len + index - ~~(n / 2) + (n % 2 ^ 1) + i) % len]);
}
return result;
}
TESTS:
var arr = [100, 120, 140, 160, 180, 200];
method(arr, 120, 3); // [100, 120, 140]
method(arr, 160, 4); // [140, 160, 180, 200]
method(arr, 180, 5); // [140, 160, 180, 200, 100]
method(arr, 100, 3); // [200, 100, 120]
I will help you by providing a pseudo code :
1 . if there is no match you should return an empty array.
2 . if there is a match you just divide the third parameter by 2, you take the result , you loop from the element found's index minus the previous result until the third parameter's value and you store the elements in a new array.
3 . you return the new array.
Update:
I saw your code and I don't see any problem with it.
After some careful debugging and overthinking my approach, i managed to find a solution that seems proper and safe. I am sure this could be optimised further and if anyone has any suggestions, feel free to share them.
var CBasicMatrix=Class.create({
initialize: function(elementList){
this.elementList=elementList;
},
select: function(id, amount){
if(amount>this.elementList.length)
amount=this.elementList.length;
if(!this.elementList.length) return false;
var elementIndex=this.elementList.indexOf(id);
if(elementIndex==-1) return false;
var isRound=amount%2==0;
var amountHalf=isRound ? (amount/2) : (Math.floor(amount/2));
var result=[];
var startIndex=(elementIndex-amountHalf);
var endIndex=(startIndex+amount-1);
var targetIndex=0;
for(i=startIndex;i<=endIndex;i++){
targetIndex=i;
if(i>this.elementList.length-1) targetIndex=i-this.elementList.length;
if(i<0) targetIndex=i+this.elementList.length;
result.push(this.elementList[targetIndex]);
}
return result;
}
});