So I play a RPG on a Virtual Tabletop that supports API. I do not want to create a bunch of objects individually, so I am working with the API, and want to read attributes from a JSON dump and then write those attributes to a object in the game (Character). So all goes well with my code so far as long as I am pulling static info. But in the case of Skills, they may or may not have all of the attr defined, so NULL. I would like to be able to identifiy the null and move on, not fail out because it is NULL.
I have attached a GIST, I am a n00b to this, and I am a System Engineer in real life, but not a coder. So I would appreciate the input!
https://gist.github.com/bigdadmike/7548421
Above is all of my code, but specifically this is the section I am working on, these have all been declared as var at top of script. I have updated this post with comments and suggestions so far from Basti. Code:
on('ready', function() {
_.each(monsterManual, function (monsterData){
log(monsterData.Name);
var character = createObj('character', {
name: monsterData.Name,
gmnotes: monsterData.FullText,
});
//*/
_.each(monsterAttributes, function(attr) {
var max = "";
var cur = "";
var re;
switch(attr){
case 'AC':
cur = parseInt(monsterData[attr].match(/(\d+)/)[1]);
break;
case 'Str':
case 'Dex':
case 'Con':
case 'Int':
case 'Wis':
case 'Cha':
re = new RegExp(attr + "\\s*(\\d*).*");
cur = parseInt(monsterData['AbilityScores'].match(re)[1]);
break;
case 'HD':
case 'Size':
case 'CR':
cur = monsterData[attr];
break;
case 'HP':
cur = parseInt(monsterData[attr]);
max = cur;
break;
case 'BaseAtk':
cur = parseInt(monsterData[attr]);
max = cur;
break;
case 'CMB':
cur = monsterData[attr];
max = cur;
break;
case 'CMD':
cur = parseInt(monsterData[attr]);
max = cur;
break;
case 'Acrobatics':
case 'Appraise':
case 'Bluff':
case 'Climb':
case 'Craft (any one)':
case 'Diplomacy':
case 'Disable Device':
case 'Disguise':
case 'Escape Artist':
case 'Fly':
case 'Handle Animals':
case 'Heal':
case 'Intimidate':
case 'Knowledge (religion)':
case 'Knowledge (planes)':
case 'Knowledge (history)':
case 'Knowledge (nature)':
case 'Knowledge (any one)':
case 'Linguistics':
case 'Perception':
case 'Ride':
case 'Sense Motive':
case 'Sleight of Hand':
case 'Spellcraft':
case 'Stealth':
case 'Survival':
case 'Swim':
case 'Use Magic Device':
re = RegExp(attr.replace('(', '\\(').replace(')', '\\)') + "\\s*(\\d*).*");
var match = re.exec(monsterData['Skills'])
if(match != null) {
cur = parseInt(monsterData['Skills'].match(re)[1]);
}
else {
cur = 0;
}
break;
default:
cur = parseInt(monsterData[attr]);
break;
}
log([attr, cur, max].join(':'))
if(cur != 0) {
createObj('attribute', {
characterid: character.id,
name: attr,
max: max,
current: cur
});
}
//*/
});
});
});
Basically
switch(attr) {
case 'AC':
//...
break;
case 'Str':
case 'Dex':
//...
break;
//...
}
will be
if(attr == 'AC') {
//...
} else if (attr == 'Str' || attr == 'Dex') {
//...
}
and so on. A case following another case directly will be converted to an or-expression.
BUT as the comments already point out, this is - with regard to readabilty - a bad idea...
You want to change this code section:
case 'Use Magic Device':
re = new RegExp(attr + "\\s*(\\d*).*");
cur = parseInt(monsterData['Skills'].match(re)[1]);
break;
to
case 'Use Magic Device':
re = RegExp(attr.replace('(', '\\(').replace(')', '\\)') + "\\s*(\\d*).*");
var match = re.exec(monsterData['Skills'])
if(match != null) {
cur = parseInt(match[1]);
} else {
cur = 0;
}
break;
This will check the match if it succeded (in this case the monster actually has the skill). If the match fails (the monst doesnt have this skill), then there won't be a parsing error and the break lets you hop out of the switch.
Further down you want to encase the call to createObject with an if:
if(cur != 0) {
createObj('attribute', {
characterid: character.id,
name: attr,
max: max,
current: cur
});
}
Furthermore, in your monsterAttributes there are two spelling errors which will cause cur to get NaN:
var monsterAttributes = [
/*...*/
'Disguise ', //there's a whitespace after Disguise, remove it!
/*...*/
'Use Magic device', //the 'd' has to be capital, as you check on 'Use Magic Device'
/*...*/
];
If I understood you correctly, you may simply check for attr being null and avoid the switch statement if this is the case. For example:
if( attr != undefined && attr != null ){
switch(attr){
//... the code as is in here
}// end switch
} // end if statement
Related
function texas(val) {
var answer = "";
switch(val) {
case 1:
case 2:
case 3:
var answer = "low";
case 4:
case 5:
case 6:
var answer = "medium";
break;
} else if(val => 7) {
var answer = "Huge"
}
return answer;
}
it says error Declaration or statement expected. ts(1128) [13, 7]
and it poits at the else if statement
You can use the "default" keyword, but you should probably update your code in order to handle the cases in which the value of the parameter is not positive or not a number:
function texas(val) {
if (val <= 0 || isNan(val)) {
throw new InvalidOperationException("val should be a positive number");
}
switch(val) {
case 1:
case 2:
case 3:
return "low";
case 4:
case 5:
case 6:
return "medium";
default:
return "Huge"
}
}
It's >= and the elsehas to be deleted. The varfor answer is unnecesary, just declare it once with let. You forgot the break in case 3:.
function texas(val) {
let answer = "";
switch(val) {
case 1:
case 2:
case 3:
answer = "low";
break;
case 4:
case 5:
case 6:
answer = "medium";
break;
}
if(val >= 7) {
answer = "Huge"
}
return answer;
}
console.log(texas(2));
console.log(texas(8));
You just need to return in the switch
function texas(val) {
var answer = "";
switch(val) {
case 1:
case 2:
case 3:
var answer = "low";
return answer;
case 4:
case 5:
case 6:
var answer = "medium";
return answer;
}
if(val => 7) {
var answer = "Huge"
}
return answer;
}
The syntax does not allow to put an else after a switch. else only makes sense in combination with an if statemen. But switch has a default: case which most closely matches your intention (hopefully):
function texas(val) {
var answer = "";
switch(val) {
case 1:
case 2:
case 3:
var answer = "low";
break;
case 4:
case 5:
case 6:
answer = "medium";
break;
default:
if(val >= 7) {
answer = "Huge"
}
// decide what should happen if val is 0, -1 or not even a number (e.g. texas('gotcha!')
break;
}
return answer;
}
Don't forget to put break in your cases, otherwise execution will "fall through" and execute the next cases. You would never end up with "low"
You can't use an if statement within a switch block.
You do have the default option tho -
function texas(val) {
var answer = "";
switch(val) {
case 1:
case 2:
case 3:
answer = "low";
case 4:
case 5:
case 6:
answer = "medium";
break;
default:
answer = val >= 7 ? "Huge" : "Invalid";
break;
}
return answer;
Note that if you have a minus / negative answer, it'll also fall into this clause, but you can the the value of answer with an inline ?: if statement...
You can't put the else after the switch block as people have stated above. switch statement is better for multi way branching and fixed data values. On the other side, if statement is better for boolean values. You can do something like this. It might not be the shortest line of codes, but just so you that there's another approach:
function texas(val) {
let answer = "";
switch (true) {
case (val == 1 || val == 2 || val == 3):
answer = "low";
break;
case (val == 4 || val == 5 || val == 6):
answer = "medium";
break;
case (val >= 7):
answer = "huge";
break;
}
return answer;
}
I am implementing a drag'n'drop interface in js which has two tables of objects and a single object as source or destination. To execute the "move" operation, I thought of using these two class methods:
_getVar(id) {
var ind;
switch (id[0]) {
case 'c':
return this.clipboard;
case 's':
ind = Number(id.substr(1)) - 1;
return this.SynthPatches[ind];
case 'f':
ind = Number(id.substr(1)) - 1;
return this.FilePatches[ind];
}
}
move(from, to) {
var fv = this._getVar(from);
var tv = this._getVar(to);
if (fv == undefined) return "Source empty";
if (tv == undefined) return "Destination undefined";
tv = fv;
return "Ok";
}
This does not work. fv and tv are local references to the correct objects. The reference fv is copied to tv and then both are forgotten.
I would like something like a deep copy in python, but it looks like the only solution is to inline _getVar() nine times, which makes for really ugly code.
The easiest way to reduce duplication here is probably to add an optional second parameter to the function and allow it to set as well as get, e.g.:
_getOrSetVar(id, value) {
var ind;
switch (id[0]) {
case 'c':
if (value !== undefined) this.clipboard = value
return this.clipboard;
break;
case 's':
ind = Number(id.substr(1)) - 1;
if (value !== undefined) this.SynthPatches[ind] = value
else return this.SynthPatches[ind];
break;
case 'f':
ind = Number(id.substr(1)) - 1;
if (value !== undefined) this.FilePatches[ind] = value
else return this.FilePatches[ind];
break;
}
}
And perform your update like this:
this._getOrSetVar(to, this._getOrSetVar(from))
I have a simple problem: I need to roll two sets of dice. For each number possible in the first roll, there are a set of conditionals that I then check against the second roll. The conditionals for each roll are different.
The problem, to me, is that something like this repeated roughly thirty times seems like a gross thing to stick in my code:
if (roll == 3) {
if (secondRoll < 5) {
do this
}
else if (secondRoll > 5 && secondRoll < 10) {
do this
}
else {
do this
}
}
if ...... and so on
So what do I do? Is there a more elegant way to do this? I've thought about something like this:
class Result {
constructor(firstRoll, secondRollMin, secondRollMax, output) {
this.firstRoll;
this.secondRollMin;
this.secondRollMax;
this.output;
}
}
and then checking the rolls against matching properties in a set of objects, but I'm not sure that's honestly any better. Any thoughts would be appreciated.
Just a small improvement, but you only need to check the upper bound of the range in each subsequence else if:
if (roll == 3) {
if (secondRoll < 5) {
do this
}
else if (secondRoll < 10) { // secondRoll must be >= 5 already
do this
}
else {
do this
}
}
Use Switch to simplify
switch (roll) {
case 1-4:
// Do something.
break;
case 5-8:
// Do something.
break;
case 9-11:
// Do something.
break;
default:
break;
}
How about creating a key for the combination and a bit simpler if/else? You could combine any combination that has the same action.
const combo = `${roll}-${secondRoll}`;
if (['1-1', '1-2', '1-3', '3-4', '3-5', '3-6'].includes(combo) {
// Do this
} else if (['1-4', '1-5', '1-6', '3-1', '3-2', '3-3'].includes(combo) {
// Do this
// ...
} else if (['6-4', '6-5', '6-6'].includes(combo) {
// Do this
}
Or create a switch/case:
const combo = `${roll}-${secondRoll}`;
switch (combo) {
case '1-1':
case '1-2':
case '1-3':
case '3-4':
case '4-5':
case '5-6':
// Do this
break;
case '1-4':
case '1-5':
case '1-6':
case '3-1':
case '4-2':
case '5-3':
// Do this
break;
// ...
case '6-4':
case '6-5':
case '6-6':
// Do this
break;
}
You can try a mixture of if, else and switch blocks. You can use different methods to call based on the first roll. A switch statement is usually more efficient than a set of nested ifs.
class Result {
constructor(firstRoll, secondRollMin, secondRollMax, output) {
this.firstRoll;
this.secondRollMin;
this.secondRollMax;
this.output;
switch(firstRoll){
case 1:
this.output = oneToXTime(secondRollMin,secondRollMin)
break;
case 2:
this.output = twoToXTime(secondRollMin,secondRollMax)
break;
case 3:
this.output = threeToXTime(secondRollMin,secondRollMax)
break;
case 4:
this.output = fourToXTime(secondRollMin,secondRollMax)
break;
case 5:
this.output = fiveToXTime(secondRollMin,secondRollMax)
break;
case 6:
this.output = sixToXTime(secondRollMin,secondRollMax)
break;
}
}
static String oneToXTime(secondRollMin,secondRollMin) {
String result = ""
if (secondRollMin < 5) {
result = "My result"
}
else if (secondRollMin < 10) {
result = "My result 2"
}
return result
}
static String twoToXTime(secondRollMin,secondRollMin) {
String result = ""
if (secondRollMin < 5) {
result = "My result"
}
else if (secondRollMin < 10) {
result = "My result 2"
}
return result
}
static String threeToXTime(secondRollMin,secondRollMin) {
// Same as above...
}
static Stfing fourToXTime(secondRollMin,secondRollMin) {
// Same as above...
}
static String fiveToXTime(secondRollMin,secondRollMin) {
// Same as above...
}
static String sixToXTime(secondRollMin,secondRollMin) {
// Same as above...
}
}
// It is simple code
var num = prompt("put number");
// This way is not worked
switch (num) {
case num > 0:
console.log("num++");
break;
case num < 0:
console.log(num-2);
break;
}
// But this worked
if (num > 0){
console.log(num++);
} else if (num < 0){
console.log(num -2);
}
My first way by "switch" is not worked but "if" method worked.
I tried all of thing for changing code or other ways but the same result.
Please guys help me.
Because the statement num > 0 inside you case will return true or false.
If you do this:
switch (true) {
case num > 0:
console.log("num++");
break;
case num < 0:
console.log(num-2);
break;
}
It will work.
Cases cannot be expressions, you must normalize your input first.
Although it is valid to place an expression in a case, in this scenario a more tried-and-true way of dealing with this is to first normalize your input first.
You can determine direction for example:
var num = parseInt(prompt("put number"), 10);
var direction = num < 0 ? -1 : 1;
switch (direction) {
case 1:
console.log("num++");
break;
case -1:
console.log(num - 2);
break;
}
The switch acts as a case switcher, meaning you cannot make comparisons to create cases, just list cases by case, and perform some function from this case. The if / else structure is suitable for making comparisons, as the expected result in the if call is always a boolean.
Example:
const a = 1;
if (a === 1) {
console.log('hello');
} else {
console.log('sad');
switch (a) {
case 1 : console.log('hello'); break;
default: console.log('sad'); break;
In your case, I recommend using if/else if/else, as it is more recommended.
I'm creating a panel and there are stats for memory, CPU and HDD. I'm using a switch statement and in the case method, I'm putting the current usage of CPU, memory and HDD.
However, the problem is that I'm using operators and I don't know which operator to use because I've tried all of them and I didn't get the results that I expected.
And this is the code: https://pastebin.com/YaxCm0Be
switch(true){
case (mem_percent_get <= 0.01):
var mem_progress_color = 'progress-bar-primary';
break;
case (mem_percent_get <= 33):
var mem_progress_color = 'progress-bar-success';
break;
case (mem_percent_get <= 66):
var mem_progress_color = 'progress-bar-warning';
break;
case (mem_percent_get <= 80):
var mem_progress_color = 'progress-bar-danger';
break;
default:
mem_progress_color = 'progress-bar-theme';
}
switch(true){
case (cpu_percent_get <= 33):
var cpu_progress_color = 'progress-bar-success';
break;
case (cpu_percent_get <= 66):
var cpu_progress_color = 'progress-bar-warning';
break;
case (cpu_percent_get <= 80):
var cpu_progress_color = 'progress-bar-danger';
break;
default:
cpu_progress_color = 'progress-bar-primary';
}
switch(true){
case hdd_percent_get <= 0.01:
var hdd_progress_color = 'progress-bar-primary';
break;
case hdd_percent_get <= 30:
var hdd_progress_color = 'progress-bar-success';
break;
case hdd_percent_get <= 60:
var hdd_progress_color = 'progress-bar-warning';
break;
case hdd_percent_get <= 80:
var hdd_progress_color = 'progress-bar-danger';
break;
default:
hdd_progress_color = 'progress-bar-theme';
}
Well, my first comment is to not use a switch in this case. What you are doing is essentially if () { } else if() {} blocks. You should be using switch when you have a value that you want to strictly check against. I suggest looking into at the MDN docs for switch.
Secondly, from what I can gather is that for the memory, you need it to be red when the value is 1696 / 2098 (80.83%). All of your if/elseif cases rely on <= which would mean that the value must be less than or equal to the number on the right of the equation. In your case, you are looking for <= 80, and without seeing how you calculate mem_percent_get (if it is in the pastebin, I'm unable to open that on my current network), you're value is likely above 80.
For your danger, you likely want 80-100+% as being red, so you should be using >= or greater than or equal to operator.
MDN has an excellent resources on comparison operators.
Created a getClassName method that accepts a percent and will return a className:
const getClassName = percent => {
switch(true){
case (percent <= 0.01):
return 'progress-bar-primary';
case (percent <= 33):
return 'progress-bar-success';
case (percent <= 66):
return 'progress-bar-warning';
case (percent <= 80):
return 'progress-bar-danger';
default:
return 'progress-bar-theme';
}
}
console.log('0: ', getClassName(0));
console.log('40: ', getClassName(40));
console.log('50: ', getClassName(50));
console.log('80: ', getClassName(80));
console.log('100: ', getClassName(100));