井字游戏自动播放无法正常工作

时间:2019-01-25 14:41:17

标签: javascript html css tic-tac-toe

我正在做一个井字游戏,该功能非常适合用户回合,但是在计算机回合播放时,这些功能会崩溃并给出意外结果,例如两次播放,请跳过转等等。

谁能告诉我我的代码有什么问题,并帮助我解决此问题?

const start = document.getElementById('start');
const table = document.getElementById('table');
places = ["one", "two", "three", "four", "five", "six", "seven", 'eight', "nine"];
let move = 0;
start.addEventListener('click', function(){
    user();
});


function user(){
    table.addEventListener('click', function(event){
        let pos = event.target;
        let Id = event.target.id;
        if (/[1-9]/.test(pos.innerHTML)){
            pos.innerHTML = "X";
            move += 1;
            places.splice(places.indexOf(Id), 1 );
        }
        if (move > 8){
            gameOver();
        } 
        if (move <= 8){
            computer();
        }
    });
}

function gameOver(){
    console.log("Game Over");
}

function computer(){
    let index = places[Math.floor(Math.random() * places.length)];
    let pos = document.getElementById(index);
    if (/[1-9]/.test(pos.innerHTML)){
        pos.innerHTML = "O";
        move += 1;
        places.splice(places.indexOf(pos), 1 );
    }
    if (move > 8){
        gameOver();
    } 
    if (move <= 8) {
        user();
    }
}
<div class="col text-center">
    <table class="table text-center">
        <tbody id="table">
            <tr>
                <td id="one">1</td>
                <td id="two">2</td>
                <td id="three">3</td>
            </tr>
            <tr>
                <td id="four">4</td>
                <td id="five">5</td>
                <td id="six">6</td>
            </tr>
            <tr>
                <td id="seven">7</td>
                <td id="eight">8</td>
                <td id="nine">9</td>
            </tr>
        </tbody>
    </table>
    <br />
    <button class="btn btn-primary" type="button" id="start">Start Game</button>
</div>

3 个答案:

答案 0 :(得分:1)

让我尝试改写我的原始答案: 轮到计算机时,您正在执行此代码

function computer(){
    let index = places[Math.floor(Math.random() * places.length)];
    let pos = document.getElementById(index);
    if (/[1-9]/.test(pos.innerHTML)){
        pos.innerHTML = "O";
        move += 1;
        places.splice(places.indexOf(pos), 1 );
    }
    if (move > 8){
        gameOver();
    } 
    if (move <= 8) {
        user();
    }

}

如果if (/[1-9]/.test(pos.innerHTML)){返回false,会发生什么? (即该字段已被占用),您的代码将继续执行,就好像计算机已经将转弯交给用户一样。

所以我的建议是,您需要确保计算机实际进行了移动,一种方法是添加一个发现的变量,该变量被初始化为false,并且在实际发现并进行计算机移动时首先将其设置为true。

这可以通过将您的方法修改为类似方式来完成:

function computer(){
   let foundEmptyField=false;
   while(foundEmptyField===false) 
   {
     let index = places[Math.floor(Math.random() * places.length)];
     let pos = document.getElementById(index);
     if (/[1-9]/.test(pos.innerHTML)){
        pos.innerHTML = "O";
        move += 1;
        places.splice(places.indexOf(pos), 1 );
        foundEmptyField = true;
     }
     if(foundEmptyField===true) {
        if (move > 8){
           gameOver();
        } 
        if (move <= 8) {
           user();
        }
     }
   }
}

如果您查看代码,则在user()代码中确实存在完全相同的问题

答案 1 :(得分:0)

问题说明: 您已经创建了一个事件监听器,该监听器在用户每次单击时发生

    start.addEventListener('click', function(){
    user();
});

您做不到的是确定轮到谁了,因此用户可能会双击甚至单击播放的图块,甚至单击计算机上的转向,并且代码不会使用户转身但接受移动当玩家转弯时。

因此,我已经添加了用户功能

        }else{
      return;
    }

如果点击的磁贴已经按X指示播放过,则会忽略转牌。

我还向计算机功能添加了一个调用,以重试一次移动,如果计算机随机生成一个已播放的磁贴编号,则它不会交还给玩家,而是会重试。

}else{
  computer();
}

最后,我简化了您的代码,因为您重复了一些代码,可以将这些代码转换成带有变量的函数。

    function gameStateCheck(stTurn){
    if (move > 8){
        gameOver();
    } 
    if (move <= 8) {
        if (stTurn == "user"){
          user();
         }else{
          computer();
         }
    }
}

替代解决方案: 此解决方案完全是-重新编写您的代码,但是由于它被告知CPU知道哪些动作有效,因此它可以正常工作,并且不会陷入函数调用循环中。

const start = document.getElementById('start');
const table = document.getElementById('table');
places = [];
start.addEventListener('click', function(){
    places = [];    // reset the array of available tiles to play
    for (i = 0; i < 9; i++){ // re populate available tiles 0-8
      places.push (i);
    }
    
    // run a loop to clear the previous game cell markers (O or X);
    for (x = 0; x < table.rows.length; x++){
        for (i = 0; i < table.rows[x].cells.length; i++){
          table.rows[x].cells[i].innerHTML = "";
        }
    }
    // Mark the users move 
   user();
});


function user(){
    table.addEventListener('click', function(event){
        // get the ID of the played tile
        let Id = parseInt(event.target.id);   
         
         // locate the index number in the array that contains the ID
        let PlayedTile = places.indexOf(Id); 
        
        if (PlayedTile > -1){
          // if PlayerTile is NOT -1, it means it exists in the array
          // lets remove it from the available tiles to play array
          places.splice(places.indexOf(Id), 1 );
          
        }else{
          // Ok so this user has already played this tile or the CPU has
          // Therefore we exit the function and nothing changes on the screen
          
          // Recommendation: add some code to notify your user this move has been played
          return;
        }
        
        // Ok so if we havent exited the function above due to having played the tile
        // we can now update the cell with an "X"
        event.target.innerHTML = "X";
        
        // we now check to see if there are any further moves available (by checking the length
        // of the places array, if it is 0 we declare game over)
        
        if (places.length == 0){
            gameover();
            return;
        }else{
        // otherwise we pass control to the CPU
    		  computer();
        }
    });
}

function computer(){
    // we know how many moves are available by the length of the array
    // so lets choose 1 random box ID number
    let cpuMove = Math.floor(Math.random() * places.length);
    
    // now lets get the value of that array index, as this value will be the table cell ID
    let cpuPlayedTileId = places[cpuMove];
    
    // now lets grab the cell element by its ID
    let pos = document.getElementById(cpuPlayedTileId);
    
    // Update the cell with an "O" marker
    // NOTE the CPU cannot physically choose an invalid move as the CPU knows the available moves
    pos.innerHTML = "O";
    
    // As it is a valid move, lets remove it from the array for the player.
    places.splice(places.indexOf(cpuPlayedTileId), 1 );
    
    // check if the game is now over
    if (places.length == 0){
        gameover();
        return;
    }else{
      user();
    }
}

function gameover(){
	alert("gameover");
  console.log("Game Over");
}
#boardGame{
  background: grey;
  border: 1px solid black;
  height: 90px;
  width: 90px;
}
#boardGame tr td{
  border: 1px solid silver;
  width: 30px;
  height: 30px;
  text-align: center;
  font-size: small;
}
<div class="col text-center">
    <table id="boardGame" class="table text-center">
        <tbody id="table">
            <tr>
                <td id="0"></td>
                <td id="1"></td>
                <td id="2"></td>
            </tr>
            <tr>
                <td id="3"></td>
                <td id="4"></td>
                <td id="5"></td>
            </tr>
            <tr>
                <td id="6"></td>
                <td id="7"></td>
                <td id="8"></td>
            </tr>
        </tbody>
    </table>
    <br>
    <button class="btn btn-primary" type="button" id="start">Start Game</button>
</div>

您的代码库,已固定 请注意,您可能会陷入无限循环中,这将导致超出呼叫错误。但是我留下的代码与您上面的代码差不多。

我上面已编码了无错误代码,就像我要编码一样

const start = document.getElementById('start');
const table = document.getElementById('table');
places = ["one", "two", "three", "four", "five", "six", "seven", 'eight', "nine"];
let move = 0;
start.addEventListener('click', function(){
    user();
});


function user(){
    table.addEventListener('click', function(event){
        let pos = event.target;
        let Id = event.target.id;
        if (/[1-9]/.test(pos.innerHTML)){
            pos.innerHTML = "X";
            move += 1;
            places.splice(places.indexOf(Id), 1 );
        }else{
          return;
        }
		gameStateCheck("CPU");
    });
}

function gameOver(){
    console.log("Game Over");
}

function computer(){
    let index = places[Math.floor(Math.random() * places.length)];
    let pos = document.getElementById(index);
    if (/[1-9]/.test(pos.innerHTML)){
        pos.innerHTML = "O";
        move += 1;
        places.splice(places.indexOf(pos), 1 );
    }else{
      computer();
    }
    gameStateCheck("user");
}

function gameStateCheck(stTurn){
	if (move > 8){
        gameOver();
    } 
    if (move <= 8) {
        if (stTurn == "user"){
          user();
         }else{
          computer();
         }
    }
}
<div class="col text-center">
    <table class="table text-center">
        <tbody id="table">
            <tr>
                <td id="one">1</td>
                <td id="two">2</td>
                <td id="three">3</td>
            </tr>
            <tr>
                <td id="four">4</td>
                <td id="five">5</td>
                <td id="six">6</td>
            </tr>
            <tr>
                <td id="seven">7</td>
                <td id="eight">8</td>
                <td id="nine">9</td>
            </tr>
        </tbody>
    </table>
    <br>
    <button class="btn btn-primary" type="button" id="start">Start Game</button>
</div>

答案 2 :(得分:0)

欢迎来到stackoverflow。每次调用用户函数时都添加事件侦听器,但是该事件侦听器仅应添加一次。在计算机功能中,您剪接了pos的索引(即HTMLElement),而是剪接了索引var的索引,例如“ one”,“ two”等。不应从计算机功能,因为它是由事件侦听器触发的。由于计算机仅从位置上未接触的元素中进行选择,因此计算机功能中的测试是多余的。为了清楚起见,我引入了一个init函数进行进一步扩展。以下是正在运行的解决方案:

<!DOCTYPE html>
<html>
<head>
    <title>Tic Tac Toe</title>
    <meta charset="UTF-8">
    <script type="text/javascript">
        var places, move;
        function init() {
            places = ["one", "two", "three", "four", "five", "six", "seven", 'eight', "nine"];
            move = 0;
            table.addEventListener('click', user);
        }

        function user(event) {
            let pos = event.target;
            let Id = event.target.id;
            if (/[1-9]/.test(pos.innerHTML)) {
                pos.innerHTML = "X";
                move += 1;
                places.splice(places.indexOf(Id), 1);
                if (move > 8) {
                    gameOver();
                }
                else {
                    computer();
                }
            }
        }

        function gameOver() {
            console.log("Game Over");
        }

        function computer() {
            let index = places[Math.floor(Math.random() * places.length)];
            let pos = document.getElementById(index);
            pos.innerHTML = "O";
            move += 1;
            places.splice(places.indexOf(index), 1);
            if (move > 8) {
                gameOver();
            }
        }
    </script>
</head>
<body>
    <div class="col text-center">
        <table class="table text-center">
            <tbody id="table">
                <tr>
                    <td id="one">1</td>
                    <td id="two">2</td>
                    <td id="three">3</td>
                </tr>
                <tr>
                    <td id="four">4</td>
                    <td id="five">5</td>
                    <td id="six">6</td>
                </tr>
                <tr>
                    <td id="seven">7</td>
                    <td id="eight">8</td>
                    <td id="nine">9</td>
                </tr>
            </tbody>
        </table>
        <br />
        <button class="btn btn-primary" type="button" onclick="init()" id="start">Start Game</button>
    </div>
</body>
</html>