用 JavaScript 实现一个井字棋游戏

用 JavaScript 实现一个井字棋游戏

在我上一篇文章中,我向你们展现了匹配类游戏,文中介绍到我是使用 JavaScript 实现并简单谈了一下前端 web 技术。 我获得了很好的反馈,因此在本周的文章中我决定讲解一个由 Javascript 实现的游戏井字棋并详细介绍其实现方案。在本项目中,我还尝试挑战不使用任何外部 Javascript 依赖库去实现它.javascript

点这里 去玩下井字棋游戏吧!css

这里有两个难度等级:小白(moron)和天才(genius)。挑战成功 moron 的话,试下可否挑战成功 genius 级别。genius 要比 moron 更难对付,不过 genius 采起的玩法有点轻敌,并不是真的那么精明。正在读文章的朋友,我保证你能凭借你的智慧发现能赢得游戏的奥秘。html

实现过程

井字棋游戏使用了三个基本的前端技术:HTML、CSS 和 JavaScript。我会向你逐个介绍实现源码并讲解它们各自的做用。如下是这三个文件:前端

tic-tac-toe.htmljava

tic-tac-toe.cssandroid

tic-tac-toe.jsios

HTML

HTML 的头部

让咱们从 head 标签开始。这个标签位于每一个 HTML 文档开头。这里将存放一些影响页面总体的元素标签。git

<head>
    <title>Tic Tac Toe</title>
    <link rel="stylesheet" href="tic-tac-toe.css">
    <link rel="shortcut icon" href="https://mitchum.blog/wp-content/uploads/2019/05/favicon.png" />
</head>        
复制代码

head 标签中包含了三个子标签:一个 title 标签和两个 link 标签。浏览器中的选项卡处会展现 title 标签中的内容。本例中为“Tic Tac Toe”。第二个 link 标签设定了咱们想展现在选项卡中的图标的连接。他们组合起来将是下面的样子:github

Browser tab for javascript Tic Tac Toe game

第一个 link 标签包含对tic-tac-toe.css文件的引用。这个文件可让咱们为 HTML 文档添加颜色和定位等样式。若是没有此文件,咱们的游戏将会显得比较沉闷。web

Tic Tac Toe game without css applied

这个是没有任何样式下的咱们页面的样子。

接下来咱们展现 HTML 文档主体。咱们将其拆分为两部分:游戏界面和控制栏。咱们先从游戏界面开始。

游戏界面

咱们将使用 table 标签来布局井字棋游戏界面。代码以下:

<table class="board">
<tr>
  <td>
      <div id="0" class="square left top"></div>
  </td>
  <td>
      <div id="1" class="square top v-middle"></div>
  </td>
  <td>
      <div id="2" class="square right top"></div>
  </td>
</tr>
<tr>
  <td>
      <div id="3" class="square left h-middle"></div>
  </td>
  <td>
      <div id="4" class="square v-middle h-middle"></div>
  </td>
  <td>
      <div id="5" class="square right h-middle"></div>
  </td>
</tr>
<tr>
  <td>
      <div id="6" class="square left bottom"></div>
  </td>
  <td>
      <div id="7" class="square bottom v-middle"></div>
  </td>
  <td>
      <div id="8" class="square right bottom"></div>
  </td>
</tr> 
</table>
复制代码

咱们为 table 标签添加“board”类,以便为其添加样式。该区域有三个 row 标签,每一个标签中包含三个用于存放数据的标签。这就组成了一个 3×3 游戏面板。咱们为其中每一个格子设置其 id 为数字而且设置一些表示其位置的 class 名。

控制栏

我所说的控制栏部分包含一个消息框,几个按钮和一个下拉列表。代码以下:

<br>
<div id="messageBox">Pick a square!</div>
<br>
<div class="controls">
 <button class="button" onclick="resetGame()">Play Again</button> 
 <form action="https://mitchum.blog/sneaky-subscribe" style="display: inline-block;">
    <button class="button" type="submit">Click Me!</button> 
 </form>
 <select id="difficulty">
   <option value="moron" selected >Moron</option>
   <option value="genius">Genius</option>
 </select>
</div>
复制代码

消息框位于两个换行符之间。第二个换行符后面是一个包含其他部分的 div 标签。play again 按钮有一个点击事件,能够在tic-tac-toe.js文件中调用 Javascript 函数。Click Me 按钮被包含在 form 标签中。最后,select 标签包含两个 options 标签:其内容为 moron 和 genius。moron 为默认选中状态。

每个 HTML 元素都被指定为各类类名和 id 名,它们在游戏逻辑和样式方面起了不小的做用。咱们来看下样式部分是如何编写的。

CSS

我会分几部分讲解tic-tac-toe.css文件的内容,由于我以为这样会使读者更容易理解。

基础元素

第一部分(包含的代码)负责为 body, main 和 h1 标签设置样式。body 标签上使用 RGB 值设置页面背景为浅蓝色。

main 标签上设置 max-width, padding 和 margin 属性将游戏界面居中于屏幕。这个精美而简洁的样式风格是我从这篇博文中借鉴的。

h1 标签包含着大写的标题“Tic Tac Toe”,而后咱们将其设置为黄色字体并居中。

代码以下:

CSS styling for the page

控制栏

接下来咱们将讨论 message 框,难度下拉列表和整行控制区的样式.

咱们将文本消息框居中并设置字体颜色为黄色。而后咱们设置边框并使用圆角。

咱们设置难度下拉列表的大小,而且设置了圆角,还设置了字体大小,颜色和位置信息。

咱们对控制栏惟一须要调整的是确保其中全部元素都为居中状态。

代码以下:

CSS styling for the controls

游戏面板

接下来要处理井字格的样式了。咱们须要设置每一个格子的大小,颜色和文本位置。更重要的是,咱们须要在适当的位置显示边框。咱们添加了几个 class 来标识游戏面板上的格子的位置,来实现著名的井字棋游戏。 咱们还改变了边框的大小让它更有三维空间的感受。

CSS styling for the tic tac toe board

按钮

最后咱们来看下按钮的样式。我必须认可,我从w3schools借用部分样式。可是,我确实进行了修改以适应咱们的配色方案。

CSS styling for the buttons

好啦,这就是 CSS 部分!如今咱们终于能够进入有趣的部分:JavaScript。

JavaScript

正如所料,JavaScript 代码是 tic tac toe 游戏中最复杂的部分。我将描述基本结构和人工智能部分,但我不是去介绍每个功能。相反,我将把它做为练习让你阅读代码并理解每一个函数是如何实现的。方便起见,这些函数已经被“加粗”。

若是代码中的某些部分让你困惑,请留言,我会为你详细解释!若是你能想出更好的实现方式,我也很乐意在评论中听到你的反馈意见。目的是让每一个人都学到更多,与此同时能够收获快乐。

基本结构

咱们须要作的第一件事就是初始化一些变量。咱们有几个变量用于存储游戏状态:一个用于表示游戏是否结束,另外一个则表示游戏的难度级别。

咱们还有一些变量用于存储一些有用的信息:格子用数组存储,格子数量和胜利条件。咱们的游戏面板是有一系列数字表明,还有八种可能的胜利条件。所以,胜利条件由一个包含八个数组的二维数组表示,每一个数组对应一个可能获胜的三个格子组合。

代码以下:

initialization javascript variables

考虑到这点,让咱们看下这个程序是如何运做的。这个游戏是事件驱动型。你点击的某些区域,代码都会做出响应,而后在屏幕上看到效果。当你点击“Play Again”按钮,游戏面板将会重置而且你能够进行下一轮的 tic tac toe 游戏。当你改变难度级别时,游戏会根据你的不一样操做做出相应操做。

固然最重要事情的仍是当玩家点击某个格子时的反馈。有许多须要检查的地方。这个逻辑大部分在名为chooseSquare的顶级函数中。

代码以下:

Javascript for choosing a tic tac toe square.

代码解读

让咱们一块儿通读代码。

176 行: 咱们须要作的第一件事就是将变量 difficulty 设置为下拉列表中选择的内容。这很重要,由于咱们的人工智能会根据此变量以肯定须要进行的操做。

177 行: 第二件事是检查游戏是否结束。若是没有咱们能够继续。不然,将会中止。

179 – 181 行: 第三,咱们将显示给玩家的消息默认设置为“Pick a square!”。咱们经过调用 setMessageBox 函数实现。而后咱们变量存储玩家选择的格子的 id 值和此 id 的dom节点。

182 行: 咱们经过调用 squareIsOpen 函数检查格子是不是开放状态。若是已经被标记,玩家就不能对方格进行操做。在相应的 else 代码块中咱们提示他。

184 - 185 行: 因为格子状态是开放的,咱们将标记设为“X”。而后咱们经过调用 checkForWinCondition 函数检查咱们是否胜利。若是咱们胜利了,咱们将返回一个包含获胜组合的数组。若是输掉游戏咱们返回 false。这是行得通的,由于 Javascript 不是强类型语言。

186 行: 若是玩家没有赢得比赛,那游戏继续,以便他的对手能够继续下一步操做。若是玩家确实赢了,那么相应的 else 代码块将经过把结束游戏变量变为 true,经过调用 highlightWinningSquares 函数将获胜格子变为绿色,并设置获胜消息。

188 – 189 行: 如今玩家的操做已完成,咱们须要计算机作出操做。名为 opponentMove 的函数会解决这个问题,稍后将详细讨论。如今咱们须要经过调用咱们在 185 行使用的那个函数来检查玩家是否输了,但此次以“O”做为参数。这就是复用!

190 行: 若是电脑输了,那么咱们必须继续,以便咱们能够检查是否平局。若是计算机获胜,那么相应的 else 代码块将经过将结束游戏变量设为 true 来处理它,经过调用 highlightWinningSquares 函数,设置失败信息,且将获胜方的格子设为红色。

192 – 197 行 咱们经过调用 checkForDraw 函数检查是否平局。若是没有获胜条件且没有更多可行的操做,那么咱们必须定为平局。若是已经为平局,那么咱们将游戏结束变量设为 true 并设置平局的消息。

这是游戏的主逻辑!函数剩余部分就是咱们已经介绍的相应 else 代码块中的逻辑。正如前面说的,请阅读其余函数以更全面的了解游戏的工做原理。

人工智能

有两个难度级别:moron 和 genius。moron 老是按照 id 的顺序取第一个可用的格子。为了保持这种有序的模式,他将牺牲一场胜利,即便是为了防止失败,他也不会偏离他。他很傻。

genius 会复杂得多。他会在那里获胜,他会尽力防止输掉游戏。后手会使他处于劣势,因此他更喜欢中心的格子保持其防守姿式。可是,他确实有能够利用的弱点。他遵循一套更好的规则,但并不擅长临机应变。当他找不到一个明显的操做步骤时会让他恢复到 moron 模式。

代码以下:

AI top level javascript function

顶级的 AI 函数

AI implementation details in javascript

AI 实现细节

你理解算法的话,请在评论中告诉咱们能够作出哪些优化将咱们的游戏变的更加智能!

(adsbygoogle = window.adsbygoogle || []).push({});

总结

这篇文章中我展现了使用 Javascript 实现的 Tic Tac Toe 游戏。而后咱们了解了它是如何实现的以及人工智能是如何工做的。让我知道你的想法吧,以及你但愿我在将来作一些怎样的游戏。我只是一我的,能力有限,作不出使命召唤那样的游戏大做。

若是你想进一步了解如何用 Javascript 编写更好的程序,我推荐一本由大神 Douglas Crockford 编写的 JavaScript: The Good Parts 书。随时间发展这门语言有显著改善,但因为其发展历史,它仍然具备一些奇怪的特性。这本书很好地帮你了解更多有质疑空间的设计选择。我在学习 JavaScript 的过程当中发现它对个人帮助很大。

若是你想购买它,并会浏览上面的连接,我将不胜感激。我将经过亚马逊的联盟计划得到佣金,对你无需额外费用。这样能够支持我继续运营本站。

感谢阅读,下期见!

若是发现译文存在错误或其余须要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可得到相应奖励积分。文章开头的 本文永久连接 即为本文在 GitHub 上的 MarkDown 连接。


掘金翻译计划 是一个翻译优质互联网技术文章的社区,文章来源为 掘金 上的英文分享文章。内容覆盖 AndroidiOS前端后端区块链产品设计人工智能等领域,想要查看更多优质译文请持续关注 掘金翻译计划官方微博知乎专栏

相关文章
相关标签/搜索