Alternate structure for a sequence of If statements? - javascript

I'm programming a poker program in JavaScript. I have a Hand class that has the properties "cards", "value" and "valueCards". The value property is an integer that corresponds to a hand type, and the valueCards is the array of five cards that also corresponds to the hand type. For example, if my original seven cards(contained in the cards property) contains a flush, this.value will flip to 6, and this.valueCards will equal only the five cards that equal the highest flush.
I have one method for each hand type, and ALL of them change the value and valueCards if that hand type is detected. I have an accessor method for value called getValue, so when I went to make a method to run all the tests on a hand and keep the highest one, it came out looking like this:
POKER.Hand.prototype.getTrueValue = function () {
this.testStraightFlush();
if(this.value == POKER.HAND_TYPE.STRAIGHT_FLUSH){ return; }
this.testQuads();
if(this.value == POKER.HAND_TYPE.QUADS){ return; }
this.testFullHouse();
if(this.value == POKER.HAND_TYPE.FULL_HOUSE){ return; }
this.testFlush();
if(this.value == POKER.HAND_TYPE.FLUSH){ return; }
this.testStraight();
if(this.value == POKER.HAND_TYPE.STRAIGHT){ return; }
this.testTrips();
if(this.value == POKER.HAND_TYPE.TRIPS){ return; }
this.testTwoPair();
if(this.value == POKER.HAND_TYPE.TWO_PAIR){ return; }
this.testPair();
if(this.value == POKER.HAND_TYPE.PAIR){ return; }
this.getHighCards();
};
I mean, the method works fine. It just bothers me, like maybe I should be doing it a different way. Does this go against convention?

If you change your this.test* functions to return true if the "hand" is found, or return false if not - then you could do something as ugly, yet somehow satisfying, as
POKER.Hand.prototype.getTrueValue = function () {
this.testStraightFlush() ||
this.testQuads() ||
this.testFullHouse() ||
this.testFlush() ||
this.testStraight() ||
this.testTrips() ||
this.testTwoPair() ||
this.testPair() ||
this.getHighCards();
};
or
change your this.test* functions to check only if this.found is false, and set this.found = true if a hand is found, so you'd simply
POKER.Hand.prototype.getTrueValue = function () {
this.found = false;
this.testStraightFlush();
this.testQuads();
this.testFullHouse();
this.testFlush();
this.testStraight();
this.testTrips();
this.testTwoPair();
this.testPair();
this.getHighCards();
};

Not an answer but I would redesign your functions :
Each method should return the prop itself :
function testFlush ()
{
if (...) return POKER.HAND_TYPE.FLUSH;
return null;
}
function testStraightFlush()
{
if (...) return POKER.HAND_TYPE.StraightFlush;
return null;
}
This way , you'll be able to get both value and check for truness.
POKER.Hand.prototype.getValue= function ()
{
return this.testFlush () || testStraightFlush()
};

Just for the fun of it, you could redesign the tests like this:
POKER.Hand.prototype.getTrueValue = function () {
var tests = [
[ "testStraightFlush", POKER.HAND_TYPE.STRAIGHT_FLUSH ],
[ "testQuads" , POKER.HAND_TYPE.QUADS ],
[ "testFullHouse" , POKER.HAND_TYPE.FULL_HOUSE ],
... etc...
];
for (var test in tests) {
var fun = this[tests[test][0]];
var val = tests[test][1];
fun();
if (this.value == val) {
return;
}
}
this.getHighCards();
};
Or the functions might simply return a boolean, so you could have a simpler tests array
var tests = [
"testStraightFlush",
"testQuads" ,
"testFullHouse" ,
... etc...
];

Related

Object extensions in nodeJS

Is it possible to have object extensions in JavaScript? For example
Extensions.js
function any.isNullOrEmpty() {
if (this == null || this == "") {
return true
}
return false
}
app.js
var x = ""
console.log(x.isNullOrEmpty()) //should log true
is this possible? How do I do it?
You could add a method to the Object prototype, and use the valueOf method to get the value of the string:
...but, because null is a primitive that cannot have a method, the only way I can think of to get the target to be null would be to use call, apply or bind.
But you would never do this in production code, because modifying the prototype of built-in objects is discouraged.
'use strict' // important for the use of `call` and `null`
Object.prototype.isNullOrEmpty = function() { return this === null || this.valueOf() === '' }
const s = ''
console.log(s.isNullOrEmpty())
const t = null
console.log(Object.prototype.isNullOrEmpty.call(t))
You could use Object.prototype to extend this type of functionality in JavaScript.
Object.prototype.isNullOrEmpty = function() {
if (this == null || this == "") {
return true
}
return false
}
var x = "";
x.isNullOrEmpty(); // returns true
you need to add your custom method into prop type of object or array or everything u want to use your method on it.
but in your case you need to this like code below:
Object.prototype.isNullOrEmpty = function(){
if (this === null || this == "") {
return true
}
return false
}
let a = {a:'10'}
console.log(a.isNullOrEmpty())
function validateValue(value){
function isNullEmpty(){
return (value === void (0) || value == null)
}
return { isNullOrEmpty }
}
}

Returning the correct item from the array

I am using code.org and I am trying to return the item from the array but receiving an error on line 34 that possibleFoods[selectedFood] is undefined. I cannot understand why, and is this what is stopping the food selections block from working? How should I correctly define selectedFood?
setScreen("BaseScreen");
onEvent("selectionbutton", "click", function( ) {
setScreen("food_decision_screen");
});
var selections = [true, true, true];
var possibleFoods = [
{name:"Raw pasta prima vera", info:{recipe:"", prepTime:{total:20,cook:0, prep:20}, image:""}},
{name:"Zucchini chips", info:{recipe:"", prepTime:{total:55,cook:30, prep:25}, image:""}}
];
var possibleFoods;
onEvent("preference_finished_button", "click", function( ) {
selections = [
getChecked("radio_buttonhot"),
getChecked("radio_buttonvege"),
getChecked("radio_button0-30")
];
if (selections[0] == false) {
if (selections[1] == false) {
if (selections[2] == true) {
selectedFood = 1;
}
}
}
setText("t_textOutputFoodInfo", "total time: " +
possibleFoods[selectedFood].info.prepTime.total);
setText("t_textOutput_foodSelectedName", "name: " +
possibleFoods[selectedFood].name);
});
selectedFood is undefined. Unsure how to define.
The selectedFood variable is not declared. Moreover, you are assigning it inside nested if conditions which might not be true always.
Try this:
Declare selectedFood outside with an initial value, right before the if statements.
var selectedFood = 0;
You have few problems here:
selectedFood is not being declared- e.g it has no "const", "var" or "let" before it.
If you do not know about scopes and the difference between var, const and let- read a bit here. Then you'll understand why its best to define selectedFood before the if blocks, and only fill up the value inside, like this:
let selectedFood;
if (selections[0] == false) {
if (selections[1] == false) {
if (selections[2] == true) {
selectedFood = 1;
}
}
}
selectedFood is undefined simply because it's not declared, in addition this line is never reached in your case: selectedFood = 1;.
Depending on what you're trying to achieve, build your conditions using Logical Operators.
replace this:
if (selections[0] == false) {
if (selections[1] == false) {
if (selections[2] == true) {
selectedFood = 1;
}
}
}
With this:
let selectedFood = 0; // Set by default to 0
if (!selections[0] && !selections[1] && selections[2]) {
selectedFood = 1;
}
Hope this helps!
EDIT: I might be able to give a more straight forward answer if you could link me to the challenge you're trying to solve.

re-write ifelse to switch

How would I go about re-writing this ifelse to a switch?
var d = document,
a = 'foo',
b = 'bar',
c = 'foobar';
if (d.URL.indexOf(a) != -1 || d.URL.indexOf(b) != -1)
{
// do this
}
elseif(d.URL.indexOf(c) != -1)
{
// do something else
}
it goes on for about 10 more ifelse which is why i'd prefer to change it to switch
I've searched for answers and found nothing so tried this:
function io(i)
{
d.URL.indexOf(i) != -1;
}
switch (io())
{
case a:
case b:
// do this
break;
case c:
// do this
break;
}
and a few variations of the same thing but I'm very much a JS novice and so knew I was probably wrong (which I was).
I think the best thing to do here would be to actually create an array of objects with their functions, then you would just cycle through that array using every. Here's some demonstration code using your above example:
var choices = [
{
value: foo,
fn: function () { // do this }
},
{
value: 'foobar',
fn: function () { // do something else }
}
];
choices.every( function( choice ) {
if ( document.URL.indexOf( choice.value ) !== -1 ) {
choice.fn();
return false;
} else return true;
});
If you have functions you know will be used multiple times, you just create them outside of the array and assign them to the fn key of multiple objects. By using return true when you don't encounter it, it'll keep moving through the array, then when it hits one where it's true, it'll return false and end the every function.

function not visible in function expressions, how to fix this?

I have a function expression like this :
var inputChecker = function(field) {
return function() {
if(field === '' || field === 'undefined' || field === null) {
return false;
}
return true;
}
}
that I want to use in several different function expressions :
(function($) {
if(inputChecker(x)) {}
})(jQuery);
(function($) {
})(jQuery);
But the problem is inputChecker is not visible in these function expressions when it's declared out of their bodies ? I don't understand why? Isn't inputChecker supposed to be global ?
Dystroy's answer is definitely simpler. But if you want it your way...
The return value of the inputChecker is a function, not boolean. If you want to call the returned function, use () expression:
var fn = inputChecker(x); // gets the function
fn(); // calls the returned function
or shorter
inputChecker(x)();
In your code
(function($) {
if(inputChecker(x)()) {
// custom code here if x is defined
}
})(jQuery);
Note: if you want to check if variable is not undefined, strip the apostrophes - undefined is constant, not string
if(field===undefined)
What you wrote is a function factory. It doesn't return a boolean but a function able to check a property.
This kind of functions is sometimes useful but :
you're here, in the returned function, checking the value of the property received by the factory. As this value can't change (it's embedded in the closure), the produced function holds no more information than just true or false. So it's useless.
you're calling inputChecker(x) as if it was a boolean instead of a function.
So what you probably want is simply
var checkInput = function(field) {
if(field === '' || field === 'undefined' || field === null){
return false;
}
return true;
}
But if you really want to generate different checking functions, dependent on another value, you could use the function factory pattern like this:
var x = true;
var checkInput = (function (x) {
if (x === true) {
return function(field) {
if(field === '' || field === 'undefined' || field === null){
return false;
}
return true;
}
} else {
return function(field) {
//evaluate field differently
}
}
}(x));
Now, dependig on what x is, one or another function will be assigned to checkInput.

Javascript function formatting

I'm concerned my if condition is not correctly formatted.
Does this look right to you?
function validateCoupon( form ){
if (form.textCoupon.value.length ){
if (form.textCoupon.value.toLowerCase() == "Item01") {
_gaq.push(['_trackEvent', 'Coupon', 'Activated', 'Item01']);
}
if (form.textCoupon.value.toLowerCase() == "Item02") {
_gaq.push(['_trackEvent', 'Coupon', 'Activated', 'Item02']);
}
$.get( "/include/checkCoupon.php", { coupon: form.textCoupon.value }, validateShipping );
}
else {
form.textCoupon.style.border = '';
validateShipping( "yes" );
}
return false;
}
Well, something appears to be a redundancy: form.textCoupon.value could be Item01 or Item02. If it's one it couldn't be the other, so I'd suggest you a switch statement.
Another problem is if you call .toLowerCase() this never will return Item01 but item01, and string equality is case-sensitive. Either call this function to both parts of condition or just don't use it.
If this were my code, this would be how I wrote it:
var validateCoupon = function (form) {
var textCoupon = form.textCoupon,
value = textCoupon.value,
track = function (value) {
_gaq.push(['_trackEvent', 'Coupon', 'Activated', value]);
};
if (value.length) {
if (value === 'Item01' || value === 'Item02') {
track(value);
}
$.get('/include/checkCoupon.php', { coupon: value }, validateShipping);
} else {
textCoupon.style.border = '';
validateShipping('yes');
}
return false;
};
Formatting of the source code is irrelevant to the JavaScript runtime. It's just a matter of personal taste.
Avoid tabs in indentation: they are not rendered identically on all platforms.

Categories

Resources