Javascript Testing Corners of an Array (Grid) - javascript

I'm doing this project trying to reproduce Schelling's Segregation model. I have a function(below) that is testing to see if the four immediate adjacent cells of the array are either the same or different or empty compared to the current cell being tested.
There are four possible spots to be tested for every cell in the array. But on corners and side spots, obviously you cant test spaces that are out of bounds. So in the function, if it finds one of the out of bounds spaces it decrements the number total around the cell. However, it keeps crashing telling me that I have an Uncaught Reference Error: Cannot read property '0' of undefined. I can't tell why its crashing.
The final lines of this code take the number of goods(similar cells) and the total number of cells around it (empty cells do not count) and gets a percentage similar.
Any help would be appreciated into telling me why it might be crashing and giving me an error? Thanks!
model.Test = function( i, j )
{
var numberToTest= 4;
var goods= 0;
if ((i - 1) >= 0)
{
if (model.BoardArray[i-1][j] != "E")
{
if (model.BoardArray[i][j] == model.BoardArray[i-1][j])
{
goods++;
}
}
else
{
numberToTest--;
}
}
else
{
numberToTest--;
}
if((i + 1) < $("#BoardSizeValue").val())
{
if (model.BoardArray[i+1][j] != "E")
{
if (model.BoardArray[i][j] == model.BoardArray[i+1][j])
{
goods++;
}
}
else
{
numberToTest--;
}
}
else
{
numberToTest--;
}
if ((j - 1) >= 0)
{
if (model.BoardArray[i][j-1] != "E")
{
if (model.BoardArray[i][j] == model.BoardArray[i][j-1])
{
goods++;
}
}
else
{
numberToTest--;
}
}
else
{
numberToTest--;
}
if ((j + 1) < $("#BoardSizeValue").val())
{
if (model.BoardArray[i][j+1] != "E")
{
if (model.BoardArray[i][j] == model.BoardArray[i][j+1])
{
goods++;
}
}
else
{
numberToTest--;
}
}
else
{
numberToTest--;
}
var similar = $("#SimilarSlider").val()/100;
if (numberToTest == 0)
{
return false;
}
else
{
var needed = goods/numberToTest;
if (needed >= similar)
{
return false;
}
else
{
return true;
}
}
}

From looking at your code, you would only get a Reference Error: Cannot read property '0' of undefined. if i was out of the bounds of the array.
I think the problem might be in this part of the code:
if ((i - 1) >= 0) {
if (model.BoardArray[i-1][j] != "E") {
if (model.BoardArray[i][j] == model.BoardArray[i-1][j]) {
if i = $("#BoardSizeValue").val() and $("#BoardSizeValue").val() is a one-based index of the array size, then [i-1] would be okay, but not [i]. So try adjusting your code to this:
if ((i - 1) >= 0 && i < $("#BoardSizeValue").val()) {
if (model.BoardArray[i-1][j] != "E") {
if (model.BoardArray[i][j] == model.BoardArray[i-1][j]) {
This would also apply to the j comparisons as well.

Related

loop won't go through first if statement

My code will only go through to the first if statement where it checks the value of key for headline1 etc... The first if statement works properly but it won't work with any of the following if statements when the first one isn't true. I've switched the second statement to the first where it checks for 'desc1' and then it works for that one only.
The purpose of this function is to check each key of an object and return the key when its value is over a certain length so I can add a class and show user some warning. This is in Vue JS so ads is in data and characterCheck is in computed property.
ads: [
{
headline1: '_keyword_',
headline2: 'Online',
headline3: 'Free',
desc1: 'Buy online _keyword_',
desc2: ' Vast collection of _keyword_',
finalurl: 'www.books.com',
path1: '',
path2: '',
boolean: true
}
]
characterCheck () {
for(var x = 0; x < this.ads.length; x++){
if(this.ads[x]['boolean'] == true) {
for(var key in this.ads[x]){
var length = this.ads[x][key].replace(/_keyword_/g, this.activeKeyword).length
if( key === 'headline1' || key === 'headline2' || key === 'headline3'){
if(length > 30){
return key
}
} else if( key == 'desc1' || key == 'desc2'){
if(length > 90){
return key
}
} else if( key == 'path1' || key == 'path2'){
if(length > 15){
return key
}
} else {
return false
}
}
}
}
}
When your first nested if condition fails, the code goes to next subsequent else-if. For some particular value, all the if and else-if block fails and code lands on final else block which contains a return statement.
If your code reaches even once there, the entire function execution immediately stops and false value is returned.
Since, you wish to wait as long as you have not looped through all the values, remove the else part and add a simple return statement to the end of the for loop like this:
function characterCheck () {
for(var x = 0; x < this.ads.length; x++) {
if(this.ads[x]['boolean'] == true) {
for(var key in this.ads[x]) {
var length = this.ads[x][key].replace(/_keyword_/g, this.activeKeyword).length
if( key === 'headline1' || key === 'headline2' || key === 'headline3') {
if(length > 30) {
return key
}
}
else if( key == 'desc1' || key == 'desc2') {
if(length > 90) {
return key
}
} else if( key == 'path1' || key == 'path2') {
if(length > 15) {
return key
}
}
}
}
}
return false
}

Javascript gives undefined instead of the ex.message

The code below works, only when I type a letter in the prompt(), I get undefined message instead of the WrongValue ex.message which is in the catch(ex). I have tried a lot of varations but I still dont know what is wrong. How do I do this correctly?
var myList = ["Oranges", "Apples", "Pineapples", "Bananas"];
var getFruit = function(index) {
if (index > myList.length || index < 0) {
throw new RangeError("The number you gave doesn't exist in the list, the number must be 0 <= # <= " + myList.length);
} else {
return myList[index];
}
if (isNaN(index)) {
throw new WrongValue("Give a number please");
} else {
return myList[index];
}
}
try {
getFruit(prompt("Which fruit are you looking for"));
} catch (ex) {
if (ex instanceof RangeError) {
console.log(ex.message);
}
if (ex instanceof WrongValue) {
console.log(ex.message);
}
}
check isNaN FIRST ... change getFruit to the following
var getFruit = function(index) {
if(isNaN(index)) {
throw new WrongValue("Give a number please");
else if(index > myList.length || index < 0) {
throw new RangeError("The number you gave doesn't exist in the list, the number must be 0 <= # <= " + myList.length);
} else {
return myList[index];
}
}
As written now always one of your condition that will be checked since they've return and throw the both prevent the code from continue to the next instruction, so try to conbine the both condition in one and check the isNaN() first, it like:
var getFruit = function(index) {
if (isNaN(index)) {
throw new WrongValue("Give a number please");
} else if (index > myList.length || index < 0) {
throw new RangeError("The number you gave doesn't exist in the list, the number must be 0 <= # <= " + myList.length);
} else {
return myList[index];
}
}
Hope this helps.

CodeMirror overlay that counts parenthesis

UPDATE:
I made a fix to the code so it looks like this:
var ch;
if (state.inExpression) {
while ((ch = stream.next()) != null) {
if (ch == "(") {
depth++;
} else if (ch == ")") {
depth--;
if (depth === 0) {
state.inExpression = false;
}
}
return highlightClass;
}
} else {
if (stream.match("#if")) {
state.inExpression = true;
return highlightClass;
}
}
It works, except if I make a change to the line of code I want highlighted.
I printed to the console and got the following:
What seems to be happening is before the overlay code is finished parsing, when I make a change to the file the code is interrupted and restarted. The problem is that the depth counter never was reset so the parentheses count gets messed up.
How can I make sure my loop will run uninterrupted? Or is there a different solution?
Original Question:
I am trying to write a CodeMirror Overlay to highlight Laravel syntax. An example of syntax to be highlighted would be #if (foo(bar)). The highlighting should start at the # and end after the last ), thus it is necessary to count parenthesis.
The following is the code I wrote to achieve this, but it is not working properly.
var ch;
if (state.inExpression) {
while ((ch = stream.next()) != null) {
if (ch == "(") {
depth++;
return highlightClass;
} else if (ch == ")") {
depth--;
if (depth === 0) {
state.inExpression = false;
return highlightClass;
}
}
}
} else {
if (stream.match("#if")) {
state.inExpression = true;
return highlightClass;
}
}
The results are hard to describe, so just take a look at this screenshot:
But it seems that my code also messes up the 'matching bracket' feature that is built in.
I think for some reason I am not properly exiting the state.inExpression.
Any ideas?

Where in the code to validate a phone number, in JavaScript orRazor?

This is my first webpage in which I prompt the user for a phone number to add to a Do Not Call List database. Everything is working so far but I need to add the following, which I can do following the advice in this answer
stripping the input from all characters except digits
validating that the resulting string is 10 digits long
Then, when telling the user that the number was added to the list, I want to present it in the (999) 999-9999 format.
Where should I add all that code? Iside the #{ } block? In JavaScript? Razor?
Check phone number
function IsNumber(s) {
var i, currentCharacter;
for (i = 0; i < s.length; i++) {
// Check that current character is number.
currentCharacter = s.charAt(i);
if (((currentCharacter < "0") || (currentCharacter > "9"))) {
return false;
}
}
// All characters are numbers.
return true;
}
function TestInternationalPhone(strPhone) {
var bracket = 3,
openBracket,
phoneNumberOnly,
phoneNumberDelimiters = "()- ",
validWorldPhoneChars = phoneNumberDelimiters + "+",
minDigitsInIPhoneNumber = 10;
strPhone = SOS.StringHelper.Trim(strPhone);
if (strPhone.length === 0) {
return false;
}
if (strPhone.indexOf("+") > 1) {
return false;
}
if (strPhone.indexOf("-") != -1) {
bracket = bracket + 1;
}
if (strPhone.indexOf("(") != -1 && strPhone.indexOf("(") > bracket) {
return false;
}
openBracket = strPhone.indexOf("(");
if (strPhone.indexOf("(") != -1 && strPhone.charAt(openBracket + 2) != ")") {
return false;
}
if (strPhone.indexOf("(") == -1 && strPhone.indexOf(")") != -1) {
return false;
}
phoneNumberOnly = SOS.StringHelper.StripCharsInBag(strPhone, validWorldPhoneChars);
return (IsNumber(phoneNumberOnly) && phoneNumberOnly.length >= minDigitsInIPhoneNumber);
}

Unexpectedly passing integer by reference?

I'm having some issues with this. For some reason, updateCurrentItem is always called with the same parameter regardless.
function updatePromoList(query) {
query = query.toUpperCase();
clearCurrentList();
var numItems = 0;
currentItem = 0;
result_set = cached[query.charAt(0)][query.charAt(1)][query.charAt(2)];
for(i in result_set){
if(numItems >= NUMBER_MATCHES){
$("<li/>").html("<span style='color: #aaa'>Please try to limit your search results</span>").appendTo("#possibilities").mouseover(function(event){ updateCurrentItem(numItems+1); });
break;
}
promo = result_set[i];
found_number = false;
if (!promo.client)
found_number = (promo.prj_number.toString().substr(0,query.length) == query) ? true : false;
if (query.length >= MATCH_NAME) {
if(promo.prj_name && typeof promo.prj_name == 'string'){
found_name = promo.prj_name.toUpperCase().indexOf(query);
} else {
found_name = -1;
}
if (promo.client)
found_client = promo.client_name.toString().indexOf(query);
else
found_client = -1;
} else {
found_name = -1;
found_client = -1;
}
if(found_client >= 0) {
var thisIndex = numItems+1;
console.log("setting", thisIndex);
$("<li/>").text(promo.client_name).bind('click',function(e){ updatePromoChoice(e,promo); }).appendTo("#possibilities").mouseover(function(event){ updateCurrentItem(thisIndex); }); } else if(found_name >= 0 || found_number) { var thisIndex = numItems+1;
console.log("setting", thisIndex);
$("<li/>").text(promo.prj_number+": "+promo.prj_name).bind('click',function(e){ updatePromoChoice(e,promo); }).appendTo("#possibilities").mouseover(function(event){ updateCurrentItem(thisIndex); });
}
if(found_number || found_client >= 0 || found_name >= 0){
numItems++;
}
}
}
function updateCurrentItem(i){
currentItem = i;
console.log("updating to", i);
}
The results of running this are:
setting 0
setting 1
setting 2
setting 3
setting 4
setting 5
setting 6
setting 7
setting 8
setting 9
setting 10
setting 11
setting 12
setting 13
then when I move my mouse over the content area containing these <li>s with the mouseOver events, all I ever see is:
updating to 4
Always 4. Any ideas?
You're creating a closure but it's still bound to the numItems variable:
function(event){ updateCurrentItem(numItems+1); }
What you should do is something like this:
(function(numItems){return function(event){ updateCurrentItem(numItems+1); }})(numItems)
Edit: I think I might have the wrong function but the same principle applies:
function(event){ updateCurrentItem(thisIndex); }
should be
(function(thisIndex)
{
return function(event){ updateCurrentItem(thisIndex); }
})(thisIndex)

Categories