- 原文地址:I Built Tic Tac Toe With JavaScript
- 原文做者:MITCHUM
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:lgh757079506
- 校對者:portandbridge,TokenJan
在我上一篇文章中,我向你們展現了匹配類遊戲,文中介紹到我是使用 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
讓咱們從 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
第一個 link 標籤包含對tic-tac-toe.css文件的引用。這個文件可讓咱們爲 HTML 文檔添加顏色和定位等樣式。若是沒有此文件,咱們的遊戲將會顯得比較沉悶。web
這個是沒有任何樣式下的咱們頁面的樣子。
接下來咱們展現 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 名,它們在遊戲邏輯和樣式方面起了不小的做用。咱們來看下樣式部分是如何編寫的。
我會分幾部分講解tic-tac-toe.css文件的內容,由於我以爲這樣會使讀者更容易理解。
第一部分(包含的代碼)負責爲 body, main 和 h1 標籤設置樣式。body 標籤上使用 RGB 值設置頁面背景爲淺藍色。
main 標籤上設置 max-width, padding 和 margin 屬性將遊戲界面居中於屏幕。這個精美而簡潔的樣式風格是我從這篇博文中借鑑的。
h1 標籤包含着大寫的標題「Tic Tac Toe」,而後咱們將其設置爲黃色字體並居中。
代碼以下:
接下來咱們將討論 message 框,難度下拉列表和整行控制區的樣式.
咱們將文本消息框居中並設置字體顏色爲黃色。而後咱們設置邊框並使用圓角。
咱們設置難度下拉列表的大小,而且設置了圓角,還設置了字體大小,顏色和位置信息。
咱們對控制欄惟一須要調整的是確保其中全部元素都爲居中狀態。
代碼以下:
接下來要處理井字格的樣式了。咱們須要設置每一個格子的大小,顏色和文本位置。更重要的是,咱們須要在適當的位置顯示邊框。咱們添加了幾個 class 來標識遊戲面板上的格子的位置,來實現著名的井字棋遊戲。 咱們還改變了邊框的大小讓它更有三維空間的感受。
最後咱們來看下按鈕的樣式。我必須認可,我從w3schools借用部分樣式。可是,我確實進行了修改以適應咱們的配色方案。
好啦,這就是 CSS 部分!如今咱們終於能夠進入有趣的部分:JavaScript。
正如所料,JavaScript 代碼是 tic tac toe 遊戲中最複雜的部分。我將描述基本結構和人工智能部分,但我不是去介紹每個功能。相反,我將把它做爲練習讓你閱讀代碼並理解每一個函數是如何實現的。方便起見,這些函數已經被「加粗」。
若是代碼中的某些部分讓你困惑,請留言,我會爲你詳細解釋!若是你能想出更好的實現方式,我也很樂意在評論中聽到你的反饋意見。目的是讓每一個人都學到更多,與此同時能夠收穫快樂。
咱們須要作的第一件事就是初始化一些變量。咱們有幾個變量用於存儲遊戲狀態:一個用於表示遊戲是否結束,另外一個則表示遊戲的難度級別。
咱們還有一些變量用於存儲一些有用的信息:格子用數組存儲,格子數量和勝利條件。咱們的遊戲面板是有一系列數字表明,還有八種可能的勝利條件。所以,勝利條件由一個包含八個數組的二維數組表示,每一個數組對應一個可能獲勝的三個格子組合。
代碼以下:
考慮到這點,讓咱們看下這個程序是如何運做的。這個遊戲是事件驅動型。你點擊的某些區域,代碼都會做出響應,而後在屏幕上看到效果。當你點擊「Play Again」按鈕,遊戲面板將會重置而且你能夠進行下一輪的 tic tac toe 遊戲。當你改變難度級別時,遊戲會根據你的不一樣操做做出相應操做。
固然最重要事情的仍是當玩家點擊某個格子時的反饋。有許多須要檢查的地方。這個邏輯大部分在名爲chooseSquare的頂級函數中。
代碼以下:
讓咱們一塊兒通讀代碼。
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 函數
AI 實現細節
你理解算法的話,請在評論中告訴咱們能夠作出哪些優化將咱們的遊戲變的更加智能!
(adsbygoogle = window.adsbygoogle || []).push({});
這篇文章中我展現了使用 Javascript 實現的 Tic Tac Toe 遊戲。而後咱們瞭解了它是如何實現的以及人工智能是如何工做的。讓我知道你的想法吧,以及你但願我在將來作一些怎樣的遊戲。我只是一我的,能力有限,作不出使命召喚那樣的遊戲大做。
若是你想進一步瞭解如何用 Javascript 編寫更好的程序,我推薦一本由大神 Douglas Crockford 編寫的 JavaScript: The Good Parts 書。隨時間發展這門語言有顯著改善,但因爲其發展歷史,它仍然具備一些奇怪的特性。這本書很好地幫你瞭解更多有質疑空間的設計選擇。我在學習 JavaScript 的過程當中發現它對個人幫助很大。
若是你想購買它,並會瀏覽上面的連接,我將不勝感激。我將經過亞馬遜的聯盟計劃得到佣金,對你無需額外費用。這樣能夠支持我繼續運營本站。
感謝閱讀,下期見!
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。