俄羅斯方塊謎題 | JS地下城 - 番外篇 - 001
題目如下。
Challenge
實作俄羅斯方塊的計分系統
背景
俄羅斯方塊是一款益智遊戲,
最初是由蘇聯俄羅斯軟件工程師 Alexey Pajitnov 設計的。關於計分制度
計分公式是基於
當玩家一次清除越多條線,所獲得的分數就會越多
的想法下去設計的。
例如,消去一行得 40 分
,消去四行得 1200 分
。且還搭配了一個
分數會隨等級倍增
的規則。
遊戲會從等級 0 開始
。
當玩家每清除 10 行,等級就會上升
。
值得注意的是,等級上升之後,消除的總行數是不會重置的。
關於這個題目,您可以參考此表:
Level 消去 1 行 消去 2 行 消去 3 行 消去 4 行 0 40 100 300 1200 1 80 200 600 2400 2 120 300 900 3600 3 160 400 1200 4800 … 7 320 800 2400 9600 … 你必須透過這張表格得出的公式來以此類推到 level N
任務
用 Nintendo 的原始計分系統來計算俄羅斯方塊的分數
type Line = 0 | 1 | 2 | 3 | 4; type getScore = (list: Line[]) => number;
Input
範例:
[4, 2, 2, 3, 3, 4, 2]
隨機長度的 array 且裡面只包含數字0
到4
Output
計算的最終分數。
Example
1 | getScore([4, 2, 2, 3, 3, 4, 2]); // returns 4900 |
- 消去 4 行 +1200 (當前等級
0
)。分數:0 + 1200 = 1200
- 消去 2 行 +100。分數:
1200 + 100 = 1300
- 消去 2 行 +100。分數:
1300 + 100 = 1400
- 消去 3 行 +300(當前等級仍為
0
)。分數:1400 + 300 = 1700
消除的總行數11
=(4 + 2 + 2 + 3)
,因此等級上升到1
(每消除10
行上升一次)- 消去 3 行 +600 (當前等級
1
)。分數:1700 + 600 = 2300
- 消去 4 行 +2400。分數:
2300 + 2400 = 4700
- 消去 2 行 +200。分數:
4700 + 200 = 4900
Answer
1 | function getScore(list) { |
看完題目的時候想說感覺蠻簡單的,實作上感覺有些邏輯有點不熟悉,還是花了點時間想了一下。
## 馬上開始
觀察分數如何得到
觀察一下行數&等級的表格,第 0 級消除 1~4 行後得到的分數是基礎值,接下來依照級數,每一級的分數會是 ( 消除 x 行的基礎分數 _ (級數+1)_ 2)
所以這邊得到幾個小結論- 消除第 0 級的 1~4 行分數 => [40, 100, 300, 1200]
- 計算分數的公式會是 ( 消除 x 行的基礎分數 _ (級數+1)_ 2)
再來先假設只有傳入一個數字吧,會比較好思考。
1
2
3
4
5
6
7
8
9
10
11
12
13// 只消掉一行
let lines = 1;
function getScore(lines) {
//消除行數
let line = 0;
//基礎分數
let basic = [40, 100, 300, 1200];
//級數
let level = 0;
// 公式
return basic[lines - 1] * (level + 1) * 2;
}
console.log(getScore(lines));應該不難。
傳入多個參數要怎麼進行?
從結果來看,因為要計算總合,這邊就直接聯想到reduce()
,還有一些需要特別注意的細節。- 消除分數會隨著等級提升而提高,但是以新數值傳入前的等級計算
- 每一輪等級計算是以還沒加上傳入行數的等級為基礎
1
2
3
4
5
6
7
8
9
10
11
12
13
14function getScore(list) {
let score_basic = [40, 100, 300, 1200];
let level_times = 2;
let level = 0;
let line = 0;
return list.reduce((acc, value) => {
//以累積的行數(line)計算目前等級
level = Math.floor(line / 10);
//計算等級後,讓累績行數加上新增的消除行數 (為下一圈做準備)
line += value;
return acc + score_basic[value - 1] * (level + 1);
}, 0);
}
getScore([4, 2, 2, 3, 3, 4, 2]); // 4900小小檢討一下
後來看了一下其他前輩的算法之後發現,在計算等級的地方,我想得有點複雜level = Math.floor(line/10)
這一段其實可以改成level = (line- line%10)/10
就不需要用到 Math 了。
後記
後來看到丟出這段題目的前輩的解法,沒看過 Functional Programming,直接被嚇到 XDD,程式碼如下:
1 | // J3小 XDD |
慌張的我馬上去查了一下 FP 在幹嘛,學習清單又多一項可以學了 (擦汗..
PS. 直接跳過傳入資料的驗證 XD
本文章若有任何資訊誤植或侵權,煩請告知,我會立刻處理。