Vue — 實作井字遊戲
原來我也寫得出來ooxx
coding 的過程,思考流程對我來說是最基礎也最重要的步驟,先列出所有應該要實作出的步驟。
Todo Steps --
- 劃出九宮格
- 設定兩個玩家:O 與 X,一方點擊完必須要換手,
點過的格子不能重複點擊 - 勝負結果出現後,剩下的空白格不能點擊
- 重置鍵可以隨時重新開始遊戲
- 審視程式碼,如果有更好的寫法就再調整
STEP 1
在 HTML 中,用 v-for 去跑迴圈,劃出九個格子,樣式屬 css 部分,就不加詳述。
STEP 2
Data 裡,設定 grids 陣列為九宮格,預設值皆為 0,player 為玩家,預設為 1 ( 畫面呈現就是代表 O 玩家 ),當點擊其中一個格子,玩家要轉換,值變成 -1 ( 代表 X 玩家)。
上方敘述得知可以設計兩個 function, setGrid 與 setSymbol
- setGrid( ){ }:寫入點擊方格時,被點擊的方格狀態要改變
- setSymbol( ){ }:寫入畫面,由數值 0, 1, -1,轉換為 空白, O, X
補充:在 Vue 裡,不能直接指定陣列的值,如以下寫法:
this.grids[index] = 1;
要用 this.$set(array, index, value) function 的方式寫入:
this.$set(this.grids, index, this.player);
STEP 3
這個步驟是這個遊戲裡最難的部分,要寫出判定輸贏的 function, , 首先我們要先新增一個二維陣列,裡面總共有八個組合,只有符合其中一個組合遊戲就結束,八個組合分別是橫排三條線,直排三條線,對角兩條線。
組合裡的數字為九宮格相對應的 index。
const winLineSets = [
[0, 1, 2], [3, 4, 5], [6, 7, 8],
[0, 3, 6], [1, 4, 7], [2, 5, 8],
[0, 4, 8], [2, 4, 6]
]
接著要設計 getWinner( ){ } function,
- 基礎寫法:for 迴圈
- 進階寫法:reduce
先求有再求好,功能先寫出來再去鑽研更好的方法,
for 迴圈
winLine 是所有贏的組合,再用 ES6 語法解構,a, b, c 分別代表贏的組合的index, 帶入 grids, 只要完成總分是 3 分,就是 O 玩家贏,反之,如果總分是 -3,就是 X 玩家贏,只要是其他分數就沒有贏家,回傳 0 。
getWinner () {
for (let i = 0; i < 8; i++) {
let winLine = winLineSets[i];
let [a, b, c] = winLine;
let sum = this.grids[a] + this.grids[b] + this.grids[c];
if (sum === 3) return 1;
if (sum === -3) return -1;
}
return 0;
},
reduce
將一個累加器及陣列中每項元素(由左至右)傳入回呼函式,將陣列化為單一值。(from MDN)
accumalator 參數是累計器,在 reduce 裡可以當成一個變數,將初始值與帶入的值累計暫存,初使值為非必填,沒有初始值就會直接以 arr 第一個進入的值開始,callback 參數中前兩個為必填,後兩個參數選填,類似 forEach 會把陣列每個元素帶入。
arr.reduce(callback[accumulator, currentValue, currentIndex, array], initialValue)
此範例中的寫法:
STEP 4
reset 功能比較好能理解,建立一個按鈕,點擊後 grids 陣列通通歸 0,玩家回復初始值 1,贏家也回復初始值 0。
reset () {
this.grids = [0, 0, 0, 0, 0, 0, 0, 0, 0];
this.player = 1;
}
STEP 5
winner 的值其實可以直接從 grids 的變化得知,所以我們可以把 getWinner 這個 function 從 methods 裡面取出,改放到 computed 裡,命名直接叫 winner (),data 裡也不需要另外宣告 winner 這個資料。
畫面呈現:
參考資料:
reduce 釋義