Passing strings from arrays with a requirement - javascript

I'm pretty much new to Javascript so this isn't a question of efficiency, more just a question of possibility!
var experience = 156;
var titleData = [
{"Duke"
if (0 < experience < 101)},
{"King"
if (100 < experience < 201)},
{"Emperor"
if (300 < experience < 301)}
];
return(titleData)
I'm creating a very small and simple game using html and javascript and have been stuck at this point for close to two hours after much google searching. I'm trying to use this array to store a list of possible titles that would be passed onto the html to be used as a title before the person's name and have paired down what I am working on into this much simpler and shorter example.
I want to use the variable 'experience' in order to return a specific string, such as Duke or Emperor from the array and then eventually pass that on with getElementById and inputting that directly on the webpage. So that when the player gains more experience, the title automatically updates. I know I'll have to use a for loop at some point, but trying to figure out exactly what needed to go into that proved to be too much of a hair-puller.
I know I am probably doing this VERY wrong, but this is my first foray into trying to use arrays in this way. I'm not married to the idea of an array or the way that I have tried to set it up, so if I am doing this in the completely most roundabout way, let me know. I hope I was able to communicate the essence of what I'm trying to accomplish, even if my code isn't clear.

As Roberrrt already mentioned, your syntax is not valid, you can not use if statements inside an object or array declaration.
One of many possible approaches would be to first declare your different titles in an array, defining the title and their min/max experience boundaries. This data can then also be moved e.g. to a separate config file to better compartementalize your code.
After that, it is only a matter of going through the different titles and checking whether the player fulfills the experience requirements:
var experience = 156;
var titleData = [];
var titles = [{
name: "Duke",
min: 0,
max: 101
}, {
name: "King",
min: 100,
max: 201
}, {
name: "Emperor",
min: 300,
max: 301
}, {
name: "Khal",
min: 120,
max: 160
}];
for (var i = 0; i < titles.length; i++) {
if (titles[i].min < experience && titles[i].max > experience) {
titleData.push(titles[i].name);
}
}
console.log(titleData); // ["King", "Khal"]
In order to make the experience boundaries even more flexible, you could even define a function for each of the titles, defining the condition:
var experience = 1000000;
var titleData = [];
var titles = [{
name: "Oddball",
condition: function(exp) {
return (exp % 2) == 0; // Exp. multiple of 2?
}
}, {
name: "Supreme Leader",
condition: function(exp) {
return exp > Math.pow(2, 10); // Exp. greater than the 10th power of 2?
}
}];
for (var i = 0; i < titles.length; i++) {
if (titles[i].condition(experience)) {
titleData.push(titles[i].name);
}
}
console.log(titleData); // ["Oddball", "Supreme Leader"]

No, you're declaring an array which holds data, you cannot use logic inside of that declaration. The correct way is to declare the titles, and push them inside the array.
// Setting the current experience a player has
var experience = 156;
// Defining a function that returns the title, based upon the experience
function getTitle(experience) {
// List all options, based on the experience
if(experience < 101) {
// Return basically means 'give back this value as function output'
return "Duke";
}
else if(experienec < 201) {
return "King";
}
else if(experience < 301) {
return "Emperor";
}
else {
return "Too high!";
}
}
// Declaring the players title, by calling the getTitle() function,
// with the experience as a parameter.
var title = getTitle(experience);
EDIT: As #Brian stated, this could be more elegant using the switch statement:
var level = 1;
switch (level) {
case 1:
return "Duke";
break;
case 2:
return "King";
break;
case 3:
return "Emperor";
break;
default:
return "Too high!";
}

An array cannot have if inside it. If you need to do this using an array, this is one way of doing it:
var titleData = [];
if (0 < experience < 101) {
titleData.push("Duke");
} else if (100 < experience < 201) {
titleData.push("King")
}
...
return(titleData)
But If its just going to be a string, you can also do:
function (experience) {
var titleData = "";
if (0 < experience < 101) {
titleData = "Duke";
} else if (100 < experience < 201) {
titleData = "King";
}
...
return(titleData)
}

If you don't need the titles for anything else, just have a function return the right one given the experience:
function titleGivenExperience(experience) {
if (experience <= 100) return "Duke";
if (experience <= 200) return "King";
return "Emperor";
}
var title = titleGivenExperience(120);

You can do something almost like you want, using javascript ternary statement
condition ? value-when-true : value-when-false;
see MDN documentation for ternary operator
e.g.
var titleData = [ experience < 0 ? "peasant" : experience < 101 ? "Duke" : experience < 201 ? "king" : experience < 301 ? "Emperor" : "uber"]
Added peasant, what happens under 0 ? ;)
Added uber, what happens above 301:?

var titleData =[];
var experience = 156;
if(0 < experience < 101)
{
var data = "Duke";
titleData.push(data);
}
if(100 < experience < 201)
{
var data = "King";
titleData.push(data);
}
if(300 < experience < 301)
{
var data = "Emperor";
titleData.push(data);
}
return(titleData);
Hope this will work,

Related

For-loops are sending my mind into a wild loops and I cant figure out why

function main(legacymoney, year2live) {
let joshAge = 18;
let yearlyAllowance = 12000;
let evenyearsLeftover = legacymoney - yearlyAllowance;
let oddyearsLeftover = evenyearsLeftover - yearlyAllowance - 950;
evenyearsLeftover = oddyearsLeftover - yearlyAllowance;
for (let i = 1801; i < year2live; i++) {
//joshAge++;
//oddyearsLeftover = evenyearsLeftover -yearlyAllowance-950;
}
if (year2live % 2 !== 0) {
console.log(`He will need ${(oddyearsLeftover-230100).toFixed(2)} dollars to survive.`);
} else {
console.log(`Yes! He will live a carefree life and will have ${evenyearsLeftover.toFixed(2)} dollars left.`);
}
}
main(50000,1802);
main(400000,1841);
the above code only passed all possible tests because I put a literal 230100 to get the answer because it was failing with the second main(400000,1841); but passing main(50000,1802);
I am getting lost somewhere in the last steps and this for loop is sending me for a loop itself.
Thanks in advance!

Problem with a JS function not returning any result

I'm quite new at JS and I can't figure out why this is not working :
function printEvens (someArr) {
for (let i = 0; i < someArr.length; i ++) {
if (someArr.length % 2 === 0) {
console.log(someArr[i]);
} else if (someArr.length % 2 !== 0) {
continue;
}
}
};
printEvens ( ['Amsterdam',
'Barcelona',
'Berlin',
'Lisbon',
'Madrid',
'Mexico City',
'Miami',
'Paris',
'Sao Paulo'] );
(I'm trying to get only the even results)
Do you have any clue ?
Thank you for your help !
From your function name, I assume that you are trying to print all even items from the array.
In your loop, instead of checking whether the position/index (here i) is even, you were checking the length of the array.
someArr.length % 2 === 0 // wrong
Try the following (didn't test it though)
function printEvens(someArr) {
for (let i = 0; i < someArr.length; i++) {
if (i % 2 === 0) {
console.log(someArr[i]);
}
}
}
You also don't need the else part.I know you are new to SO. Please try to add more details to your question.
Good luck
I just want to log them (sorry for the misusage of "return", quite new in this). I want to log only the results with an even index.
I found another solution by writing :
function printEvens (someArr) {
for (let i = 0; i < someArr.length; i += 2) {
console.log(someArr[i]); }
}
But I'm doing this as an exercise and I was supposed to use %
This is a lot different than your old thing, but this should work:
function printEvens(someArr) {
for (i = 0; i < someArr.length; i += 2) {
if (someArr[i]) {
console.log(someArr[i]);
}
}
}
Instead of checking if the value is even, we just skip ahead with the addition assignment operator += to instantly reach the next even value.

Why does this code only work in certain JS executors?

This code takes an integer and returns the amount of 1s that are present.
function countOnes(i) {
let str = i.toString();
let ones = 0;
for(let x = 0; x < i.length; x++) {
if(str.charAt(x) === '1') ones++;
}
return ones;
}
console.log(countOnes(111000));
But it only appears to work in certain executors of JavaScript. If I enter this code into p5.js or Mozilla MDN, I will receive the desired output of 3.
But if I use the console in my browser and some other websites emulating that, 0 will be returned with every given value.
Why is this the case?
you cant loop on i.length, i its still a 'Number' type,
you should loop on "str.length" instead.
you better give more meaningful names... i should be num,
str should be numStr, ones should be counter.
try this:
function countOnes(num) {
var counter = 0;
var numsArray = Array.from((num + ''))
numsArray.forEach(num => {
return (num == 1)? counter++ : ''
})
return counter
}
console.log(countOnes(1110010)); // 4

Javascript - dont compare if condition met

I have this script for my html table which colors the cells in column row by row:
$(document).ready( function () {
var table, aP, rtvP, mmP, meP;
table = document.getElementById('productTable');
for (i = 1; i < table.rows.length; i++) {
var rowCells = table.rows.item(i).cells;
if (rowCells[3].firstChild.data !== '—') {
aP = parseFloat(rowCells[3].firstChild.data);
} else {
aP = 0;
}
if (rowCells[5].firstChild.data !== '—') {
rtvP = parseFloat(rowCells[5].firstChild.data);
} else {
rtvP = 0;
}
if (rowCells[7].firstChild.data !== '—') {
mmP = parseFloat(rowCells[7].firstChild.data);
} else {
mmP = 0;
}
if (rowCells[9].firstChild.data !== '—') {
meP = parseFloat(rowCells[9].firstChild.data);
} else {
meP = 0;
}
console.log(aP, rtvP, mmP, meP);
if (aP > rtvP || mmP || meP) {
rowCells[3].bgColor = 'red';
} else if (aP === rtvP || mmP || meP) {
rowCells[3].bgColor = 'yellow';
} else {
rowCells[3].bgColor = 'green';
}
}
})
I know that is a little monster, but the only thing I miss is that, there should be no comparison for value if that value = 0. Ex. If aP = 100, rtvP = 150, mmP = 0, meP = 50, value of mmP should be skipped in comparison. Is there easy way to do that? I don't want to make another spaghetti of IFs
You could try converting one of those instances to a proper function:
function convertP(value) {
if (value !== '—') {
return parseFloat(value);
}
return 0;
}
Then you can call it like:
meP = convertP(rowCells[9].firstChild.data);
Where you can augment that convertP function to be "smarter" and handle different cases later.
Now for your comparison problem you probably want to store these converted values into an array instead of as a bunch of unrelated variables, like:
var points = [ ];
[ 3, 5, 7, 9 ].forEach(function(i) {
points.push(convertP(rowCells[i].firstChild.data));
});
Where now you have all of them in one neat, tidy container. You can then compare them quickly by doing something like:
var diffs = [ ];
points.forEach(function(p) {
diffs.push(aP - p);
});
The key thing to remember here is that floating point values are often approximations so it's important to not depend on them being precisely equal. 1.0 + 2.0 does not necessarily === 3.0. There's going to be a tiny amount of deviation due to floating point quirks, so go with +/- some tiny value, even if that value is 0.000001.
Now you can identify your color condition with a function:
function colorCondition(aP, points) {
var state = 'green';
var epsilon = 0.000001;
points.forEach(function(p) {
if (aP > (p + epsilon)) {
state = 'red';
}
else if (aP > (p - epsilon)) {
state = 'yellow';
}
});
return state;
}
Now you have a generic solution that can work with N inputs. This is the goal of programming when you're trying to adhere to the Zero, One or Infinity Rule.
One of the ways to put a prerequisite condition in if is using the logical AND operator: &&.
For your variables it will be something like:
if (mmP!=0 && mmP>aP){}
This way if mmP is 0, first condition will return false and second condition won't be processed.
You can enforce a condition without making another spaghetti of IFs.
I'm not sure I understood your use case, so if that does not work for you just comment it.

Refactor big switch statement

I have the following switch statement:
switch (type) {
case 1: // 1 BYTE 8-bit unsigned integer
pointer = count > 4 ? offset : pointer;
for (let i = 0; i < count; i++) {
value += dataView.getUint8(pointer + i);
}
tag.value = parseInt(value, 10);
return tag;
case 3: // 3 SHORT 16-bit unsigned integer
pointer = count > 2 ? offset : pointer;
for (let i = 0; i < count; i++) {
value += dataView.getUint16(pointer + 2 * i, littleEnd);
}
tag.value = parseInt(value, 10);
return tag;
case 4: // 4 LONG 32-bit unsigned integer
pointer = count > 1 ? offset : pointer;
for (let i = 0; i < count; i++) {
value += dataView.getUint32(pointer + 4 * i, littleEnd);
}
tag.value = parseInt(value, 10);
return tag;
case 5:
...
and so on.
The pattern is every time the same with some small variations. How can I refactor this? I want to refactor the pattern inside the case and I'm also trying to remove the whole switch block. Is that possible?
(This probably belongs on the Code Review Stack Exchange.)
Without a bit of larger context it's difficult to provide a reasonable refactoring, or even determine if such a refactoring would be worth the effort and additional maintenance.
The nutshell is that you have a number of type that need to be handled. Rather than a switch, you could implement a command pattern where each type is either a small class, or a simple object. (Using a class makes it marginally easier to pass in an "execution context" that contains the variables not shown in the snippet.)
For the sake of brevity, here's a (very) rough outline.
You'd have a base type handler. This wraps up dataView looping and tag value setting. Since I don't know the context, I'm pretending there's a context you pass in. I include all variables that weren't shown in your snippet.
(I didn't include value, which it looks like you should, but I didn't know the intent.)
class BaseTypeHandler {
constructor(ctx) {
this.ctx = ctx
}
getPointer = () => throw new Error('Missing getPointer implementation')
getViewData = () => throw new Error('Missing getViewData implementation')
getValueFromDataView = () => {
let value = 0
for (let i = 0; i < this.ctx.count; i++) {
value += this.getViewData(i, pointer)
}
return value
}
getTag = () => {
const pointer = this.getPointer()
, value = this.getValueFromDataView()
this.ctx.tag.value = parseInt(value, 10)
return this.ctx.tag
}
}
Each subclass implements the required unique functionality, here how to get the pointer, and how to get data from the dataView.
class Type1Handler extends BaseTypeHandler {
getPointer = () =>
this.ctx.count > 4 ? this.ctx.offset : this.ctx.pointer
getViewData = (i, pointer) =>
this.ctx.dataView.getUint8(pointer + i)
}
class Type3Handler extends BaseTypeHandler {
getPointer = () =>
this.ctx.count > 2 ? this.ctx.offset : this.ctx.pointer
getViewData = (i, pointer) =>
this.ctx.dataView.getUint16(pointer + 2 * i, littleEnd);
}
Then you wrap those up in an object of type handlers:
const typeHandlers = {
1: Type1Handler,
3: Type3Handler,
4: Type4Handler
}
const handler = new typeHandlers(type)
, tag = handler.getTag()
TL;DR
Unless you have a tremendous number of these, and you cannot use math to figure out the getPointer and getViewData implementations, you might want to stick with the switch.
Simple objects or immediate functions may be a significantly smaller implementation, although not necessarily easier to reason about. They also have the advantage of being able to close over variables you already have locally.

Categories