4
\$\begingroup\$

I have a JavaScript function that increments a counter for each square on the chessboard as it becomes dominated by a queen and decrements it if one of the dominating queens are removed (only queens, this isn't actually a chess game with all of the pieces, it's essentially the 8 queens puzzle). If a square is dominated by at least one queen, (e.g. square.dominatedBy > 0), a CSS class is later applied to change the color of the square.

The function seems far longer than it needs to be though, and there has to be a better way to DRY it up.

(chessBoardSquares is an array of an array of Squares on the board, which are objects with properties such as row, column, and dominatedBy)

function setDominatedSquares(queenPosition, remove = false) {
    // handle squares in the same row as the queen
    for (var column = 0; column < boardSizeX; column++) {
        if (remove) {
            chessBoardSquares[queenPosition.row][column].dominatedBy--;
        } else {
            chessBoardSquares[queenPosition.row][column].dominatedBy++;
        }
    }
    // handle squares in the same column as the queen
    for (var row = 0; row < boardSizeY; row++) {
        if (remove) {
            chessBoardSquares[row][queenPosition.column].dominatedBy--;
        } else {
            chessBoardSquares[row][queenPosition.column].dominatedBy++;
        }
    }
    // handle diagonals down and to right
    var row = queenPosition.row;
    var column = queenPosition.column;
    while (row < boardSizeY && column < boardSizeX) {
        if (remove) {
            chessBoardSquares[row][column].dominatedBy--;
        } else {
            chessBoardSquares[row][column].dominatedBy++;
        }
        row++;
        column++;
    }
    // handle diagonals up and to left
    row = queenPosition.row;
    column = queenPosition.column;
    while (row >= 0 && column >= 0) {
        if (remove) {
            chessBoardSquares[row][column].dominatedBy--;
        } else {
            chessBoardSquares[row][column].dominatedBy++;
        }
        row--;
        column--;
    }

    // handle diagonals down and to left
    row = queenPosition.row;
    column = queenPosition.column;
    while (row >= 0 && column < boardSizeX) {
        if (remove) {
            chessBoardSquares[row][column].dominatedBy--;
        } else {
            chessBoardSquares[row][column].dominatedBy++;
        }
        row--;
        column++;
    }

    // handle diagonals up and to right
    row = queenPosition.row;
    column = queenPosition.column;
    while (row < boardSizeY && column >= 0) {
        if (remove) {
            chessBoardSquares[row][column].dominatedBy--;
        } else {
            chessBoardSquares[row][column].dominatedBy++;
        }
        row++;
        column--;
    }
    // update the UI
    updateDominatedSquares();
}

Update: For anyone interested, this code is now running live at queensoptimization.azurewebsites.net

\$\endgroup\$
  • 1
    \$\begingroup\$ Shouldn't a queen's dominance be limited by obstacles? \$\endgroup\$ – 200_success Mar 22 '17 at 13:00
  • \$\begingroup\$ @200_success This is an interesting point that I hadn't thought about. However, in this case, the only potential obstacle would be another queen, which would end up not changing the squares that would be dominated at all from the case where there was no obstacle. \$\endgroup\$ – Bassinator Mar 22 '17 at 15:20
4
\$\begingroup\$

I would probably break this up into a function setDominatedForLine that would work for each direction. Instead of a true/false remove parameter I used a dominatedIncrement parameter with a value of +1 or -1.

function setDominatedSquares(queenPosition, dominatedIncrement = +1) {

  function setDominatedForLine(rowInc, columnInc) {
    let row    = queenPosition.row;
    let column = queenPosition.column;
    while (row >= 0 && row < boardSizeY && column >= 0 && column < boardSizeX) {
      chessBoardSquares[row][column].dominatedBy += dominatedIncrement;
      row    += rowInc;
      column += columnInc;
    }
  }

  // Column
  setDominatedForLine( 0,  1);
  setDominatedForLine( 0, -1);
  // Row
  setDominatedForLine( 1,  0);
  setDominatedForLine(-1,  0);
  // Diagonals
  setDominatedForLine( 1,  1);
  setDominatedForLine( 1, -1);
  setDominatedForLine(-1,  1);
  setDominatedForLine(-1, -1);

  // update the UI
  updateDominatedSquares();
}

You could also modify it slightly with something like:

let directions = [ {r:-1, c:-1}, {r:-1, c: 0}, {r:-1, c: 1},
                   {r: 0, c:-1},               {r: 0, c: 1},
                   {r: 1, c:-1}, {r: 1, c: 0}, {r: 1, c: 1} ]
for (let dir of directions) 
  setDominatedForLine( dir.r, dir.c );

But I'm not sure if that is an improvement.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.