Finding neighbors in a game of five-in-a-row - javascript

I can declare a winner if a player gets five of their tokens in a row, and now I am trying to implement the feature of capturing an opponent's pieces. For example, I am player X, I can trap O's pieces like this X00X in any direction on the board. In order to implement this, is the following logic correct:
Find all neighbors around O, check and see if the neighbor is an X or an O, if there are two 0's in a row surrounded by an X on each side, I can take those pieces. Is there a better way to approach this problem? I am thinking of something like this:
function isOCaptured(token, row, col){
if(gameBoard[row][col]==="O" && gameBoard[row][col+1] === "X"
&& gameBoard[row][col-1] === "X"){
return true;
}
return false;
}
But it does not seems to return true when I place one O in between two X's.
Here is what my server.js and app.js look like right now: https://jsfiddle.net/Amidi/s3gnx3rL/4/ The HTML is just a 13 x 13 grid of buttons with an event attached to each which sends the buttons coordinates to the add() function in my app.js

Now, the problem seems to be that the code only works if the "O" was placed last. This can be solved with a for-loop.
for(var i = -1; i <= 1; i++) {
if (gameBoard[row][col+i]==="O" && gameBoard[row][col+i+1] === "X"
&& gameBoard[row][col+i-1] === "X") {
return true;
}
}
return false;
You can also use a slice:
// The closest 5 cells to the left/right of the newly added piece, as a string
var str = gameBoard[row].slice(col-2,col+3).join("");
// Look for the pattern "XOX" in those 5 cells. Double negation to return bool.
return !!str.match("XOX");
Old answer
According to your comment, the code was called like this:
if(isOCaptured(x,y)===true){console.log("y is between 2 x\s");
This means that the function is called with two instead of three arguments. That will result in the following values of the arguments: token = x, row = y and col = undefined.
The expression being evaluated will thus be:
gameBoard[y][undefined]==="O" && gameBoard[y][undefined+1] === "X"
&& gameBoard[y][undefined-1] === "X"
Which would evaluate as follows:
Evaluating gameBoard[y] will succeed, resulting in a column (the wrong one though).
Then we try indexing the column with undefined, and since the array doesn't contain an element called undefined, it will fail, resulting in (again) undefined.
Then we compare this value undefined with "0", which is obviously false.
The expression false && ... will return false, as will the whole function.
If the second part would have been executed, it would calculate undefined+1, which is (quite accurately) evaluated to NaN (not a number). The array doesn't contain NaN either, so this calculation would evaluated to false as well.
Now, for some advice:
The statement if(expr){return true} else {return false} can be simplified to just return expr.
These kinds of bugs are pretty easy to find if you use the Chrome Debugger (or Firebug for firefox), where you can step through the code and see exactly what happens and where stuff goes wrong.

Related

Short-Circuiting to Print Every Value

Here is my code:
for (let i = 0; i <= 100; i++) {
let output = "";
if (i % 3 === 0) {
output += "Cool";
}
if (i % 5 === 0) {
output += "Breeze";
}
console.log(output || i);
}
In this code, I use a for loop to vary the value of the binding i from 0 to 100.
In the first if statement, I use the modulo and the addition assignment operator to add the string "Cool" to the binding output.
In the second if statement, I use the modulo and the addition assignment operator to add the string "Breeze" to the binding output.
The function of my last statement in the body of my for loop is to print the value of the output binding in the browser console. I do this through short-circuiting. Now, I understand the logic of short-circuiting with the "OR" operator, since the interpreter will short-circuit its full logic of comparing both operands and automatically choose the operand on the left if it can be converted to true, which strings and numbers can, so the operand output is always going to be chosen.
What I don't understand is why short-circuiting is needed to visibly print every value in the console. If I were to use the statement console.log(output); it consolidates the number type values, stating how many were printed in a row before it had to print a string.
Can someone please explain this logic? Why is short-circuiting needed here to prevent the consolidation?
If I were to use the statement console.log(output); it consolidates the number type values, stating how many were printed in a row before it had to print a string.
In case it isn't clear to others, what you're referring to is this:
This is an artifact of the browser console, which consolidates duplicate logs together, to make debugging easier. Here, it's consolidating the duplicate logged empty strings. It's not a issue with your code's logic. If you were to log the output by any other method, the blank outputs would be displayed serially, as you'd expect, rather than being clumped together:
const table = document.querySelector('table').children[0];
for (let i = 0; i <= 100; i++) {
let output = "";
if (i % 3 === 0) {
output += "Cool";
}
if (i % 5 === 0) {
output += "Breeze";
}
table.innerHTML += `<tr>Cell value: ${output}</tr>`;
}
<table>
<tbody>
</tbody>
</table>
Your code is perfectly fine, you just need to find a way to display it other than console.log so that its unintuitive clumping doesn't mess things up.
You can also turn off the grouping by unchecking "Group Similar":

for_each inside if_else in JS

I am new to the coding world, just started learning javascript. Im trying to design a table kind of output but unable to complete it. here is what I am trying to achieve
"Jan - 1 - quarter1" and on second row
"Feb - 2 - quarter1" ...etcetera
I made use of foreach , if/else and combine them both but couldn't get output maybe because we cannot add a foreach inside an if statement or so! can someone help where I am going wrong here?
const Months = ['jan','Feb']
if (Months = 'Jan'||'Apr'||'Jul'||'Sep') {
Months.forEach(function(Month, index) {
console.log(`${Month}--${index + 1}`)}
} else {
console.log(`${Month}--${index + 1}`)
}
It's pretty unclear what you're trying to accomplish but I wanted to offer a few things that I saw in your code. Since you are quite new, I understand you may not be super familiar with the language yet.
First, if (Months = 'Jan'||'Apr'||'Jul'||'Sep') will always return true no matter what, because you're making three separate mistakes! No worries, let me break them down for you.
The first mistake is that you are using a single equals sign in Months = 'Jan'. The single equals sign is what is known as an ASSIGNMENT operator. You are setting your variable Months equal to the string 'Jan'. What you are looking for is the STRICT EQUALITY operator === which tests to see whether two things are equal.
Please see this for reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
Your second mistake is that you are looking at the entire Months variable and trying to compare its values against strings. If you had used strict equality like so:
if (Months === 'Jan')
it still would have failed because Months is an Array. What you need to do is use Months.forEach to iterate over each element of the array, and then do an equality comparison over each month.
Your third mistake is the way you are using the OR operator ||.
Let's look at this code that will have fixed the prior two errors:
var months = ['Jan','Feb','Apr','Jul','Sep'];
months.forEach(element => {
if (element === 'Jan' || 'Feb' || 'Mar'){
console.log('Gotcha');
}
});
This will still always return true because EACH THING SEPARATE BY THE OR OPERATOR WILL BE EVALUATED INDEPENDENTLY. In order to properly run your test, you need a separate equality test in each section separated by an OR.
Run the following code snippet and look at the output:
var foo = "Hi";
const test1 = (foo === "Boo" || "You");
const test2 = (foo === "Boo" || foo === "You");
console.log(test1);
console.log(test2);
if (test1) {
console.log("This is true??")
}
So, what is going on there?
test1 winds up being assigned the value of "You" because the first part evaluates to false, so it assigns the second part.
test2 is false as we would expect.
But what happens if we use an "if" statement on test1, which is currently set to the string "You"?
Take a look at this answer for clarity. why does if("string") evaluate "string" as true but if ("string"==true) does not?
At the end of it all, what you want is something like this:
var months = ['Jan','Feb','Apr','Jul','Sep'];
months.forEach(element => {
if (element === 'Jan' || element === 'Feb') {
console.log('woot');
}
});
You want this? Make an array with the data that you want.. and go through the array with a foreach ?
var months = ['Jan','Feb','Apr','Jul','Sep'];
months.forEach(element => {
console.log(element + " - " + "quarter1");
});

If/then calculation within Zap running even when statement is false

Essentially what I'm attempting to do is circumvent when users enter a number in a non-standard format. For example:
1.5 million should be 1500000
Previous Zap step extracts the number using the Formatter > Extract Number function. So the result is the variable rawNum and the original number is noformatNum.
var str = inputData.noformatNum;
var n = inputData.noformatNum.includes ("million");
if (n = true) return {
finalNum: Number(inputData.rawNum) * 1000000
};
else return { finalNum : inputData.noformatNum };
It works in that it completes the operation and turns 1.5 to 1500000, but it executes each time, even if noformatNum doesn't include "million" in the string. I'm not super experienced with Javascript, but after digging around W3C and the Zapier documentation for a couple hours I'm stumped. Any help is much appreciated. Thanks!
It looks like there's a small but significant syntax issue here. You'll want to use a triple equal sign === instead of a single = in your conditional.
if (n = true) return {
should be
if (n === true) return {
In an if...else statement, the part in parenthesis (the "condition") should be something that evaluates to either a "truthy" or "falsy" value. (MDN)
n = true assigns the value of true to the variable n, so JavaScript considers the whole thing "truthy" no matter what.
n === true compares n to true, which is what you want for the if...else statement to work. The value will be "truthy" or "falsy" depending on the value of n.

Sort array for object key that holds unique value

I have an array that looks like this:
var coll = [
{
prop1:true,
prop2:false,
id:"888399"
},
{
prop1:true,
prop2:true,
id:"/XS-555224"
},
{
prop1:false,
prop2:false,
id:"/DL-555444"
}
]
I want to sort the array so that the element with the ID that begins with "/DL" (for which there will always only be one) always starts at the top. How do I do that?
I don't feel like a custom sort will be the best choice because I don't have to compare elements against one another, I only have to find the one with the "/DL", slice it out, and insert it at the beginning of the array.
However, to do that, I'll still need to iterate over each element of the array to find the element and then perform a couple operations. So then I start thinking that I might as well just do the sort. The problem is how to write the correct condition to compare 2 items and checking the beginning of the ID string. So I figure that I can just simply test for the beginning of the String and return the value myself without comparison.
So I try this:
coll.sort(function(a,b){
var itemA = a.id;
var itemB = b.id;
if(itemA.lastIndexOf("/DL") === 0){
return 1;
}
});
But this comparison isn't working. What is wrong with my custom compare function? Thanks for any helpful tips.
Even though you are just looking for one record to move to the front you still need to check both parameters in the sort, it could be either one.
coll.sort(function(a,b) {
return a.id.indexOf('/DL') === 0 ? -1 : b.id.indexOf('/DL') === 0 ? 1 : 0;
});
Basically we want the '/DL' record to be the 'lowest' value in the array so it will show up first (sort orders things low to high). If a is lower we return negative, if b is lower we return positive. So when sorting if a is the /DL we need to return a negative. If b is the /DL we return a positive. So this expression in english is basically "Is a is our record? -1. If not, is b our record? 1. If neither then 0."
you can try this:
var orderedArr = coll.sort(function(val){
return !val.id.toString().startsWith('/DL');
});
[EDIT]
Once that you have user with IE, you can add this to make your life easier in the future:
if (!String.prototype.startsWith) {
String.prototype.startsWith = function(searchString, position) {
position = position || 0;
return this.indexOf(searchString, position) === position;
};
}
so you'll be able to use startsWith now and whenever you want.

cannot read shorthand javascript/query

i've spent ages trying to understand bootstrap's navigation bar, mainly by spending 4-5 days reading stackoverflow posts
& finally i think i've found an answer that helps!!!
trouble is, i can't understand the accompanying javascript/jquery code. i'm guessing its a shorthand version of js or something but just what it means i cannot decipher
basically, its the javascript code that appears on this jsfiddle page
$('.navbar').on('show', function () {
var actives = $(this).find('.collapse.in'),
hasData;
if (actives && actives.length) {
hasData = actives.data('collapse')
if (hasData && hasData.transitioning) return
actives.collapse('hide')
hasData || actives.data('collapse', null)
}
});
so, if anyone can explain to me what the code is doing on a line by line basis it'd be really cool
the first line i understand. its the weird-ass syntax in the next 6 lines that have me mystified
var actives = $(this).find('.collapse.in'),
hasData;
This creates two variables. One with elements picked from current scope that match the selector .collapse.in, and one empty variable.
if (actives && actives.length)
If actives exists and contains more than zero elements, do the following...
hasData = actives.data('collapse')
Retrieve arbitrary data stored under the key collapse. See https://api.jquery.com/jquery.data/ for more info.
if (hasData && hasData.transitioning) return
If hasData exists and hasData.transitioning is truthy, stop function execution.
actives.collapse('hide')
Call the collapse function on actives. This is not a native jQuery function, so you'll have to look up whatever plugin it comes from to make sense of the argument being passed in.
hasData || actives.data('collapse', null)
If hasData is truthy, skip this line. Otherwise, set the arbitrary data in actives variable to null.

Categories