我的 TicTacToe 中的这些意外效果是否只是我不知道的 Javascript 计时方面?

如何解决我的 TicTacToe 中的这些意外效果是否只是我不知道的 Javascript 计时方面?

我制作了一款运行良好的井字游戏。不过,我正在努力解决两件事。

  1. 在我选择我的之后,对手在“DumbAI”中的动作立即显示。当我施加 setTimeout() 并且 AI 对手获胜时,残局序列不会触发。不过,当我获胜时它会起作用。

最后的顺序是,当任何人连续得到 3 个时,警报应该闪烁,获胜的 3 个方格会突出显示,并且事件侦听器被移除,因此无法进行更多标记。

相反,代码让我切换到活跃玩家。如果主动玩家连续获得 3 个,则残局序列会触发。

所有这些功能都在同一个块中。通过在对手的移动上放置 setTimeout(),是否跳过了残局序列?

  1. 同样,当我将残局序列分解为单独的块时,会出现另一个问题。

当我将残局序列从方块中取出并获胜时,代码会闪烁警报并突出显示空格,但它也会允许 AI 对手进行额外的移动。

通过将残局序列从块中取出,计算机是否在代码中移动得太快,允许对手在启动残局序列之前轮到他?

script.js:

var ONE_CLASS
var TWO_CLASS

const btn = document.querySelector('#PlayerOneSymbol');

btn.onclick = function () {
    const XOs = document.querySelectorAll('input[name="choice"]');
    for (const XO of XOs) {
        if (XO.checked) {
          ONE_CLASS = XO.value
          TWO_CLASS = XO.value == 'X' ? 'O' : 'X'
          break;
        }
    }
    alert("First Move Belongs to " + ONE_CLASS + ". Select Player Two.");
    };

var playerTwoIdentity
  
const btn2 = document.querySelector('#PlayerTwoChoice');
btn2.onclick = function () {
    const Opponents = document.querySelectorAll('input[name="choice2"]');
    for (const Opponent of Opponents) {
        if (Opponent.checked) {
          playerTwoIdentity = Opponent.value
          break;
        }
    }
    alert("Your Opponent is "  + playerTwoIdentity + ". Start New Game.")
    };

let playerOneTurn 
    
function swapTurns() {
  playerOneTurn = !playerOneTurn
};

const winningTrios = [
    [0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,7],[2,5,2]
]

restartBtn.addEventListener('click',startGame);

function startGame() {
  if (ONE_CLASS == undefined || playerTwoIdentity == undefined) {return alert ("Make sure players are defined")}
  console.log("player 1 = " + ONE_CLASS + ",player 2 = " + playerTwoIdentity)
  drawBoard();
  playerOneTurn = true;
}

const arrayfromBoxes = Array.from(document.getElementsByClassName('box'));
const stylingOfBoxes = document.querySelectorAll('.box');

function drawBoard() {
  console.log(stylingOfBoxes)
  for (let i = 0; i < stylingOfBoxes.length; i++) {
  stylingOfBoxes[i].addEventListener('click',boxmarked,{once: true});}
    stylingOfBoxes.forEach(gridBox => {
    gridBox.classList.remove(ONE_CLASS)
    gridBox.classList.remove(TWO_CLASS)
    gridBox.classList.remove('winner')
    gridBox.innerHTML = ""
    })
    }

function boxmarked(e) {
    const index = arrayfromBoxes.indexOf(e.target)
// how to consolidate? maybe I just let ONE_CLASS mark and then if the AI or player
// or do it even earlier and link it with playerTurn? 
    if(playerOneTurn) {
        arrayfromBoxes[index].classList.add(ONE_CLASS)
        e.target.innerHTML = ONE_CLASS
      } else {
        arrayfromBoxes[index].classList.add(TWO_CLASS)
        e.target.innerHTML = TWO_CLASS
      }

      // if (playerhasWon()) {
      //   declareWinner()
      //   return
      // } 
      
      // if (emptySpaceRemains() == false) {
      //   declareTie()
      //   return
      // }
    hasGameEnded()
    swapTurns()

    // eliminate repetition - 
    if(playerTwoIdentity === "Dumb AI") {
      var dumbAIArray = arrayfromBoxes.reduce((dumbAIArray,box,idx) => {
        if (box.innerHTML === "") {
          dumbAIArray.push(idx);
          }
          return dumbAIArray;
        },[]);
        let dumbAIpicked = dumbAIArray[Math.floor(dumbAIArray.length * (Math.random()))]
        arrayfromBoxes[dumbAIpicked].classList.add(TWO_CLASS)
        arrayfromBoxes[dumbAIpicked].innerHTML = TWO_CLASS

// why does Timeoutfunction prevent opponent sequence?
// setTimeout(() => {arrayfromBoxes[dumbAIpicked].classList.add(TWO_CLASS)},500);
// setTimeout(() => {arrayfromBoxes[dumbAIpicked].innerHTML = TWO_CLASS},500);

// if (playerhasWon()) {
//   declareWinner()
//   return
// } 

// if (emptySpaceRemains() == false) {
//   declareTie()
//   return
// }

  hasGameEnded()
  swapTurns()
    } else { console.log("Human")
    }
}

function hasGameEnded() {
      // fix declareWinner() appears before the added classes bc alert happens quicker than redraw
      // I also cannot pull these out because then the opponent move fires and shows
      // could have something to do with timing of in-block code
      if (playerhasWon()) {
        declareWinner()
        return
      } 
      
      if (emptySpaceRemains() == false) {
        declareTie()
        return
      }
}

function checkClass() {
  if(playerOneTurn) {
  return ONE_CLASS
} else {
  return TWO_CLASS
};}

function emptySpaceRemains() {
  var innerHTMLempty = (insidebox) => insidebox.innerHTML===""
  console.log(arrayfromBoxes.some(innerHTMLempty))
  return (arrayfromBoxes.some(innerHTMLempty))
}

function declareTie() {
  setTimeout(alert ("TIE GAME"),1000)}

function playerhasWon() {
    var indexOfSelected = arrayfromBoxes.reduce((indexOfSelected,idx) => {
        if (box.classList[1] === checkClass()) {
            indexOfSelected.push(idx);
        }
        return indexOfSelected;
    },[]);

  const winningThreeIndexes = winningTrios
  .map(trio => trio.filter(i => indexOfSelected.includes(i)))
  .filter(i => i.length === 3);

  console.log(winningThreeIndexes)
  console.log(winningThreeIndexes.length)

  if (winningThreeIndexes.length === 1) {winningThreeIndexes[0].map((index) => {arrayfromBoxes[index].className += ' winner'})}
 
   var isThereAWinner = 
    winningTrios.some(trio => {return trio.every(i => indexOfSelected.includes(i))});
       console.log({isThereAWinner});
   return isThereAWinner
      }

function declareWinner() {
  setTimeout(alert (checkClass() + " WINS"),1000);
  for (let i=0; i < stylingOfBoxes.length; i++) {
    stylingOfBoxes[i].removeEventListener('click',{once: true});}
}

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>Tic Tac Toe</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
        <h1 id="playtext">Let's Play</h1>

    <div class="radioContainer">
        <div id="playerOne">
        <h3>Player One</h3>
        <form>
            <input type="radio" name="choice" value="X"> X<br>
            <input type="radio" name="choice" value="O"> O<br>
            <input type="button" id="PlayerOneSymbol" value="Confirm">
        </form>
        </div>

        <div id="playerTwo">
        <h3>Player Two</h3>
        <form>
            <input type="radio" name="choice2" value="Human"> Human<br>
            <input type="radio" name="choice2" value="Dumb AI"> Dumb AI<br>
            <input type="radio" name="choice2" value="Smart AI"> Smart AI<br>
            <input type="button" id="PlayerTwoChoice" value="Confirm">
        </form>
        </div>
    </div>

    <div class="buttonHolder">
        <div class="buttonWrapper">
    <button id="restartBtn">Start New Game</button>
        </div>
    </div>

    <div class="gameboard">
        <div class="box" ></div>
        <div class="box" ></div>
        <div class="box" ></div>
        <div class="box" ></div>
        <div class="box" ></div>
        <div class="box" ></div>
        <div class="box" ></div>
        <div class="box" ></div>
        <div class="box" ></div>
    </div>
</div>
    <script src="script.js"></script>
</body>
</html> 

style.css:

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  display: flex;
  justify-content: center;
}

#playtext {
  text-align: center;
  padding: 10px;
}

.buttonHolder {
  height: 60px;
  width: 100%;
  float: left;
  position: relative;
  background-color: purple;
}

.buttonWrapper {
position: absolute;
top: 50%;
left: 50%; 
-ms-transform: translate(-50%,-50%);
transform: translate(-50%,-50%);
}

.container {
  background-color: purple;
  justify-content: center;
  /* display: flex;
  flex-wrap: wrap; */
  width: 400px;
  height: 600px;
}

#gameboard {
border-top:10px;
border-bottom: 4px;
border-bottom-color: black;
background-color: chartreuse;
}

.box {
  background-color: yellow;
  width: 125px;
  height: 125px;
  float: left;
  width: 33.33%;
}

button:hover {
  cursor: pointer;
  transform: translateY(-2px);
}


.winner {
  background-color: black;
}

.X {
  content: 'X';
  font-size: 135px;

}

.O {
  content: 'O';
  font-size: 135px;
}

#spacer {
height: 10px;
width: 100%;
background-color: purple;
padding: 10px;
}

#playerOne {
background-color: blanchedalmond;
padding: 5px;
height: 110px;
float: left;
width: 50%;
}

#playerTwo {
background-color: mintcream;
padding: 5px;
height: 110px;
float: left;
width: 50%;
}

解决方法

一位朋友帮我弄清楚了#1 中发生的事情——我想。他指出 JS 是异步的。我有三个功能:

  1. 对手在空格中放置标记。
  2. 评估棋盘以查看对手是否获胜。
  3. 如果没有,它会切换回合并让玩家选择一个空间。
  • 如果是,则结束游戏并阻止选择空格

我希望 (1) 延迟时,(2) 和 (3) 不会触发,直到 (1) 触发。

但实际上 (1) 被延迟了,所以 (2) 无论如何都会跑,并没有看到对手获胜,所以 (3) 让玩家选择一个空间。

所以为了解决这个问题,我在所有 3 个函数上都设置了超时时间:

  setTimeout(() => {
        let dumbAIpicked = dumbAIArray[Math.floor(dumbAIArray.length * (Math.random()))]
        arrayfromBoxes[dumbAIpicked].classList.add(TWO_CLASS)
        arrayfromBoxes[dumbAIpicked].innerHTML = TWO_CLASS

        if (playerhasWon()) {
        declareWinner()
        return
        } 
        if (emptySpaceRemains() == false) {
        declareTie()
        return
        }
        // hasGameEnded()
        swapTurns()
``},500);

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res