Value check during iteration of a loop - javascript

So I've been sent a technical test for a job interview, I've done the vast majority of it but having an issue with one part. Effectively, it needs to check whether the health of the elephant is under 70, if it is it can no longer walk, if this is still the case on the next iteration of the interval, it needs to pronounce them dead. My code works some of the time but also allows them to go straight from healthy to dead and it also seemingly allows them to not die when the iteration happens when they can't walk.
Below is the code and a JS fiddle.
https://jsfiddle.net/Stackz18/dprk1fto/3/
var timer = 0;
var monkeyArray = [100, 100, 100, 100, 100];
var giraffeArray = [100, 100, 100, 100, 100];
var elephantArray = [100, 100, 100, 100, 100];
function feedingMonkeys() {
for (let i = 0; i < monkeyArray.length; i++) { //loop through array
var feedingNumber = parseInt(Math.floor(Math.random() * 16) + 10); //create unique random number between 10 and 25
if (monkeyArray[i] <= 100 && monkeyArray[i] >= 30) { // if between 99 and 30 run the code
monkeyArray[i] = monkeyArray[i] + feedingNumber; // add random number to array value
let TransformedArray = monkeyArray.map(item => item >= 100 ? 100 : item <= 29 ? 'Dead' : item); //remap array in new array to show status of animal
$('.m-health').each(function (i, obj) {
this.innerHTML = TransformedArray[i]; // change html value to the new mapped array values
});
}
else if (monkeyArray[i] >= 100) {
monkeyArray[i] = 100;
}
}}
function feedingGiraffes() {
for (let i = 0; i < giraffeArray.length; i++) { //loop through array
var feedingNumber = parseInt(Math.floor(Math.random() * 16) + 10); //create unique random number between 10 and 25
if (giraffeArray[i] <= 100 && giraffeArray[i] >= 30) { // if between 99 and 30 run the code
giraffeArray[i] = giraffeArray[i] + feedingNumber; // add random number to array value
let TransformedArray = giraffeArray.map(item => item >= 100 ? 100 : item <= 29 ? 'Dead' : item); //remap array in new array to show status of animal
$('.g-health').each(function (i, obj) {
this.innerHTML = TransformedArray[i]; // change html value to the new mapped array values
});
}
else if (giraffeArray[i] >= 100) {
giraffeArray[i] = 100;
}
}}
function feedingElephants() {
for (let i = 0; i < elephantArray.length; i++) { //loop through array
var feedingNumber = parseInt(Math.floor(Math.random() * 16) + 10); //create unique random number between 10 and 25
if (elephantArray[i] <= 100) { // if under 100 run the code
elephantArray[i] = elephantArray[i] + feedingNumber;
let TransformedArray = elephantArray.map(item => item >= 100 ? 100 : item <= 70 ? item + ': Can no longer walk' : item);
console.log(TransformedArray);
$('.e-health').each(function (i, obj) {
this.innerHTML = TransformedArray[i];
});
if (elephantArray[i] > 70) {
$(this).parents(".elephant").removeClass("walk");
}
}
else if (elephantArray[i] >= 100) {
elephantArray[i] = 100;
}
}
}
function feeding() {
feedingMonkeys();
feedingGiraffes();
feedingElephants();}
function monkeyHealth() {
for (let i = 0; i < monkeyArray.length; i++) {
var removeNumber = parseInt(Math.floor(Math.random() * 21));
monkeyArray[i] = monkeyArray[i] - removeNumber;
}
let TransformedArray = monkeyArray.map(item => item >= 100 ? 100 : item <= 29 ? 'Dead' : item);
$('.m-health').each(function (i, obj) {
this.innerHTML = TransformedArray[i];
if (monkeyArray[i] < 30) {
$(this).parents(".monkey").addClass("dead");
}
});}
function giraffeHealth() {
for (let i = 0; i < giraffeArray.length; i++) {
var removeNumber = parseInt(Math.floor(Math.random() * 21));
giraffeArray[i] = giraffeArray[i] - removeNumber;
}
let TransformedArray = giraffeArray.map(item => item >= 100 ? 100 : item <= 29 ? 'Dead' : item);
$('.g-health').each(function (i, obj) {
this.innerHTML = TransformedArray[i];
if (giraffeArray[i] < 30) {
$(this).parents(".giraffe").addClass("dead");
}
});}
function elephantHealth() {
for (let i = 0; i < elephantArray.length; i++) {
if (elephantArray[i] <= 70) {
let TransformedArray = elephantArray.map(item => item >= 100 ? 100 : item <= 70 ? 'Dead' : item);
$('.e-health').each(function (i, obj) {
this.innerHTML = TransformedArray[i];
if (elephantArray[i] < 70) {
$(this).parents(".elephant").removeClass("walk");
$(this).parents(".elephant").addClass("dead");
}
});
}
else {
let TransformedArray = elephantArray.map(item => item >= 100 ? 100 : item <= 70 ? item + '%: Can no longer walk': item);
$('.e-health').each(function (i, obj) {
this.innerHTML = TransformedArray[i];
if (elephantArray[i] <= 70) {
$(this).parents(".elephant").addClass("walk");
}
});
}
var removeNumber = parseInt(Math.floor(Math.random() * 21));
elephantArray[i] = elephantArray[i] - removeNumber;
}}
var intervalId = window.setInterval(function () {
timer += 1;
if (timer >= 24) {
timer = 0
}
document.getElementById("hour").innerHTML = timer;
monkeyHealth();
giraffeHealth();
elephantHealth();
}, 2000);

Related

I want to check the grade of the students marks , based on average

What's wrong with this code? I tried get marks using array and pass the array in to function parameters and calculate the average in that function.
const marks = [100,100,80];
var summ = 0;
function calculateGrade(){
for(let i=0; i<=marks.length;i++){
summ = summ+marks[i];
var avg = (summ/marks.length);
}
if(avg<=59){
console.log('F');
}
else if(avg>=60 && avg<=69){
console.log('D');
}
else if(avg>=70 && avg<=79){
console.log('C');
}
else if(avg>=80 && avg<=89){
console.log('B');
}
else if(avg>=90 && avg<=100){
console.log('A');
}
}
console.log(calculateGrade(marks));
const sum = marks.reduce((partialSum, a) => partialSum + a, 0);
const marks = [100, 100, 80];
var summ = 0;
//issue one (Tmarks were missing )
function calculateGrade(Tmarks) {
// issues 2 ( <= should be < )
for (let i = 0; i < Tmarks.length; i++) {
summ += Tmarks[i];
}
var avg = summ / Tmarks.length;
if (avg <= 59) {
console.log("F");
} else if (avg >= 60 && avg <= 69) {
console.log("D");
} else if (avg >= 70 && avg <= 79) {
console.log("C");
} else if (avg >= 80 && avg <= 89) {
console.log("B");
} else if (avg >= 90 && avg <= 100) {
console.log("A");
}
}
console.log(calculateGrade(marks));
Following were the issues in your code
You were not getting the parameters in function definition
issues 2 ( <= should be < )
You just added an extra = in your for loop
i<=marks.length
instead of
i<marks.length
So while calculating the sum & average, a garbage value gets added up.
You are very close
const marks = [100, 100, 80];
function calculateGrade(marks) {
let summ = 0;
for (let i = 0; i < marks.length; i++) {
summ += marks[i];
}
const avg = summ / marks.length;
let grade = '';
if (avg < 59) {
grade = 'F';
} else if (avg <= 69) {
grade = 'D';
} else if (avg <= 79) {
grade = 'C';
} else if (avg <= 89) {
grade = 'B';
} else {
grade = 'A';
}
return grade;
}
console.log(calculateGrade(marks));
There are couple of mistakes in your code.
1.
for(let i=0; i<=marks.length;i++)
marks.length is 3. Array index starting from 0.
const marks = [100,100,80];
index 0 is 100.
index 1 is 100.
index 2 is 80.
When you add i<=marks.length, this is equals to i<=3.
= in here will run the loop extra circle and this will return NaN because there are only 3 elements in you array and array indexing is 0 based.
2.
for(let i=0; i<=marks.length;i++){
summ = summ+marks[i];
var avg = (summ/marks.length);
}
avg is out of scope. you have defined avg inside the loop and trying to access it outside of the loop. Anything declared in the loop is scoped to that loop and are not available outside the loop.
3.
console.log(calculateGrade(marks));
Your calculateGrade() function is not accepting any parameters. So you can't pass any parameter into this function.
4.
console.log(calculateGrade(marks));
since calculateGrade() function is not returning any value, this will print nothing. So you don't need to call this inside a console.log();.
I have simplified your code as below.
const marksArr = [100, 100, 80];
calculateGrade(marksArr);
function calculateGrade(marks) {
console.log('calling calculateGrade(marks)...');
var avg = (marksArr.reduce(function(a, b) {
return a + b;
}, 0)) / marksArr.length;
console.log('avg is', avg);
if (avg <= 59) {
console.log('Grade', 'F');
} else if (avg >= 60 && avg <= 69) {
console.log('Grade', 'D');
} else if (avg >= 70 && avg <= 79) {
console.log('Grade', 'C');
} else if (avg >= 80 && avg <= 89) {
console.log('Grade', 'B');
} else if (avg >= 90 && avg <= 100) {
console.log('Grade', 'A');
}
}
` calculateGrade(){
let marks = [100,100,80];
let summ = 0;
let avg = 0;
for(let i = 0; i < marks.length; i++){
summ = summ+marks[i];
avg = (summ/marks.length);
}
if(avg<=59){
console.log('F');
}
else if(avg>=60 && avg<=69){
console.log('D');
}
else if(avg>=70 && avg<=79){
console.log('C');
}
else if(avg>=80 && avg<=89){
console.log('B');
}
else if(avg>=90 && avg<=100){
console.log('A');
}
}`
> array start from 0

Randomising arrays to form an highly entropic grid

I am attempting to make a 5x5 grid using arrays with the following limitations
Should not exceed more than 4 check marks per grid
Should not have 2 consecutive check marks
This is what I have come up with so far, I would appreciate if someone could help me figure out how would I achieve the latter condition
let emoji = {
0: '✅',
1: '❓',
}
let grid = []
let checkmarks = 0
for (let i = 0; i < 5; i++) {
let row = []
for (let j = 0; j < 5; j++) {
let random = crypto.randomInt(0, 1000) % 2
if (random == 0) {
if(checkmarks < 4) {
row.push(emoji[0])
checkmarks++
}
else {
row.push(emoji[1])
}
} else {
row.push(emoji[1])
}
}
grid.push(row)
}
I am attempting to make it as random as possible.
I'm posting this answer because the accepted answer doesn't seem to produce a consistent result. I agree with most of the approach, but result just wasn't always returning 4 checkmarks (because it seems to reset after each iteration, which can increase the maximum number of loops needed).
But ultimately, the idea is to fill the 5x5 array with the ❓ character first, randomly select a location, verify the surrounding blocks are not ✅, and then place a ✅ if these conditions are met. If not, I instead just select a new position but keep the existing results until the needed number of ✅ have been set.
let grid = [],
rows = 5,
cols = 5,
maxChecks = 4,
totalChecks = 0,
emoji = {
0: '✅',
1: '❓',
};
const _RandomChecks = () => {
grid = [];
totalChecks = 0;
for(let i = 0; i < rows; i++) {
grid[i] = [];
for(let j = 0; j < cols; j++) {
grid[i] = [...grid[i], emoji[1]];
}
}
while(totalChecks < maxChecks) {
let rndRow = parseInt(crypto.randomUUID().replace(/[^0-9]/g, "").substr(-8)) % rows,
rndCol = parseInt(crypto.randomUUID().replace(/[^0-9]/g, "").substr(-8)) % cols,
valid = (grid[rndRow][rndCol] == emoji[1]) ? true : false;
if(grid[rndRow-1]?.[rndCol] && valid) valid = (grid[rndRow-1]?.[rndCol] == emoji[1]) ? true : false;
if(grid[rndRow+1]?.[rndCol] && valid) valid = (grid[rndRow+1]?.[rndCol] == emoji[1]) ? true : false;
if(grid[rndRow][rndCol-1] && valid) valid = (grid[rndRow][rndCol-1] == emoji[1]) ? true : false;
if(grid[rndRow][rndCol+1] && valid) valid = (grid[rndRow][rndCol+1] == emoji[1]) ? true : false;
if(valid) {
grid[rndRow][rndCol] = emoji[0];
totalChecks++;
}
}
console.log(grid.map(row => row.join('')).join('\n'));
}
_RandomChecks();
Instead of randomly determining if a cell should be a checkmark I would rather randomly find cells that should be a checkmark.
Your current solution decreases the chance of getting a checkmark with each cell.
Created some example code for you:
const emojis = ['✅', '❓']
const size = 5
const checkmarks = []
for (let i = 0; i < 4; i += 1) {
while (true) {
// get random x and y
const x = Math.random() * size | 0
const y = Math.random() * size | 0
// check if x and y are far enough from existing checkmarks
const areNeighbours = checkmarks.some(c => {
if (c.x === x) {
return Math.abs(c.y - y) <= 1
}
if (c.y === y) {
return Math.abs(c.x - x) <= 1
}
return false
})
if (!areNeighbours) {
checkmarks.push({
x,
y
})
break
}
}
}
const grid = []
for (let y = 0; y < size; y += 1) {
grid.push([])
for (let x = 0; x < size; x += 1) {
const checkmark = checkmarks.find(c => c.x === x && c.y === y)
grid[y][x] = checkmark ? emojis[0] : emojis[1]
}
}
console.log(grid.map(row => row.join('')).join('\n'))
Imagine a 5x5 board initially filled by ❓.
Next you toss 4 coins at once, each coin will landed in one cell, head or tail.
If head, place a ✅ in the cell.
Now check if non-consecutive ✅ condition is met. If not start over.
Solution:
const emojis = ['✅', '❓'];
function randomInt(min, max) {
return min + Math.floor(Math.random() * (max - min));
}
function tossCoins(checkmarkLimit, size) {
const positions = Array.from({ length: checkmarkLimit }, () => {
const pos = randomInt(0, size * size);
const tail = Math.random() > 0.5;
if (tail) return null;
const x = pos % 5;
const y = (pos - x) / 5;
return [x, y];
})
return positions.filter(Boolean);
}
function checkNonConsecutive(positions) {
for (let i = 0; i < positions.length; i++) {
const p = positions[i];
for (let j = 0; j < positions.length; j++) {
if (i == j) continue;
const o = positions[j];
const distance = Math.abs(p[0] - o[0]) + Math.abs(p[1] - o[1])
if (distance <= 1) {
return false;
}
}
}
return true;
}
function main() {
const checkmarkLimit = 4;
const size = 5;
const grid = Array.from({ length: size }, () => Array.from({ length: size }, () => emojis[1]));
let positions = tossCoins(checkmarkLimit, size);
while (!checkNonConsecutive(positions)) {
positions = tossCoins(checkmarkLimit, size);
}
positions.forEach(([x, y]) => {
grid[y][x] = emojis[0];
});
return grid;
}
for (let n=0; n < 10; n++) {
console.log('round: ' + n);
console.log(main().map(row => row.join('')).join('\n'));
}

get range from the nearest number in javascript

I have one range object and another is price_values array, now I want to nearest range from the range object for each value of price_values array. I have tried the below solution but it's not given me the proper range.
range = {
0: '25-500',
1: '1500-2500',
2: '5000-10000'
}
let price_values = [5, 100, 1500, 7000, 15000]
I tired below solution
let nearestPriceRangeArr = [];
let rangeLength = Object.keys(range).length;
Object.keys(range).forEach(key => {
price_values.forEach((price, qKey) => {
let rangeArr = key.split("-");
let fromRange = parseInt(rangeArr[0]);
let toRange = parseInt(rangeArr[1]);
if(price <= fromRange) {
if(x == 0) {
nearestPriceRangeArr[price] = key;
}
} else {
if (price >= fromRange && price <= toRange) {
nearestPriceRangeArr[price] = key;
} else {
if(price >= toRange) {
let ab = (x == rangeLength - 1) ? key : key;
nearestPriceRangeArr[price] = ab;
}
}
}
x++;
});
});
Expected Output
nearestPriceRangeArr[5] = '25-500';
nearestPriceRangeArr[100] = '25-500';
nearestPriceRangeArr[1500] = '1500-2500';
nearestPriceRangeArr[7000] = '5000-10000';
nearestPriceRangeArr[15000] = '5000-10000';
You could take an array of ranges and find the range by checking the price.
const
range = ['25-500', '1500-2500', '5000-10000'],
prices = [5, 100, 1500, 7000, 15000],
result = Object.fromEntries(prices.map(p => [p, range.find((r, i, { length }) => {
const [low, high] = r.split('-').map(Number);
return p <= high || i === length - 1;
})]));
console.log(result);
Don't know what I did, but its strange solution for your strange problem.
console.clear();
let range = {
0: '25-500',
1: '1500-2500',
2: '5000-10000'
}
let price_values = [5, 100, 1500, 7000, 15000];
let nearestPriceRangeArr = {};
let rangeValues = Object.values(range);
price_values.forEach((price)=>{
// for prices which are in one the range_values
rangeValues.forEach((range, rangeIndex)=>{
let ranges = range.split('-');
if(price >= parseInt(ranges[0]) && price <= parseInt(ranges[1])){
nearestPriceRangeArr = {
...nearestPriceRangeArr,
[price] : range
}
}
/* if price is not falling in any range */
// if price is smaller than first range
if(rangeIndex === 0){
if(price <= ranges[0]){
nearestPriceRangeArr = {
...nearestPriceRangeArr,
[price] : range
}
}
} else {
// if price is greater than previous range
// and smaller than current range
const previousRanges = rangeValues[rangeIndex - 1].split("-");
if(price > previousRanges[1] && price <= ranges[0] ){
nearestPriceRangeArr = {
...nearestPriceRangeArr,
[price] : range
}
} else {
// if price is greater than last range
if(price > ranges[1]){
nearestPriceRangeArr = {
...nearestPriceRangeArr,
[price] : range
}
}
}
}
})
})
console.log(nearestPriceRangeArr);
console.log(nearestPriceRangeArr[5])
console.log(nearestPriceRangeArr[100])
console.log(nearestPriceRangeArr[1500])
console.log(nearestPriceRangeArr[7000])
console.log(nearestPriceRangeArr[15000])

Problem with Javascript function not returning total sum in a for loop with if conditions

I am writing pure javascript without any HTML and I am having trouble with one of my functions that would need to return the total "course points."
The program consists of prompting the user the # of course taken followed by the grade received which is pushed in the "grades" array. The function calculateCP will allow it to reiterate every element of the array and is suppose to give me the total course points given the following if conditions.
Please help why my function isn't working! The output is returning only the first element of the array, not the total sum of all elements.
calculateCP = () => {
let coursePoints;
let total = 0;
for (let i = 0; i < grades.length; i++) {
if (grades[i] >= 90) {
coursePoints = 4;
} else if (grades[i] >= 80 && grades[i] < 90) {
coursePoints = 3;
} else if (grades[i] >= 70 && grades[i] < 80) {
coursePoints = 2;
} else if (grades[i] >= 60 && grades[i] < 70) {
coursePoints = 1;
} else if (grades[i] < 60) {
coursePoints = 0;
}
return total = total + coursePoints;
}
}
const grades = [];
let noOfCourses = parseInt(prompt("Please enter # of courses taken: "));
console.log("\n")
for (let i = 0; i < noOfCourses; i++) {
grades.push(prompt('Enter grade recieved '));
}
console.log(calculateCP());
}
In the for loop you just want to sum the values.. only once you're done, return the total :) something like this..
calculateCP = () => {
let coursePoints;
let total = 0;
for (let i = 0; i < grades.length; i++) {
if (grades[i] >= 90) {
coursePoints = 4;
} else if (grades[i] >= 80 && grades[i] < 90) {
coursePoints = 3;
} else if (grades[i] >= 70 && grades[i] < 80) {
coursePoints = 2;
} else if (grades[i] >= 60 && grades[i] < 70) {
coursePoints = 1;
} else if (grades[i] < 60) {
coursePoints = 0;
}
total = total + coursePoints;
}
return total;
}
const grades = [];
let noOfCourses = parseInt(prompt("Please enter # of courses taken: "));
console.log("\n")
for (let i = 0; i < noOfCourses; i++) {
grades.push(prompt('Enter grade recieved '));
}
console.log(calculateCP());
}
try to remove the return statement from the for loop and put it right after it..
change this:
return total = total + coursePoints;
to this:
... for loop
total = total + coursePoints;
}
return total;

Subset sum with number reuse allowed

I have a list of positive integers e.g. 15, 29, 110, and a target e.g. 44. I'm trying to find all possible combinations which sum to the target but importantly, the numbers in the set can be used multiple times e.g.
Target = 44
Result = 1x15, 1x29
Target = 307
Result = 2x110, 3x29
I found a dynamic programming solution which works when the combination is no more than one of each number. So Target 44 works but not my 307 example (returns Not Found).
How can the multiples or number reuse be done?
function subset(people, min, max)
{
var subsets = [];
subsets[0] = '';
for (var person in people)
{
for (var s = min-1; s >= 0; --s)
{
if (s in subsets)
{
var sum = s + people[person];
if (!(sum in subsets))
{
subsets[sum] = subsets[s] + ' ' + person;
if (sum >= min && sum <= max)
{
return subsets[sum];
}
}
}
}
}
return 'Not found';
}
var p = {
optionA:15,
optionB:29,
optionC:110
};
var qty = 307;
console.log(subset(p, qty, qty));
Try this recursive solution:
function subset(people, min, max) {
const pairs = Object.entries(people),
results = [],
getSum = multiplications => multiplications.reduce((sum, multiplicator, position) =>
sum + pairs[position][1] * multiplicator, 0),
formatResult = result => result.map(multiplications =>
multiplications.reduce((res, multiplicator, position) =>
(multiplicator > 0 ? res.push(`${multiplicator}x${pairs[position][1]}`) :
res, res), []));
function findSums(multiplications, position) {
let s;
while((s = getSum(multiplications)) <= max) {
if (s >= min) {
results.push([...multiplications]);
}
if (position < pairs.length - 1) {
const m = [...multiplications],
nextPosition = position + 1;
m[nextPosition]++;
findSums(m, nextPosition);
}
multiplications[position]++;
}
}
findSums(pairs.map(_ => 0), 0);
return results.length > 0 ? formatResult(results) : "Not found";
}
var p = {
optionA:15,
optionB:29,
optionC:110
};
var qty = 307;
console.log(subset(p, qty, qty));
Change the second loop in such way:
for (var s = 0; s <= wantedSum - people[person] ; s++)
Using this approach you fill all entries of subsets[] array\list where index is multiple of people[person] (instead of single entry). For example, with value 3 you fill 3,6,9,12... entries.

Categories

Resources