0

I'm programming a checkers game for a high school project. I have a weird variable behaviour and I can't figure out why it's happening. Let me show you the code:

var player = 1;
var lastClicked;
var wasClicked = false;
var isEmpty = new Array(8);
for (var i = 0; i < 8; i++) {
    isEmpty[i] = new Array(8);
    for (var j = 0; j < 8; j++) {
        isEmpty[i][j] = true;
    }
}
function CreateBoard() {
    var board = document.createElement("table");
    board.cellSpacing = 0;
    for (var i = 0; i < 8; i++) {
        var tr1 = document.createElement("tr");
        for (var j = 0; j < 8; j++) {
            var td1 = document.createElement("td");
            td1.setAttribute("id", "td" + i + j);
            td1.addEventListener("click", function () { CheckIandJForLater(i, j); });
            if (i % 2 == 0) {
                if (j % 2 == 0)
                    td1.style.backgroundColor = "beige";
                else
                    td1.style.backgroundColor = "black";
            }
            else {
                if (j % 2 == 0)
                    td1.style.backgroundColor = "black";
                else
                    td1.style.backgroundColor = "beige";
            }
            tr1.appendChild(td1);
        }
        board.appendChild(tr1);
    }
    document.body.appendChild(board);
}
function CheckIandJForLater(i, j) { // A function which is meant to show the weird behavior, which prevents me from using function I want to use in the event listener
    alert("Function i: " + i);
    alert("Function j: " + j);
}
function DeployPieces() {
    CreateBoard();
    var pieceIndex = 1;
    for (var i = 0; i < 8; i++) {
        if (i < 3) {
            if (i % 2 == 0) {
                for (var j = 1; j < 8; j += 2) {
                    var td1 = document.getElementById("td" + i + j);
                    var circle1 = document.createElement("span");
                    circle1.setAttribute("class", "redCircle");
                    circle1.setAttribute("id", "circle" + i + j);
                    wasFilled = true;
                    circle1.setAttribute("onclick", "AlertToPressOnSquare(); lastClicked = this; wasClicked = true;");
                    td1.appendChild(circle1);
                    isEmpty[i][j] = false;
                }
            }
            else { 
                for (var j = 0; j < 8; j += 2) {
                    var td2 = document.getElementById("td" + i + j);
                    var circle2 = document.createElement("span");
                    circle2.setAttribute("class", "redCircle");
                    circle2.setAttribute("id", "circle" + i + j);
                    wasFilled = true;
                    circle2.setAttribute("onclick", "AlertToPressOnSquare(); lastClicked = this; wasClicked = true;");
                    td2.appendChild(circle2);
                    isEmpty[i][j] = false;
                }
            }
        }
        else if (i > 4) {
            if (i % 2 == 0) {
                for (var j = 1; j < 8; j += 2) {
                    var td3 = document.getElementById("td" + i + j);
                    var circle3 = document.createElement("span");
                    circle3.setAttribute("class", "whiteCircle");
                    circle3.setAttribute("id", "circle" + i + j);
                    wasFilled = true;
                    circle3.setAttribute("onclick", "AlertToPressOnSquare(); lastClicked = this; wasClicked = true;");
                    td3.appendChild(circle3);
                    isEmpty[i][j] = false;
                }
            }
            else {
                for (var j = 0; j < 8; j += 2) {
                    var td4 = document.getElementById("td" + i + j);
                    var circle4 = document.createElement("span");
                    circle4.setAttribute("class", "whiteCircle");
                    circle4.setAttribute("id", "circle" + i + j);
                    wasFilled = true;
                    circle4.setAttribute("onclick", "AlertToPressOnSquare(); lastClicked = this; wasClicked = true;");
                    td4.appendChild(circle4);
                    isEmpty[i][j] = false;
                }
            }
        }  
    }
}

function AlertToPressOnSquare() {
    alert("Player " + player + ", please press on the square to which you would like to move the piece");
    if (player == 1)
        player = 2;
    else if (player == 2)
        player = 1;
}
function MoveToSquare(i, j) { //The function I want to use in the td1 event listener
    if (wasClicked && isEmpty[i][j]) {
        var lastClickedId = lastClicked.getAttribute("id");
        var lastClickedLocation = lastClickedId[6] + lastClickedId[7];
        var v1 = parseInt(lastClickedId[6], 10);
        var v2 = parseInt(lastClickedId[7], 10);
        var tdFrom = document.getElementById("td" + lastClickedLocation);
        var tdTo = document.getElementById("td" + i.toString() + j.toString());
        if (lastClicked.getAttribute("class") == "whiteCircle") {
            if (v1 == i - 1 && (v2 == j - 1 || v2 == j + 1)) {
                tdFrom.removeChild(lastClicked);
                tdTo.appendChild(lastClicked);
            }
        }
        else if (lastClicked.getAttribute("class") == "redCircle") {
            if (v1 == i + 1 && (v2 == j - 1 || v2 == j + 1)) {
                tdFrom.removeChild(lastClicked);
                tdTo.appendChild(lastClicked);
            }
        }
        alert("Player " + player + ", please press on the piece you would like to move");
        wasClicked = false;
    }
}

So, the weird behavior is as follows: Every time I click on a td in the table and run the CheckIandJForLater function, I get the value 8 for both i and j. They should not get these values, as i and j are supposed to be updated in the for loop. Moreover, they should never reach the value of 8, since both the loops run between 0 and 7. It's also worth noting that if I put alert(i); and alert(j); regularly, without the CheckIAndJForLater function, their values are printed fine. I really struglle in finding out how to solve this weird behavior. May someone help me? Thank you. Why is that behavior happening? Is there a solution?

  • Does this answer your question? [JavaScript closure inside loops – simple practical example](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – Ivar Apr 09 '21 at 15:48
  • The loops run up to 8. When the variables reach 8, the loop exits, but the variables have to get to 8 for that to happen. – Charlie Bamford Apr 09 '21 at 15:52
  • I'll check it, thanks –  Apr 09 '21 at 15:53
  • 1
    If you want to keep the current i and j in the event listener, you need to create a variable in that event listener's scope with the values in it. Something like `td1.addEventListener(click, () => CheckIAndJForLater(...[i, j]))` Which creates a new array containing the values of i and j, then spreads it into CheckIAndJForLater. – Charlie Bamford Apr 09 '21 at 15:57
  • I can see where https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example answers my question, but I can't understand how to implement the suggested solution in my program. –  Apr 09 '21 at 16:18
  • Charles Bamford, are you sure it should be implemented like that? I haven't learned such a syntax in school (the `() => CheckIAndJForLater(...[i, j])`). –  Apr 09 '21 at 16:21
  • To me it is unclear what your intention is versus the code. I agree with the others, this is normal behavior for a for loop. I'd suggest stripping back your function to the bare minimum needed to show the issue, we can then assist from there. – Jarrod Christman Apr 12 '21 at 14:03

0 Answers0