How to make game a draw with existing code

Viewed 51

I've created functions with all winning combinations for player one and player two but need to create one for a draw and don't want to write out all possible draw combinations. What would be the best way to attempt this? I was thinking if I could make the playerOneWin and playerTwoWin function true if they run I could have a draw function() that says if both are false then the match is a draw, or if all boxes are fille and playerOne and playerTwo haven't won then it is a draw.

var box1 = document.querySelector(".box1");
var box2 = document.querySelector(".box2");
var box3 = document.querySelector(".box3");
var box4 = document.querySelector(".box4");
var box5 = document.querySelector(".box5");
var box6 = document.querySelector(".box6");
var box7 = document.querySelector(".box7");
var box8 = document.querySelector(".box8");
var box9 = document.querySelector(".box9");

var activePlayer;

var playerOne = "X";
var playerTwo = "O";

activePlayer = playerOne;

function clickBoxPlayer(event) {
  if (activePlayer === playerOne) {
    var boxClicked = event.target;

    if (
      boxClicked.innerHTML === playerOne ||
      boxClicked.innerHTML === playerTwo
    ) {
      console.log("noturturn");
    } else if (boxClicked.innerHTML === "") {
      boxClicked.innerHTML = activePlayer;
      activePlayer = playerTwo;
    }
    console.log("one");
    //tie && winning function

    function playerOneWin() {
      if (
        box1.innerHTML === playerOne &&
        box2.innerHTML === playerOne &&
        box3.innerHTML === playerOne
      ) {
        console.log("playeronewins");
      } else if (
        box1.innerHTML === playerOne &&
        box4.innerHTML === playerOne &&
        box7.innerHTML === playerOne
      ) {
        console.log("playeronewins");
      } else if (
        box1.innerHTML === playerOne &&
        box5.innerHTML === playerOne &&
        box9.innerHTML === playerOne
      ) {
        console.log("playeronewins");
      } else if (
        box2.innerHTML === playerOne &&
        box5.innerHTML === playerOne &&
        box8.innerHTML === playerOne
      ) {
        console.log("playeronewins");
      } else if (
        box3.innerHTML === playerOne &&
        box6.innerHTML === playerOne &&
        box9.innerHTML === playerOne
      ) {
        console.log("playeronewins");
      } else if (
        box3.innerHTML === playerOne &&
        box5.innerHTML === playerOne &&
        box7.innerHTML === playerOne
      ) {
        console.log("playeronewins");
      } else if (
        box4.innerHTML === playerOne &&
        box5.innerHTML === playerOne &&
        box6.innerHTML === playerOne
      ) {
        console.log("playeronewins");
      } else if (
        box7.innerHTML === playerOne &&
        box8.innerHTML === playerOne &&
        box9.innerHTML === playerOne
      ) {
        console.log("playeronewins");
      }
    }
    playerOneWin();
  } else if (activePlayer === playerTwo) {
    var boxClicked = event.target;

    if (
      boxClicked.innerHTML === playerOne ||
      boxClicked.innerHTML === playerTwo
    ) {
      console.log("noturturn");
    } else if (boxClicked.innerHTML === "") {
      boxClicked.innerHTML = activePlayer;
      activePlayer = playerOne;
    }

    console.log("two");
  }
  //player two winning combinations
  function playerTwoWin() {
    if (
      box1.innerHTML === playerTwo &&
      box2.innerHTML === playerTwo &&
      box3.innerHTML === playerTwo
    ) {
      console.log("playertwowins");
    } else if (
      box1.innerHTML === playerTwo &&
      box4.innerHTML === playerTwo &&
      box7.innerHTML === playerTwo
    ) {
      console.log("playertwowins");
    } else if (
      box1.innerHTML === playerTwo &&
      box5.innerHTML === playerTwo &&
      box9.innerHTML === playerTwo
    ) {
      console.log("playertwowins");
    } else if (
      box2.innerHTML === playerTwo &&
      box5.innerHTML === playerTwo &&
      box8.innerHTML === playerTwo
    ) {
      console.log("playertwowins");
    } else if (
      box3.innerHTML === playerTwo &&
      box6.innerHTML === playerTwo &&
      box9.innerHTML === playerTwo
    ) {
      console.log("playertwowins");
    } else if (
      box3.innerHTML === playerTwo &&
      box5.innerHTML === playerTwo &&
      box7.innerHTML === playerTwo
    ) {
      console.log("playertwowins");
    } else if (
      box4.innerHTML === playerTwo &&
      box5.innerHTML === playerTwo &&
      box6.innerHTML === playerTwo
    ) {
      console.log("playertwowins");
    } else if (
      box7.innerHTML === playerTwo &&
      box8.innerHTML === playerTwo &&
      box9.innerHTML === playerTwo
    ) {
      console.log("playertwowins");
    }
  }
  playerTwoWin();
}

var allBoxes = document.querySelector(".allBoxes");
allBoxes.addEventListener("click", clickBoxPlayer);
.allBoxes div {
  display     : block;
  float       : left;
  width       : 2em;
  height      : 2em;
  margin      : .3em;
  background  : lightgrey;
  text-align  : center;
  line-height : 1.8em;
  cursor      : pointer;
  }
.allBoxes div:nth-of-type(4),
.allBoxes div:nth-of-type(7) {
  clear : left;
  }
<section class="allBoxes">
  <div class="box1"></div>
  <div class="box2"></div>
  <div class="box3"></div>
  <div class="box4"></div>
  <div class="box5"></div>
  <div class="box6"></div>
  <div class="box7"></div>
  <div class="box8"></div>
  <div class="box9"></div>
</section>

2 Answers

You are correct, if you changed your playerOneWin and playerTwoWin functions to return true or false based on the checks that you are already doing and if you also add a function that returns true if all boxes are filled (and false otherwise), then you can use them to check for the winning and the draw conditions like this

    if (playerOneWin()) {
        console.log("playeronewins");
    }

    // your other code

    if (playerTwoWin()) {
        console.log("playertwowins");
    }
    else if (allBoxesFilled() && !playerOneWin()) {
        console.log("draw");
    }

EDIT: to check all of the boxes you can put all of them (box1 - box9) into an array

// you could also do this by selecting all boxes
// with a document.querySelectorAll(...)
const boxes = [box1, box2, box3, box4, box5, box6, box7, box8, box9]

and then call .every on the boxes array with a predicate function. The predicate function has to return true, when the condition you are interested in is met, and false when the condition is not met. The condition you are interested in is that each box has to be filled, so it must not be empty, so the condition is innerHTML !== "". With such predicate function .every will return true only if the condition is true for all the items in the array (every means every item meets the condition in the predicate function). Which gives us the following code

const allBoxesFilled = boxes.every(box => box.innerHTML !== "")

You can use it like this in your code (instead of the function call), or put it into a function

function allBoxesFilled() {
  const boxes = [box1, box2, box3, box4, box5, box6, box7, box8, box9]
  return boxes.every(box => box.innerHTML !== "")
}

the way to do that:

const
  Boxes    = Array.from(document.querySelectorAll('#allBoxes > div'))
, players  = ['x','o']
, winCases = [[0,1,2],[3,4,5],[6,7,8],[0,4,8],[2,4,6],[0,3,6],[1,4,7],[2,5,8]] 
  ;
var 
  playerNum = 0
, winnerIs  = ''
  ;
document.querySelector('#allBoxes').onclick = ({target}) =>
  {
  if (!target.matches('#allBoxes div')
    || winnerIs != '' 
    ) return

  if (target.textContent ==='')
    {
    target.textContent = players[playerNum]
    checkWinner(players[playerNum])
    playerNum = ++playerNum % 2
  } }
function checkWinner(player)
  {
  if (winCases.some(suite=>suite.every(x=>Boxes[x].textContent === player )))
    {
    winnerIs = player
    console.log(' winner is:',player)
     
    for (let [a,b,c] of winCases)
      {
      if ( Boxes[a].textContent === player
        && Boxes[b].textContent === player
        && Boxes[c].textContent === player
        ){
        Boxes[a].className = Boxes[b].className = Boxes[c].className = 'win'
        break;
  } } } }
#allBoxes div {
  display     : block;
  float       : left;
  width       : 2em;
  height      : 2em;
  margin      : .3em;
  background  : lightgrey;
  text-align  : center;
  line-height : 1.8em;
  cursor      : pointer;
  }
#allBoxes div:nth-of-type(4),
#allBoxes div:nth-of-type(7) {
  clear : left;
  }
#allBoxes div.win {
  background : yellow;
  }
<section id="allBoxes">
  <div></div><div></div><div></div>
  <div></div><div></div><div></div>
  <div></div><div></div><div></div>
</section>

Related