圈圈叉叉

來自 LIOJ 上的題目。這題在考二維陣列的應用,覺得還真的蠻容易搞混的,所以想記錄下來。

解題方向

最簡單的方式就是窮舉所有會贏的可能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
O
O
O
-------
O
O
O
-------
O
O
O
-------
O
O
O
-------
O
O
O

關於二維陣列

由於拿到的資料會是 ['ooo', 'xxo', 'xxo'],所以如果要取出每一行的字串的話:

1
2
3
'ooo' // lines[0]
'xxo' // lines[1]
'xxo' // lines[2]

如果要取出每行的一個字元的話:

1
2
3
4
5
6
7
8
9
10
11
12
ooo
'o' // lines[0][0]
'o' // lines[0][1]
'o' // lines[0][2]
xxo
'x' // lines[1][0]
'x' // lines[1][1]
'o' // lines[1][2]
xxo
'x' // lines[2][0]
'x' // lines[2][1]
'o' // lines[2][2]

(上下一起對照著看,比較不會搞混)

如果現在我們想要看「橫排」的每一個字元有沒有相同?會發現可以利用迴圈來做:

1
2
3
4
5
for(let i=0; i<3; i++) {
if(lines[i][0] === lines[i][1] && lines[i][1] === lines[i][2]) {
return lines[i][0]
}
}

每一行要檢查的字元都固定為 [0][1][2],需要改變的只有前面代表「行數」的索引值。

反過來,如果要看「直排」的每一個字元有沒有相同?也可以用迴圈來做:

1
2
3
4
5
6
7
8
9
10
11
'o' // lines[0][0]
'x' // lines[1][0]
'x' // lines[2][0]

'o' // lines[0][1]
'x' // lines[1][1]
'x' // lines[2][1]

'o' // lines[0][2]
'o' // lines[1][2]
'o' // lines[2][2]
1
2
3
4
5
for(let i=0; i<3; i++) {
if(lines[0][i] === lines[1][i] && lines[1][i] === lines[2][i]) {
return lines[0][i]
}
}

每一個字元要檢查的固定行數為 [0][1][2],需要改變的只有後面代表「字元」的索引值。

所以這樣就處理完「橫排」跟「直排」的部分了,接下來只要把「斜排」的部分也做完就搞定:

1
2
3
4
5
6
7
'o' // lines[0][0]
'x' // lines[1][1]
'o' // lines[2][2]

'o' // lines[0][2]
'x' // lines[1][1]
'x' // lines[2][0]

這裡沒有辦法寫成迴圈,所以直接判斷就好:

1
2
3
4
5
6
if(lines[0][0] === lines[1][1] && lines[1][1] === lines[2][2]) {
return lines[0][0]
}
if(lines[0][2] === lines[1][1] && lines[1][1] === lines[2][0]) {
return lines[0][2]
}

工具都備好了,最後只要集合起來就完成囉:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function whoWin(lines) {
// 橫排
for(let i=0; i<3; i++) {
if(lines[i][0] === lines[i][1] && lines[i][1] === lines[i][2]) {
return lines[i][0]
}
}
// 直排
for(let i=0; i<3; i++) {
if(lines[0][i] === lines[1][i] && lines[1][i] === lines[2][i]) {
return lines[0][i]
}
}
// 斜排
if(lines[0][0] === lines[1][1] && lines[1][1] === lines[2][2]) {
return lines[0][0]
}
if(lines[0][2] === lines[1][1] && lines[1][1] === lines[2][0]) {
return lines[0][2]
}
// 以上都沒有通過,代表平手
return 'DRAW'
}

另一種選擇

如果二維陣列不好理解的話,你也可以把資料轉換成一行字串,例如說 'oooxxoxxo',接著在照著上面的做法也是 ok。

先用數字表示位置:

1
2
3
4
5
6
7
o o o
x x o
x x o

0 1 2
3 4 5
6 7 8

橫排的情況:

1
2
3
0 1 2
3 4 5
6 7 8
1
2
3
4
5
6
7
8
9
10
let str = 'oooxxoxxo'
for(let i=0; i<3; i++) {
// i=0 => n=0
// i=1 => n=3
// i=2 => n=6
let n = i*3
if(str[n] === str[n+1] && str[n+1] === str[n+2]) {
return str[n]
}
}

直排的情況:

1
2
3
0 3 6
1 4 7
2 5 8
1
2
3
4
5
6
7
8
9
let str = 'oooxxoxxo'
for(let i=0; i<3; i++) {
// i=0 => 0 3 6
// i=1 => 1 4 7
// i=2 => 2 5 8
if(str[i] === str[i+3] && str[i+3] === str[i+6]) {
return str[i]
}
}

斜排的情況:

1
2
0 4 8
2 4 6
1
2
3
let str = 'oooxxoxxo'
if(str[0] === str[4] && str[4] === str[8]) return str[0]
if(str[2] === str[4] && str[4] === str[6]) return str[2]

最後一樣組合起來就大功告成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function whoWin(str) {
// 橫排
for(let i=0; i<3; i++) {
// i=0 => n=0
// i=1 => n=3
// i=2 => n=6
let n = i*3
if(str[n] === str[n+1] && str[n+1] === str[n+2]) {
return str[n]
}
}
// 直排
for(let i=0; i<3; i++) {
// i=0 => 0 3 6
// i=1 => 1 4 7
// i=2 => 2 5 8
if(str[i] === str[i+3] && str[i+3] === str[i+6]) {
return str[i]
}
}
// 斜排
if(str[0] === str[4] && str[4] === str[8]) return str[0]
if(str[2] === str[4] && str[4] === str[6]) return str[2]

// 平手
return 'DRAW'
}

mentor-program-day18 凱薩加密
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×