Search code examples
javascripthtmlnode.jsdomtic-tac-toe

using JS to make tic tac toe


I have made a tic tac toe using JS however it has some problems My code is:

let x = [];
let o = [];
let xTurn = false;
let winPat = [
  ['00', '10', '20'],
  ['01', '11', '21'],
  ['02', '12', '22'],
  ['00', '01', '02'],
  ['10', '11', '12'],
  ['20', '21', '22'],
  ['00', '11', '22'],
  ['02', '11', '20']
];

const tableR = document.getElementsByClassName('tableR');
const button = document.getElementById('btn')

for (let i = 0; i <= 2; i++) {
  for (let j = 0; j <= 2; j++) {
    let newElement = document.createElement('td');
    tableR.item(i).appendChild(newElement);
    newElement.addEventListener('click', () => {
      if (elementIsEmpty(newElement)) {
        const img = document.createElement('img');
        if (xTurn) {
          img.src = 'https://www.google.com/url?sa=i&url=https%3A%2F%2Fcommons.wikimedia.org%2Fwiki%2FFile%3ARed_X.svg&psig=AOvVaw1B-fppvlN2x5oSCGllnXGc&ust=1634565535566000&source=images&cd=vfe&ved=0CAkQjRxqFwoTCMjbg6XN0fMCFQAAAAAdAAAAABAD';
          x.push(String(i) + String(j))
        } else {
          img.src = 'https://www.google.com/imgres?imgurl=https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2Fd%2Fd0%2FLetter_o.svg%2F407px-Letter_o.svg.png&imgrefurl=https%3A%2F%2Fcommons.wikimedia.org%2Fwiki%2FFile%3ALetter_o.svg&tbnid=p-B77Lz3DDttwM&vet=12ahUKEwizlYTWzdHzAhXMg9gFHTSaBJkQMygAegUIARDaAQ..i&docid=K2HPZsIMOu4d5M&w=407&h=768&q=pixture%20of%20o&ved=2ahUKEwizlYTWzdHzAhXMg9gFHTSaBJkQMygAegUIARDaAQ';
          o.push(String(i) + String(j))
        }
        newElement.append(img)
        checkWinOrDraw(xTurn)
        xTurn = !xTurn
      }
    })
  }
}

const td = document.getElementsByTagName('td')
button.addEventListener('click', () => {
  reset();
});

function elementIsEmpty(el) {
  return (/^(\s|&nbsp;)*$/.test(el.innerHTML));
}

function checkWinOrDraw(xTurn) {
  for (let i = 0; i < winPat.length; i++) {
    if (xTurn) {
      if (winPat[i].every(element => x.includes(element))) {
        alert('X wins')
        reset()
        return
      }
    } else {
      if (winPat[i].every(element => o.includes(element))) {
        alert('O wins')
        reset()
        return
      }
    }
  }

  for (let item of td) {
    if (elementIsEmpty(item))
      return
  }
  alert('Draw')
  reset()
}


function reset() {
  x = [];
  o = [];
  for (let item of td) {
    item.textContent = ''
  }
}
body {
  margin: 0px;
  background-color: #3c4552;
  color: aliceblue;
  text-align: center;
}

header {
  height: 75px;
  background-color: #1f1e1c;
  padding: 20px;
  font-size: large;
}

table {
  border-collapse: collapse;
  margin: 40px auto;
}

td {
  border: 7px solid black;
  height: 121px;
  width: 121px;
  cursor: pointer;
}

button {
  background-color: #1f1e1c;
  color: white;
  width: 25%;
  height: 50px;
  font-size: larger;
  border: black solid 2px;
  border-radius: 7px;
  cursor: pointer;
}

img {
  display: block;
  width: 100%;
  height: 100%;
}
<header>
  <h1>TicTacToe</h1>
</header>
<main>
  <table>
    <tr class="tableR"></tr>
    <tr class="tableR"></tr>
    <tr class="tableR"></tr>
  </table>
</main>
<footer>
  <button id="btn">RESET</button>
</footer>

my problem is that when the game ends, say X wins, the image is not rendered on the screen, and alert() is called. I googled a lot and found no solutions.

details and clarity: the image is not rendered on screen at the end of the game. try on your computer and see. alert() is called before the image is present in-game which results in a bad user experience. hence I need a solution.


Solution

  • Here your append() function is not able to complete image load & your checkWinOrDraw() function got called that's why this is happening.

    Please try with the below code i am calling the checkWinOrDraw() once image gets loaded or failed.

    for (let i = 0; i <= 2; i++) {
      for (let j = 0; j <= 2; j++) {
        let newElement = document.createElement('td');
        tableR.item(i).appendChild(newElement);
        newElement.addEventListener('click', () => {
          if (elementIsEmpty(newElement)) {
            const img = document.createElement('img');
            if (xTurn) {
              img.src =  'https://dummyimage.com/20x20/3a4ca6/fff';
              x.push(String(i) + String(j))
            } else {
              img.src = 'https://dummyimage.com/30x30/fff/fff';
              o.push(String(i) + String(j))
            }
            console.log(xTurn)
             xTurn = !xTurn
            img.addEventListener('load', checkWinOrDraw)
      img.addEventListener('error', checkWinOrDraw)
            newElement.appendChild(img)
          }
        })
      }
    }
    
    function checkWinOrDraw(e,xTurn) {
            
      //console.log('checking',xTurn)
      for (let i = 0; i < winPat.length; i++) {
        if (xTurn) {
          if (winPat[i].every(element => x.includes(element))) {
            alert('X wins')
            reset()
            return
          }
        } else {
          if (winPat[i].every(element => o.includes(element))) {
            alert('O wins')
            reset()
            return
          }
        }
      }
    
      for (let item of td) {
        if (elementIsEmpty(item))
          return
      }
      alert('Draw')
      reset()
    }