Search code examples
jquerydynamichtml-tableuser-input

Make a dynamic checkerboard responsive to user input jQuery


I'm working on a coding challenge asking me to create a checkerboard using jQuery, along with an input form asking for how big the gameboard will be (i.e. 6x6 board, 7x7 board, etc.). I am having difficulty with odd/even class assignment for whenever the input is an odd number (i.e. 7x7 board, 9x9 board, 11x11 board). If you run the JS fiddle when increasing input # to any odd number, the odd/even assignment "skips".

$(document).ready(function() {
    
  //create input form for number/size of board
  $('h1').append('<div class=div1>Size of Board: <input type="text" id = "size1" name="size2" min = "2" max = "100" step = "2" value = "6"><input type="submit" id="submit1" value="Create"></div>')
 
  //create button to print Game Pieces 
  $('h1').append('<div><input type="submit" id="submitForm" value="Lets Play!"></div>');
  
  
  var z = '';
  //on clicking the button, create array of empty boxes/<td>
  $('#submit1').click(function() {
    var array = [];
    //remove previous appended array
    $('tbody').empty();

    //grab current value or size of gameboard
    z = $('#size1').val();
    
      //with a for loop, create "empty" table (z by z) of boxes
      for (var i=0; i<z; i++) {
        //addClass so we can grab later for color assignment
        var trEven = $('<tr>').addClass('trEven');
        var trOdd = $('<tr>').addClass('trOdd');
        //Differentiate between row to row: assign class trEven and trOdd to every other row      
        if (i%2 == 0) {
          array.push(trEven);
        }
        else {
          array.push(trOdd);
        }
        //for each row add z number of td's
          for (var j=0; j<z; j++) {
            array[i].append('<td></td>');
          }
      } 

    //append updated array to <tbody>
    $('tbody').append(array);
    //select all evens/odds of trOdd/trEven to assign colors using special selectors
    $('.trOdd td:odd').css('background-color', 'black'); 
    $('.trOdd td:even').css('background-color', 'white'); 
    $('.trEven td:odd').css('background-color', 'white');
    $('.trEven td:even').css('background-color', 'black'); 

  });//onclick function
  
  
  //Play Button: add game pieces
  $('#submitForm').click(function(){
    if (z <= 6) {
      //first two rows
      $('#gameBoard tr:eq(0) td:odd').append('<div class="gamePiece">')
      $('#gameBoard tr:eq(1) td:even').append('<div class="gamePiece">')
      //last two rows
      $('#gameBoard tr:last td:even').append('<div class="gamePiece">')
      $('#gameBoard tr:nth-last-child(2) td:odd').append('<div class="gamePiece">')
    }
    else if (z > 6) {
	  //first three rows
      $('#gameBoard tr:eq(0) td:odd').append('<div class="gamePiece">')
      $('#gameBoard tr:eq(1) td:even').append('<div class="gamePiece">')
      $('#gameBoard tr:eq(2) td:odd').append('<div class="gamePiece">')
      //last three rows
      $('#gameBoard tr:last td:even').append('<div class="gamePiece">')
      $('#gameBoard tr:nth-last-child(2) td:odd').append('<div class="gamePiece">')
      $('#gameBoard tr:nth-last-child(3) td:even').append('<div class="gamePiece">') 
    }

  })//onclick function
  
  
})//document
table {
  border: solid 1px black;
  border-spacing: 0px;
}
td {
  width: 50px;
  height: 50px;
}
.div1 {
  font-size: medium;
}
.gamePiece {
  border-radius: 100%;
  height: 100%;
  width: 100%;
  background-color: red;
}
<!DOCTYPE html>

<body>
  <h1>Game Board</h1>
  <table id="gameBoard">
    <tbody></tbody>
  </table>
  <script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
</body>

If you pull up the inspector tool and click on the 'skipped' row (ex. third row) and compare it to the first row, both rows are recognized as and "even" row, but the first td element differs. The first td/"column" of the Row 1, is being pulled as td:even. However the first td/"column" of the third row is being pulled as td:odd. From my knowledge it seems that after each pair of rows (1 odd row & 1 even row) the indexing skips, the first column is "1" when it should be "0". This only occurs when the board size is odd.

Does anyone know why the index is being skipped?


Solution

  • What about a boolean flag to determine where you're at to assign a class?

    First, declare a boolean variable inside of your "Create" button click handler:

    var toggleFlag = true;
    

    Then, in your for loop where you "count" the amount of td in each row, you can assign a class right away:

    //for each row add z number of td's
    for (var j = 0; j < z; j++) {
        if(toggleFlag){
            array[i].append('<td class="odd"></td>');
        }else{
            array[i].append('<td class="even"></td>');
        }
        // Toggle the flag for next iteration
        toggleFlag=!toggleFlag;
    }
    

    As soon as this loop is finished, check if you are supposed to have an odd or even amount of td on each row... Because if it is odd, you have to toggle again:

    // If rows contain an even amout of td, toggle again before looping to next row
    if(z % 2 == 0){
        toggleFlag=!toggleFlag;
    }
    

    And finally, when you hit the "Let's play" button to add the pieces, you can select td using the odd class instead of the :odd or :even selector.

    $('#gameBoard tr:nth-last-child(3) td.odd').append('<div class="gamePiece">')
    

    See this working CodePen
    ;)


    EDIT to explain the initial error

    The error you have in your code is located in these lines:

    $('.trOdd td:odd').css('background-color', 'black'); 
    $('.trOdd td:even').css('background-color', 'white'); 
    $('.trEven td:odd').css('background-color', 'white');
    $('.trEven td:even').css('background-color', 'black'); 
    

    This logic is good for an even amount of squares.
    But with an odd amount, you fatally get an offset of one.

    This is what is making this "two by two" row grouping effect.
    So you'd have to have an "alternated logic" of this code block... at each row.
    Which is not quite simple.
    That's why I took the problem from sooner in the code by assigning the classes in the loop that cycle the tds one by one.

    Just to illustrate it, I've made another CodePen.
    It shows clearly that this selector $('.trOdd td:odd') selects ALL td that has the odd class in an odd tr... But not only on one row! like I'm sure you were thinking... It doesn't get the rows one by one like a human would. It grabs all the table to collect matching elements.

    See? For jQuery, there is only two rows (trOdd and trEven)...
    ;)