# JavaScript - Tic-Tac-Toe Game * 完成範例:[CodePen](https://codepen.io/liu_0821/pen/XWOKevO)、[GitHub](https://github.com/liu-huangling/JSPractice)、[Medium](https://medium.com/@LindaLiu0821/javascript%E5%9C%B0%E4%B8%8B%E5%9F%8E08-tic-tac-toe-game-1c254a34978b) ![IMG_0776.jpeg](https://hackmd.io/_uploads/Hyy-U3K7a.jpg) > 8F - 圈圈叉叉遊戲 ### 使用語法 * HTML、CSS(SCSS)、JS(原生) ### 攻略要點 1. 【特定技術】先手為 O,後手為 X,某方獲勝時,上方會紀錄各方的獲勝戰績 2. 【特定技術】每回合結束後,會判定結果頁(平手、O 獲勝、X 獲勝) 3. 【特定技術】需符合 RWD,能在低螢幕解析度也能遊玩,介面不能超出 x 軸,至少在以下解析度能夠遊玩。 * iPhone SE 320px * iPhone 8 375px * iPhone PLUS 414px 4. 【特定技術】請使用瀏覽器離線儲存技術,將戰績保留起來,重新打開遊戲也仍可觀看到歷史戰績。 * localStorage 5. 【書寫能力】請寫 BLOG,描述你在開發「滿足獲勝條件」解題思維來進行加強描述 * 上面三個 O 符合獲勝條件 * 斜線三個 X 符合獲勝條件 ### 拆解步驟 * **HTML** 1. 挑戰主要都是在同個頁面完成,所以主要架構可以分成下面這張圖。 ![IMG_0783.jpeg](https://hackmd.io/_uploads/Bk677M97T.jpg) * **CSS(SCSS)** 1. 這次比較特別是使用`SCSS`撰寫響應式網頁設定(RWD)與大量的使用偽元素。 2. 以下我會簡單說明一下用`原生CSS`與`SCSS`撰寫的區別。 * <font color=blue>原生CSS</font>撰寫RWD ``` .box{ width: 450px; height: 450px; } //iphone plus @media all and (max-width: 414px) { .box{ width: 400px; height:400px; } } ``` * <font color=blue>SCSS</font>撰寫RWD ``` @mixin iphone-plus(){ @media all and (max-width: 414px) { @content; } } .box{ width: 450px; height: 450px; @include phone-plus() { width: 400px; height: 400px; } } ``` * 兩者的區別在於==前者==會統一集中在<font color=cake>`@media`</font>內進行樣式調整,==後者==則可以先把格式範圍設定好,再使用<font color=cake>`@include`</font>導入,可針對小範圍做調整。 * 至於哪個好用一樣看個人或是看專案大小決定想要使用的方式~😚 * **JS** ## 說明一下解題思路 1. 判斷點選`div`要新增<font color=blue>o</font>或<font color=red>x</font>與重複點選不作為 2. 判斷遊戲輸贏狀態 3. 分數加總與紀錄於`localStorage` 4. 重新開始 ## 判斷點選`div`要新增<font color=blue>o</font>或<font color=red>x</font>與重複點選不作為 1. 迴圈計算點選的元素是否為`div.playDiv` 2. 設定變數`circleStatus`判斷是要新增<font color=blue>`o`</font>或<font color=red>`x`</font> ``` if(e.target.className.includes("playDiv") && e.target.children.length == 0){ ... } ``` 3. 判斷點選的`div`中是否包含子元素去決定是否可以新增 * 使用`Element.children`語法 4. 建立元素並新增至被點選的`div`中 * 使用`document.createElement`語法,創立該元素 * 使用`appendChild`語法,將新建立的元素新增至父元素 ## 判斷遊戲輸贏狀態 1. 紀錄已經被點選的`div`元素有哪些,並記錄至陣列 ``` for(var i = 0; i < playGroup.length;i++){ arrayStatus.push(playGroup[i].dataset.status); } ``` 2. 建立獲勝條件 ![S__10330175](https://hackmd.io/_uploads/rJRdC-JVa.jpg) > 九宮格示意圖 3. 獲勝條件為:"012","345","678","036","147","258","048","246" 4. 迴圈跑獲勝條件對應紀錄已被點選的陣列 * 使用`array.forEach` 語法,對每數組的每個元素執行給定的值。 ``` // 用這三個數字帶入判斷式,判斷是否有成立獲勝條件 arrayStatus[winNum[0]] && arrayStatus[winNum[1]] && arrayStatus[winNum[2]] ``` 5. 當值==`0`,則<font color=cake>圈圈獲勝</font>;當值==`1`,則<font color=cake>叉叉獲勝</font>;若紀錄已被點選的陣列無包含`undefined`,則為<font color=cake>平手</font> ## 分數加總與紀錄於`localStorage` 1. 判斷是否有`localStorage`的紀錄值;無,建立圈圈與叉叉的`localStorage`,有,進入`switch`判斷 2. 判斷`function`傳入值為`cross` or `circle`,判斷為何方獲勝,則加一分 ## 重新開始 1. 該關的關,該顯示的顯示(? 2. 迴圈清除遊戲`div`內所有子元素 * 使用`Element.childNodes`語法,尋找所有子元素 * 使用`remove()`語法,移除該元素 ### 結尾 * 以目前做到現在來看我覺得進步蠻多的,整體邏輯逐漸可以不用參考其他人就可以寫出來(當然也或許是這次的題目會比較簡單),但就覺得小小有成就感ฅ^•ﻌ•^ฅ。 --- ##### ヽ(∀゚ )人(゚∀)人( ゚∀)人(∀゚ )人(゚∀)人( ゚∀)ノヽ(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人(゚∀゚)人( ゚∀)人(∀゚ )人( ゚∀)人 ##### 以上 如果哪裡有錯誤或有問題,歡迎提出來一起討論~~~~