昨天完成了 row 方向和 column 方向的勝負判斷,今天我們要來完成右斜和左斜方向的勝負判斷,我這邊先把這兩個方向命名為 forwardSlash( / ), backSlash( \ )。
首先我們要來分析一下左斜的勝負判斷該怎麼做,下面我畫了輔助線來幫助我們看圖。
參考 Day08 的做法,如果我們也可以產生出一個結構為 arrs 的 array of array,我們就可以用同樣的函數來順利的完成勝負判斷。
再次說明一下,這個函數有三個輸入
const result = getWinCase(blocks, arrs, winnerCondition);
透過這個函數,我們希望能夠得到這樣的結構的物件。這個結構的物件可以幫助我們知道目前是否已經產生贏家?若有,誰是贏家?以及這個贏家他連成幾條線?這條線是哪幾個格子連成線的?
// 這是圈圈贏,連成一條線的範例結果
const result = {
1: [ [0, 1, 2] ],
-1: []
};
// 這是圈圈贏,連成兩條線的範例結果
const result = {
1: [ [0, 1, 2], [2, 4, 6] ],
-1: []
};
所以今天的重點會放在如何找出相對應方向的 arrs。
我們先來看一下左斜(forwardSlash)是不是有一些等差等比,或其他的規則在裡面,所以先把狀況都列出來以便觀察。
考慮 3x3 的情況,下面是我們所期待得到的 arrs
arrs = [
[0],
[1, 3],
[2, 4, 6],
[5, 7],
[8],
]
考慮 4x4 的情況,下面是我們所期待得到的 arrs
arrs = [
[0],
[1, 4],
[2, 5, 8],
[3, 6, 9, 12],
[7, 10, 13],
[11, 14],
[15],
]
如果找不到規律,可以多列幾個出來觀察。
下面畫了輔助線的圖片是我找到的線索
多列幾個之後,我跟大家分享我觀察到的現象,以及我接下來的做法。
不管是幾乘幾的棋盤,我覺得 arrs 都可以拆開來看成兩個部分,拆解的部分,可以依據我上面的圖來劃分。
以 3x3 棋盤為例,我覺得 arrs 可以拆成下面這兩部分:
// arrs-1
[
[0],
[1, 3],
[2, 4, 6],
]
// arrs-2
[
[5, 7],
[8],
]
以 4x4 的棋盤為例,也可以依此類推:
// arrs-1
[
[0],
[1, 4],
[2, 5, 8],
[3, 6, 9, 12],
]
// arrs-2
[
[7, 10, 13],
[11, 14],
[15],
]
如果這樣拆開來看的話,我們可以發現 arrs 中每一個小 ar r的第一個數字
,彼此是等差關係
,而且單看一個 arr 的話,數字之間也是等差關係
。
所以根據這樣的關係,我可以分別計算出 arr-1
和 arr-2
後,做合併,就可以得到我們的目標 arrs 了。
所以 forwardSlash 的 arrs ,我的計算方法如下:
// ex: 得到 [0, 1, 2]
const firstHeaders = _.range(0, gameScale);
// ex: 得到 [5, 8]
const secondHeaders = _.range(gameScale * 2 - 1, gameScale * gameScale, gameScale);
// 得到 arrs-1
const firstArr = firstHeaders.map((header, index) => (
_.range(header, index * gameScale + 1, gameScale - 1)
));
// 得到 arrs-2
const secondArr = secondHeaders.map((header, index) => (
_.range(header, header + (secondHeaders.length - index) * (gameScale - 1), gameScale - 1)
));
// 合併 arrs-1 及 arrs-2
const arrs = [...firstArr, ...secondArr];
根據同樣的方法, backSlash 的 arrs 也可以迎刃而解
同樣的,考慮 3x3 的情況,下面是我們所期待得到的 arrs
arrs = [
[2],
[1, 5],
[0, 4, 8],
[3, 7],
[6],
]
考慮 4x4 的情況,下面是我們所期待得到的 arrs
arrs = [
[3],
[2, 7],
[1, 6, 11],
[0, 5, 10, 15],
[4, 9, 14],
[8, 13],
[12],
]
我們一樣把 3x3 的 arrs 拆成兩部份
// arr-1
[
[2],
[1, 5],
[0, 4, 8],
]
// 以及 arr-2
[
[3, 7],
[6],
]
拆開之後,也能夠發現 arrs 中每一個小 arr 的第一個數字,彼此是等差關係
,而且單看一個 arr 的話,數字之間也是等差關係
。
同樣的伎倆,我們又破解了 backSlash 的 arrs 了!
勝負判斷方法的最後,我們要把所有方向的 arrs 合併
tic-tac-toe/src/containers/TicTacToe/utils.js
這邊我的勝負判斷方法的函數名稱是 getWinner()
,如下:
const isWin = getWinner(blocks, gameScale, winnerCondition);
我希望這個函數有有三個輸入和一個輸出,三個輸入是我們熟悉的參數,是為了計算出各個方向(ex: row, column, forwardSlash, backSlash)的arrs所需要的,輸出是一個命名為 isWin
的物件,這邊來說明一下這個物件。
isWin:
isWin = { winner: ‘’, winCaseArr: [], isGameFinished: false }
透過 isWin 這個物件,我們可以來判斷勝負
tic-tac-toe/src/containers/TicTacToe/components/InfoBoard/index.js
有了 isWin 物件之後,我們可以在 <InfoBoard />
裡面顯示出勝負的狀態,也可以標示連成一條線的棋子,以下是加入 isWin 參數之後的成果展示: