1

Question

How can i compare two adjacent cells thanks to them coordinates?

Documentation which helped me

I already saw these questions, they helped me but they are different from my case:

  1. question on stackOverflow
  2. question on stackOverflow
  3. question on stackOverflow
  4. Mds documentation to build a dynamic table

Code

I've a dynamically generated table

function tableGenerate(Mytable){
        for(var i = 0; i < myTable.length; i++) {
            var innerArrayLength = myTable[i].length;
            for(var j = 0; j<innerArrayLength; j++){
                if(myTable[i][j] === 0){
                    myTable[i][j]="x";
                }else{
                    myTable[i][j]="y";
                };
            };
            $("#aTable").append("<tr><td>"+ myTable[i].join('</td><td>') + "</td></tr>")    
        }
}  

About the interested cells (two global variables) in actualPosition row and cell have random values

var mainTd = {
     name: 'interestedValue',
     actualPosition:{
            row: 5,
            cell: 4
          }
};

var otherMainTd = {
     actualPosition:{
            row: 2,
            cell: 3
          }
};

The final part of the code works in this way:

  • I save the position of selectedTd in two differents variables
  • I create the 2d array directions with the coordinates of near cells relatives to the selectedTd
  • enter in the first if, compare the two cells. If one of the coordinates are the same, you enter in this last if.

function compare(selectedTd) {
    let tdRow = selectedTd.actualPosition.row;
    let tdCell = selectedTd.actualPosition.cell;
    let directions = [
        [tdRow - 1, tdCell],
        [tdRow + 1, tdCell],
        [tdRow, tdCell + 1],
        [tdRow, tdCell - 1]
    ]; //these are the TD near the mainTd, the one i need to compare to the others

    let tdToCompare = [];

    if (selectedTd.name === 'interestedValue') {
        tdToCompare = [otherMainTd.actualPosition.row, otherMainTd.actualPosition.cell];
        for (let i = 0; i < directions.length; i++) {
            if (directions[i] == tdToCompare) {
                console.log('you are here');
            }
        }
    } else {
        tdToCompare = [mainTd.actualPosition.row, mainTd.actualPosition.cell];
        for (let i = 0; i < directions.length; i++) {
            if (directions[i] === tdToCompare) {
                console.log('you are here');
            }
        }
    }
};

Now the main problem is: I read the coordinates, I store them in the 2 arrays, I can read them but I cannot able to enter in the if statement.

This is what I want to achieve: compare the coordinates of the blackTd with the coordinates of the red-borders td.

enter image description here

Codepen

the interested functions in the codepen are with different names, but the structure is the same that you saw in this post. I changed the original names because I think it could be more clear with general names instead of the names that i choose.

the interested functions are:

  • function fight(playerInFight) ---> function compare(selectedTd)
  • function mapGenerate(map) ---> function tableGenerate(MyTable)
  • mainTd and otherMainTd ---> character and characterTwo

CodepenHere

Vikasdeep Singh
  • 20,983
  • 15
  • 78
  • 104
Legeo
  • 784
  • 4
  • 20
  • 44
  • 1
    You are mixing == and ===. Remember they don't do the same. Use == except when you need to compare the type of the variables also. You mention an if you're interested but it's not very clear which one you're referring. There are three, I guess it's the first but it's better to point which one is – Javi Mollá Sep 12 '18 at 11:02
  • Thanks for your comment, i will read better the difference between this == and ===, thanks. Now i refer to this `if(directions[i] == tdToCompare){ console.log('you are here');` i cannot enter in this final if, also when the `directions[i]` and `tdToCompare` are the same. – Legeo Sep 12 '18 at 13:25
  • 1
    Your code is complex enough that I would suggest you create a working demo on [Fiddle](https://jsfiddle.net/) or a similar service. – montrealist Sep 12 '18 at 13:40
  • 1
    @JaviMollá - It is ALWAYS recommended to use `===`. – Rafael Herscovici Sep 12 '18 at 13:50
  • 1
    Oh, sorry. I was totally wrong. Thanks for pointing it out – Javi Mollá Sep 12 '18 at 14:00
  • Thanks for all the comments. I founded [explanation](https://stackoverflow.com/questions/359494/which-equals-operator-vs-should-be-used-in-javascript-comparisons) – Legeo Sep 12 '18 at 14:46
  • 1
    @Legeo only a suggestion/comment. When you create the table, assign the `td` content to a variable. Then, at the end of the for, add the content to the DOM. Running this line `$("#aTable").append(""+ myTable[i].join('') + "")` each line, impacts a lot the browser, because you are changing the DOM on each iteration. – manuerumx Sep 14 '18 at 14:07
  • Thanks manuerumx, i've only 3 months of js on my shoulder and advices like the your and the previous are pure gold for me. Thanks. – Legeo Sep 14 '18 at 14:21

1 Answers1

1

Update: Reading your code again I think I figured out the problem. You're comparing array instances instead of their actual values. See this simple example to illustrate the issue:

var a = [1];
var b = [1];

console.log(a===b);

What you'd need to do in your code is this:

 if (selectedTd.name === 'interestedValue') {
    tdToCompare = [otherMainTd.actualPosition.row, otherMainTd.actualPosition.cell];
    for (let i = 0; i < directions.length; i++) {
        if (
          directions[i][0] === tdToCompare[0] &&
          directions[i][1] === tdToCompare[1]
        ) {
            console.log('you are here');
        }
    }
} else {
    tdToCompare = [mainTd.actualPosition.row, mainTd.actualPosition.cell];
    for (let i = 0; i < directions.length; i++) {
        if (
          directions[i][0] === tdToCompare[0] &&
          directions[i][1] === tdToCompare[1]
        ) {
            console.log('you are here');
        }
    }
}

Now it checks if the values, and thus the cells, are matching.


Recommendations:

If I were you, I would write the method a bit different. Below is how I would do it.

function compare(selectedTd) {
  const
    // Use destructuring assignemnt to get the row and cell. Since these are 
    // values that won't be changed in the method declare them as "const". Also
    // drop the "td" prefix, it doesn't add anything useful to the name.
    // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment  
    { row, cell } = selectedTd.actualPosition,
    
    // Directions can also be a const, it will not be reassigned in the method.
    directions = [
        [row - 1, cell],
        [row + 1, cell],
        [row, cell + 1],
        [row, cell - 1]
    ],
    // A few things happens in this line:
    // - It is a destructuring assignment where the names are changed. In this case 
    //   row and cell are already assigned so it is necessary to give them another name.
    // - Don't put the row and cell in an array. You will have to access the actual values
    //   anyway as you can't compare the array instances.
    // - Instead of doing this in the if…else you had, decide here which cell you want to
    //   look for. It means the rest of the method can be written without wrapping any
    //   logic in an if…else making it less complex.
    { row: referenceRow, cell: referenceCell } = (selectedTd.name === 'interestedValue')
      ? otherMainTd.actualPosition
      : mainTd.actualPosition,
    
    // Use find instead of a for loop. The find will stop as soon as it finds a match. The
    // for loop you had kept evaluating direction items even if the first one was already
    // a match.
    // The "([row,cell])" is the signature of the callback method for the find. This too is
    // a destructuring assignment only this time with one of the arrays of the directions
    // array. The first array item will be named "row" and the second item "cell". These
    // variable names don't clash with those declared at the top of this method as this
    // is a new scope.
    // The current directions entry is a match when the row and cell values match.
    matchingNeighbor = directions.find(([row, cell]) => row === referenceRow && cell === referenceCell);
    
    // "find" returns undefined when no match was found. So when match is NOT unddefined
    // it means directions contained the cell you were looking for.
    if (matchingNeighbor !== undefined) {
      console.log('you are here');    
    }
};

const
  mainTd = {
    name: 'interestedValue',
    actualPosition: {
      cell: 1,
      row: 1
    }
  },
  otherMainTd = {
    actualPosition: {
      cell: 0,
      row: 1
    }
  };

compare(mainTd);

Orginal answer:

There is quite a bit going on in your question, I hope I understood it properly.

What I've done is create a Grid, you pass this the dimensions and it will create the array for each cell in the grid. Then it returns an object with some methods you can use to interact with the grid. It has the following methods:

  • cellAtCoordinate: Pass it an X and Y coordinate and it returns the cell.
  • isSameLocation: Pass it two cells and it checks if the cells are in the same location.
  • neighborsForCoordinate: Pass it an X and Y coordinate and it returns an array with the cells above, below, to the right, and to the left (if they exist).

With all of this out of the way the compare method becomes a little more manageable. Getting the neighbours is now just a single call, the same for the check if two cells match.

Like I said, I hope this is what you were trying to achieve. If I got the problem wrong and something needs some further explaining, please let me know.

/**
 * Creates grid with the provided dimensions. The cell at the top left corner
 * is at coordinate (0,0). The method returns an object with the following 
 * three methods:
 * - cellAtCoordinate
 * - isSameLocation
 * - neighborsForCoordinate
 */
function Grid(width, height) {
  if (width === 0 || height === 0) {
    throw 'Invalid grid size';
  }
  
  const
    // Create an array, each item will represent a cell. The cells in the
    // array are laid out per row.
    cells = Array.from(Array(width * height), (value, index) => ({
      x: index % width,
      y: Math.floor(index / height)
    }));
    
  function cellAtCoordinate(x, y) {
    // Make sure we don't consider invalid coordinate
    if (x >= width || y >= height || x < 0 || y < 0) {
      return null;
    }

    // To get the cell at the coordinate we need to calculate the Y offset
    // by multiplying the Y coordinate with the width, these are the cells
    // to "skip" in order to get to the right row.
    return cells[(y * width) + x];
  }
  
  function isSameLocation(cellA, cellB) {
    return (
      cellA.x === cellB.x &&
      cellA.y === cellB.y
    );
  }

  function neighborsForCoordinate(x, y) {
    // Make sure we don't consider invalid coordinate
    if (x >= width || y >= height || x < 0 || y < 0) {

      return null;
    }
    const
      result = [];

    // Check if there is a cell above.
    if (y > 0) result.push(cellAtCoordinate(x, y - 1));
    // Check if there is a cel to the right
    if (x < width) result.push(cellAtCoordinate(x + 1, y));
    // Check if there is a cell below.
    if (y < height) result.push(cellAtCoordinate(x, y + 1));
    // Check if there is a cell to the left.
    if (x > 0) result.push(cellAtCoordinate(x - 1, y));

    return result;
  }

  return {
    cellAtCoordinate,
    isSameLocation,
    neighborsForCoordinate
  }
}

function compareCells(grid, selectedCell) {
  const
    // Get the neighbors for the selected cell.
    neighbors = grid.neighborsForCoordinate(selectedCell.x, selectedCell.y);
    compareAgainst = (selectedCell.name === 'interestedValue')
      ? otherMainTd
      : mainTd;
      
    // In the neighbors, find the cell with the same location as the cell
    // we want to find.
    const
      match = neighbors.find(neighbor => grid.isSameLocation(neighbor, compareAgainst));
      
    // When match is NOT undefined it means the compareAgainst cell is
    // a neighbor of the selected cell.
    if (match !== undefined) {
      console.log(`You are there at (${match.x},${match.y})`);
    } else {
      console.log('You are not there yet');
    }      
}

// Create a grid which is 3 by 3.
const
  myGrid = Grid(3, 3),
  // Place the main TD here:
  // - | X | -
  // - | - | -
  // - | - | -
  mainTd = {
    name: 'interestedValue',
    x: 1,
    y: 0
  },
  // Place the other TD here:
  // - | - | -
  // Y | - | -
  // - | - | -  
  otherMainTd = {
    x: 0,
    y: 1
  };


// Check if the mainTd is in a cell next to the otherMainTd. It is not
// as the neighboring cells are:
// N | X | N
// Y | N | -
// - | - | -

compareCells(myGrid, mainTd);
// Move the mainTd to the center of the grid
// - | - | -
// Y | X | -
// - | - | -
mainTd.y = 1;

// Compare again, now the main TD is next the the other.
// -  | N | -
// YN | X | N
// -  | N | -
compareCells(myGrid, mainTd);
Thijs
  • 2,341
  • 2
  • 14
  • 22
  • I'm sorry about the quality of the question, i tried my best to explain. Can i ask what was the hardest part to understand ? so i can try to change it a little bit. If you open the codepen you will see a little game with a map, that is random generated. Now i need to understand when a character is near the other to start some basic interaction. I think that use the coords of the td was the best way. The main problem is that i'm not able to compare the value, that i stored in the array, and i don't understand why. – Legeo Sep 14 '18 at 15:04
  • 1
    Updated my answer, I think I found the problem. – Thijs Sep 14 '18 at 15:14
  • I read better your answer, get it. Thanks for your explanation, it's really clear. – Legeo Sep 14 '18 at 15:26
  • I had some more time now, so I updated my answer once more. I've rewritten your compare method and explained why I would do things different. I had a look at your game and it looks nice, well done! I do think your JS could benefit from some better structuring. As far as what made your question hard to answer, for me it was a lack of example input. You started with a map generation method, then some data structure and finally the method you needed help with. Lots of info with little bearing on the problem. In many cases a good questions has example input, code, and expected output. – Thijs Sep 14 '18 at 19:11
  • this is the best answer i've ever received in stack overflow. Your explanation is really exhaustive and i really appreciate all the effort that you put in it. I need one more hour to gave to you the bounty. Thank for all the explanation, they means a lot for me. – Legeo Sep 15 '18 at 08:52