skip to Main Content

I am making Tic Tac Toe Game , I am giving two options for the player to play the game that is VS player and VS computer
Both functions logic is ready but when I am integrating both the code so the function that I run first , only that logic is only implemented
ex if I run first VSplayer then after clicking on VScomp then also VSplayer code is running, and vice versa
I know this code can be optimized but I was facing problems that’s why I tried to break both in different functions and try it

// Computer Logic
function VScomp() {
    var Boxes = document.querySelectorAll('.box')
    var info = document.getElementById('info')
    let reset = document.getElementById('reset')
    var a = "X"
    let gameover = false
    info.innerText = `Player X Turn`

    Boxes.forEach(box => {
        box.addEventListener('click', () => {
            if (box.innerHTML == "" && !gameover) {

                box.innerHTML = a
                checkWins()
                compchoice()

                if (gameover) {
                    Boxes.forEach((box) => {
                        box.style.cursor = "not-allowed"
                    })
                }
            }
        })
    })
    // Check Wins
    const checkWins = () => {
        let wins = [
            [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]
        ]
        wins.forEach(i => {
            if (Boxes[i[0]].innerHTML == Boxes[i[1]].innerHTML && Boxes[i[1]].innerHTML == Boxes[i[2]].innerHTML && Boxes[i[0]].innerHTML != "") {
                info.innerText = `${Boxes[i[0]].innerHTML} Won`
                gameover = true
                i.forEach(y => {
                    Boxes[y].classList.add("winner")
                })

            }
        })
    }
    reset.addEventListener('click', () => {
        Boxes.forEach(box => {
            box.innerHTML = ""
            gameover = false
            a = "X"
            info.innerText = `Player X Turn`
            Boxes.forEach((box) => {
                box.classList.remove("winner")
                box.style.cursor = "pointer"
            })
        })
    })

    function compchoice() {
        if (!gameover) {
            let flag = false;

            while (!flag) {
                let nums = Math.floor(Math.random() * 8);
                let box = Boxes[nums];

                if (box.innerHTML === "") {
                    box.innerHTML = "O";
                    flag = true;
                    checkWins();
                }
            }
        }
    }
}

// // VS player Logic
function VSplayer() {
    let Boxes = document.querySelectorAll('.box')
    let info = document.getElementById('info')
    let reset = document.getElementById('reset')
    var a = "O"
    let gameover = false
    info.innerText = `X Turn`

    Boxes.forEach(box => {
        box.addEventListener('click', () => {
            if (box.innerHTML == "" && !gameover) {
                if (a === "O") {
                    info.innerText = `${a} Turn`
                    a = "X"
                }
                else if (a === "X") {
                    info.innerText = `${a} Turn`
                    a = "O"
                }
                box.innerHTML = a
                checkWins()

                if (gameover) {
                    Boxes.forEach((box) => {
                        box.style.cursor = "not-allowed"
                    })
                }
            }
        })
    })

    // Check Wins
    const checkWins = () => {
        let wins = [
            [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]
        ]
        wins.forEach(i => {
            if (Boxes[i[0]].innerHTML == Boxes[i[1]].innerHTML && Boxes[i[1]].innerHTML == Boxes[i[2]].innerHTML && Boxes[i[0]].innerHTML != "") {
                info.innerText = `${Boxes[i[0]].innerHTML} Won`
                gameover = true

                i.forEach(y => {
                    Boxes[y].classList.add("winner")
                })
            }
        })
    }
    reset.addEventListener('click', () => {
        Boxes.forEach(box => {
            box.innerHTML = ""
            gameover = false
            a = "O"
            info.innerText = `X Turn`
            Boxes.forEach((box) => {
                box.classList.remove("winner")
                box.style.cursor = "pointer"
            })
        })
    })
}
VScomp()
* {
  padding: 0;
  margin: 0;
}
body {
  overflow: hidden;
}
.game {
  grid-template-columns: repeat(3, 10vw);
  grid-template-rows: repeat(3, 15vh);
}
.customfont
{
  font-size: 56px;
  color: black;
}
.carousel
{
  top:-16px;
}
.carousel-inner
{
  top: 4px;
}
.carousel-control
{
  top: -16px;
}

@media screen and (max-width: 730px) {
  .game {
    grid-template-columns: repeat(3, 16vw);
  }
}
.box {
  border: 1px solid black;
  display: flex;
  flex-wrap: wrap;
  align-content: center;
  justify-content: center;
}

.box:hover {
  cursor: pointer;
  background-color: #d0d8d9;
}

.maindiv {
  background-color: #2e2922;
}

.subdiv {
  background-color: silver;
  border-radius: 22px;
  min-width: 300px;
}
#reset:hover
{
    color: red !important;
}
#reset:focus
{
    box-shadow: none !important;
}

#tic {
  animation: tic 2s linear 1;
}
@keyframes tic {
  from {
    margin-left: -60vw;
  }
  to {
    margin-left: 0;
  }
}
#tac {
  animation: tac 2s linear 1;
}
@keyframes tac {
  0% {
    margin-top: -60vh;
    
  }
  85% {

    margin-top: 0;
    
  }
}
#toe {
  animation: toe 2s linear 1;
}
@keyframes toe {
  from {
    margin-right: -60vw;
  }
  to {
    margin-right: 0vw;
  }
}
.winner
{
  animation: blink 1s linear infinite ;
  
}

@keyframes blink
{
from {
color: transparent;
}
to {
color: black;
}
}
<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <link rel="stylesheet" href="style.css">
    <title>Tic Tac Toe</title>
</head>

<body>
    </div>

    <div class="maindiv min-vh-100 d-flex justify-content-center flex-column align-content-center flex-wrap">
        <div class="text-white d-flex justify-content-center">

            <div>
                <h1 class="ps-3" id="tic">TIC</h1>
            </div>
            <div>
                <h1 class="ps-3" id="tac">TAC</h1>
            </div>
            <div>
                <h1 class="ps-3 text-end" id="toe">TOE</h1>
            </div>


        </div>
        <div class="subdiv d-flex h-100 p-4 flex-column">
            <div class="gameInfo">

                  <div>
                                            <button class="VScomp" onclick="VSplayer()">VS Player</button>
                    <button class="VSplayer" onclick="VScomp()">VS Comp</button>
                  </div>
                <h2>
                    <div class=" d-flex justify-content-center" id="info"></div>
                </h2>

            </div>
            <div class="game mt-4 d-grid  justify-content-center ">
                <div class="box fw-bolder fs-3 border-top-0 border-start-0 "></div>
                <div class="box fw-bolder fs-3 border-top-0 "></div>
                <div class="box fw-bolder fs-3 border-top-0 border-end-0 "></div>
                <div class="box fw-bolder fs-3 border-start-0 "></div>
                <div class="box fw-bolder fs-3 "></div>
                <div class="box fw-bolder fs-3 border-end-0 "></div>
                <div class="box fw-bolder fs-3 border-start-0 border-bottom-0 "></div>
                <div class="box fw-bolder fs-3 border-bottom-0 "></div>
                <div class="box fw-bolder fs-3 border-bottom-0 border-end-0 "></div>
            </div>
            <div class="d-flex justify-content-center mt-3"><button type="button" class="btn btn-lg"
                    id="reset">Reset</button></div>
        </div>
    </div>


    <script src="JQUERY-Version.js"></script>
    <script src="temp.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js"
        integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB"
        crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"
        integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13"
        crossorigin="anonymous"></script>
</body>

</html>

2

Answers


  1. VScomp and VSplayer both add event handlers to your boxes. If you call both functions, both sets of event handlers will be added so both handlers will be called when a box is clicked.

    To fix this, either remove the event handlers before adding the new ones, or use a single event handler that looks at the current playing mode to decide what to do.

    Login or Signup to reply.
  2. You need to call both VScomp and VSplayer to support both use-cases, but, besides of that, you will need to switch off the events when the other use-case is chosen. This is a working example that you can start your thought-process from:

    var isComp = true;
    // Computer Logic
    function VScomp() {
        var Boxes = document.querySelectorAll('.box')
        var info = document.getElementById('info')
        let reset = document.getElementById('reset')
        var a = "X"
        let gameover = false
        info.innerText = `Player X Turn`
    
        Boxes.forEach(box => {
            box.addEventListener('click', () => {
                if (!isComp) return;
                if (box.innerHTML == "" && !gameover) {
    
                    box.innerHTML = a
                    checkWins()
                    compchoice()
    
                    if (gameover) {
                        Boxes.forEach((box) => {
                            box.style.cursor = "not-allowed"
                        })
                    }
                }
            })
        })
        // Check Wins
        const checkWins = () => {
            let wins = [
                [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]
            ]
            wins.forEach(i => {
                if (Boxes[i[0]].innerHTML == Boxes[i[1]].innerHTML && Boxes[i[1]].innerHTML == Boxes[i[2]].innerHTML && Boxes[i[0]].innerHTML != "") {
                    info.innerText = `${Boxes[i[0]].innerHTML} Won`
                    gameover = true
                    i.forEach(y => {
                        Boxes[y].classList.add("winner")
                    })
    
                }
            })
        }
        reset.addEventListener('click', () => {
            if (!isComp) return;
            Boxes.forEach(box => {
                box.innerHTML = ""
                gameover = false
                a = "X"
                info.innerText = `Player X Turn`
                Boxes.forEach((box) => {
                    box.classList.remove("winner")
                    box.style.cursor = "pointer"
                })
            })
        })
    
        function compchoice() {
            if (!isComp) return;
            if (!gameover) {
                let flag = false;
    
                while (!flag) {
                    let nums = Math.floor(Math.random() * 8);
                    let box = Boxes[nums];
    
                    if (box.innerHTML === "") {
                        box.innerHTML = "O";
                        flag = true;
                        checkWins();
                    }
                }
            }
        }
    }
    
    // // VS player Logic
    function VSplayer() {
        let Boxes = document.querySelectorAll('.box')
        let info = document.getElementById('info')
        let reset = document.getElementById('reset')
        var a = "O"
        let gameover = false
        info.innerText = `X Turn`
    
        Boxes.forEach(box => {
            box.addEventListener('click', () => {
                if (isComp) return;
                if (box.innerHTML == "" && !gameover) {
                    if (a === "O") {
                        info.innerText = `${a} Turn`
                        a = "X"
                    }
                    else if (a === "X") {
                        info.innerText = `${a} Turn`
                        a = "O"
                    }
                    box.innerHTML = a
                    checkWins()
    
                    if (gameover) {
                        Boxes.forEach((box) => {
                            box.style.cursor = "not-allowed"
                        })
                    }
                }
            })
        })
    
        // Check Wins
        const checkWins = () => {
            let wins = [
                [0, 1, 2], [3, 4, 5], [6, 7, 8], [0, 3, 6], [1, 4, 7], [2, 5, 8], [0, 4, 8], [2, 4, 6]
            ]
            wins.forEach(i => {
                if (Boxes[i[0]].innerHTML == Boxes[i[1]].innerHTML && Boxes[i[1]].innerHTML == Boxes[i[2]].innerHTML && Boxes[i[0]].innerHTML != "") {
                    info.innerText = `${Boxes[i[0]].innerHTML} Won`
                    gameover = true
    
                    i.forEach(y => {
                        Boxes[y].classList.add("winner")
                    })
                }
            })
        }
        reset.addEventListener('click', () => {
            Boxes.forEach(box => {
                box.innerHTML = ""
                gameover = false
                a = "O"
                info.innerText = `X Turn`
                Boxes.forEach((box) => {
                    box.classList.remove("winner")
                    box.style.cursor = "pointer"
                })
            })
        })
    }
    VSplayer();
    VScomp();
    * {
      padding: 0;
      margin: 0;
    }
    body {
      overflow: hidden;
    }
    .game {
      grid-template-columns: repeat(3, 10vw);
      grid-template-rows: repeat(3, 15vh);
    }
    .customfont
    {
      font-size: 56px;
      color: black;
    }
    .carousel
    {
      top:-16px;
    }
    .carousel-inner
    {
      top: 4px;
    }
    .carousel-control
    {
      top: -16px;
    }
    
    @media screen and (max-width: 730px) {
      .game {
        grid-template-columns: repeat(3, 16vw);
      }
    }
    .box {
      border: 1px solid black;
      display: flex;
      flex-wrap: wrap;
      align-content: center;
      justify-content: center;
    }
    
    .box:hover {
      cursor: pointer;
      background-color: #d0d8d9;
    }
    
    .maindiv {
      background-color: #2e2922;
    }
    
    .subdiv {
      background-color: silver;
      border-radius: 22px;
      min-width: 300px;
    }
    #reset:hover
    {
        color: red !important;
    }
    #reset:focus
    {
        box-shadow: none !important;
    }
    
    #tic {
      animation: tic 2s linear 1;
    }
    @keyframes tic {
      from {
        margin-left: -60vw;
      }
      to {
        margin-left: 0;
      }
    }
    #tac {
      animation: tac 2s linear 1;
    }
    @keyframes tac {
      0% {
        margin-top: -60vh;
        
      }
      85% {
    
        margin-top: 0;
        
      }
    }
    #toe {
      animation: toe 2s linear 1;
    }
    @keyframes toe {
      from {
        margin-right: -60vw;
      }
      to {
        margin-right: 0vw;
      }
    }
    .winner
    {
      animation: blink 1s linear infinite ;
      
    }
    
    @keyframes blink
    {
    from {
    color: transparent;
    }
    to {
    color: black;
    }
    }
    <!doctype html>
    <html lang="en">
    
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
            integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
        <link rel="stylesheet" href="style.css">
        <title>Tic Tac Toe</title>
    </head>
    
    <body>
        </div>
    
        <div class="maindiv min-vh-100 d-flex justify-content-center flex-column align-content-center flex-wrap">
            <div class="text-white d-flex justify-content-center">
    
                <div>
                    <h1 class="ps-3" id="tic">TIC</h1>
                </div>
                <div>
                    <h1 class="ps-3" id="tac">TAC</h1>
                </div>
                <div>
                    <h1 class="ps-3 text-end" id="toe">TOE</h1>
                </div>
    
    
            </div>
            <div class="subdiv d-flex h-100 p-4 flex-column">
                <div class="gameInfo">
    
                      <div>
                                                <button class="VScomp" onclick="isComp = false">VS Player</button>
                        <button class="VSplayer" onclick="isComp = true">VS Comp</button>
                      </div>
                    <h2>
                        <div class=" d-flex justify-content-center" id="info"></div>
                    </h2>
    
                </div>
                <div class="game mt-4 d-grid  justify-content-center ">
                    <div class="box fw-bolder fs-3 border-top-0 border-start-0 "></div>
                    <div class="box fw-bolder fs-3 border-top-0 "></div>
                    <div class="box fw-bolder fs-3 border-top-0 border-end-0 "></div>
                    <div class="box fw-bolder fs-3 border-start-0 "></div>
                    <div class="box fw-bolder fs-3 "></div>
                    <div class="box fw-bolder fs-3 border-end-0 "></div>
                    <div class="box fw-bolder fs-3 border-start-0 border-bottom-0 "></div>
                    <div class="box fw-bolder fs-3 border-bottom-0 "></div>
                    <div class="box fw-bolder fs-3 border-bottom-0 border-end-0 "></div>
                </div>
                <div class="d-flex justify-content-center mt-3"><button type="button" class="btn btn-lg"
                        id="reset">Reset</button></div>
            </div>
        </div>
    
    
        <script src="JQUERY-Version.js"></script>
        <script src="temp.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js"
            integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB"
            crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"
            integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13"
            crossorigin="anonymous"></script>
    </body>
    
    </html>

    As you can see, I used an isComp flag to know whether the secondary moves are to be made by the comp. If so, then the comp will make the moves. Otherwise a human move will be expected.

    A better solution would be to create a single cell event listener for each cell and implement two validators. Depending on what mode you are in, the right move validator would be chosen.

    Validator in comp mode: first player is on move and the move to be made is valid.

    Validator in human mode: any player is on move and the move to be made is valid.

    In comp mode call a comp move function after the player has moved as long as the game did not finish.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search