skip to Main Content

I am making a tic-tac-toe with HTML, CSS and JavaScript. To the result verification, I am using two arrays, one counting the "X" moves, and the other couting the "O" moves with its id numbers. And an IF block, using array.includes() with all cases that are wins. But always this code return that "x won".

I tried this code

function result_check() {
     if (moves_counter_x.includes(
         1 && 4 && 7 || 2 && 5 && 8 ||
         3 && 6 && 9 || 1 && 2 && 3 ||
         4 && 5 && 6 || 7 && 8 && 9)) {
         console.log("x won")
     }
}

I tried this code too:

function result_check() {
     if (moves_counter_x.includes(1 && 4 && 7) ||
         moves_counter_x.includes(2 && 5 && 8) ||
         moves_counter_x.includes(3 && 6 && 9) ||
         moves_counter_x.includes(1 && 2 && 3) ||
         moves_counter_x.includes(4 && 5 && 6) ||
         moves_counter_x.includes(7 && 8 && 9)) {
         console.log("x won")
     }
}

But always this code return that x won. By example, when the the numbers on moves_counter_x are [1, 5, 6].
Why this function isn’t working?

4

Answers


  1. You can’t put the logical operators inside the includes() argument, it doesn’t automatically distribute. You have to call the function multiple times, and combine the results.

    function result_check() {
        if ((moves_counter_x.includes(1) && moves_counter_x.includes(4) && moves_counter_x.includes(7)) ||
            (moves_counter_x.includes(2) && moves_counter_x.includes(5) && moves_counter_x.includes(8)) ||
            (moves_counter_x.includes(3) && moves_counter_x.includes(6) && moves_counter_x.includes(9)) ||
            (moves_counter_x.includes(1) && moves_counter_x.includes(2) && moves_counter_x.includes(3)) ||
            (moves_counter_x.includes(4) && moves_counter_x.includes(5) && moves_counter_x.includes(6)) ||
            (moves_counter_x.includes(7) && moves_counter_x.includes(8) && moves_counter_x.includes(9))) {
    
            console.log("x won")
        }
    }
    
    Login or Signup to reply.
  2. The "and" operator does not combine its operands. Instead it returns the first operand if it is falsy, and the second operand otherwise.

    Thus we have

    0 && 3 === 0
    1 && 3 === 3
    4 && 5 && 6 === 6
    

    When you write

    moves_counter_x.includes(4 && 5 && 6)
    

    It is identical to

    // returns true because the array contains 6
    moves_counter_x.includes(6)
    

    What you actually want to write is

    moves_counter_x.includes(4) &&
    moves_counter_x.includes(5) &&
    moves_counter_x.includes(6)
    
    Login or Signup to reply.
  3. && and || are fully evaluated before being passed to a function, so moves_counter_x.includes(1 && 4 && 7) evaluates to the last term in the sequence to be evaluated (7, always, because 1 and 4 are both truthy, so 7 is the result of the expression), and you’re only checking if moves_counter_x.includes(7). You have to check the "includiness" for each value independently, and && and || the return from includes together, e.g. for a simplified subset of your test, instead of:

    moves_counter_x.includes(1 && 4 && 7) || moves_counter_x.includes(2 && 5 && 8)
    

    you’d need to change it to:

    moves_counter_x.includes(1) && moves_counter_x.includes(4) && moves_counter_x.includes(7) ||
    moves_counter_x.includes(2) && moves_counter_x.includes(5) && moves_counter_x.includes(8)
    

    There are ways to simplify this with other data structures and utilities (e.g. some and every methods combined with looping), but for a beginner, learn the basics of using the boolean operators correctly first.

    Login or Signup to reply.
  4. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every

    Use Array::every() to check whether each array item is contained in another array:
    Replace num1 && num2 && num3 to [num1,num2,num3].every(num => arr.includes(num)).

    You can make your own include() function to check whether an array contains a set of values to have a similar syntax of what you tried. Note that && logical operator provides the first truthy value if available or the first value if not. So you don’t check existence of your operands since you check existence of the && expression’s result. You should pass them as separate arguments.

    const moves_counter_x = [7, 8, 9];
    result_check();
    
    function result_check() {
        const includes = (...args) => args.every(move => moves_counter_x.includes(move));
         if (includes(1, 4, 7) ||
             includes(2, 5, 8) ||
             includes(3, 6, 9) ||
             includes(1, 2, 3) ||
             includes(4, 5, 6) ||
             includes(7, 8, 9)) {
             console.log("x won")
         }
    }

    To go fancy you could put your moves into 1 array:

    const moves_counter_x = [7, 8, 9];
    result_check();
    
    function result_check() {
        const moves = [
          1, 4, 7, 
          2, 5, 8,
          3, 6, 9,
          1, 2, 3,
          4, 5, 6,
          7, 8, 9
        ];
        
        for(let i = 0; i < moves.length; i += 3){
          if(moves.slice(i, i + 3).every(move => moves_counter_x.includes(move))){
             console.log("x won")
             break;
          }     
        }
    }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search