俄羅斯方塊謎題 | JS地下城 — 番外篇 001

Wen-Shiu Hsu | Kevin Hsu
5 min readNov 20, 2020

俄羅斯方塊謎題

今天在Line的社群上面,有位前輩釋出了公司內部的面試題,蠻有趣的就試做了一下,順便參考看看其他前輩都怎麼寫的,收穫良多R~
題目如下。

Challenge

實作俄羅斯方塊的計分系統

背景

俄羅斯方塊是一款益智遊戲,
最初是由蘇聯俄羅斯軟件工程師Alexey Pajitnov設計的。

關於計分制度

計分公式是基於 當玩家一次清除越多條線,所獲得的分數就會越多 的想法下去設計的。
例如,消去一行得 40 分消去四行得 1200 分

且還搭配了一個分數會隨等級倍增的規則。
遊戲會從等級 0 開始
玩家每清除 10 行,等級就會上升
值得注意的是,等級上升之後,消除的總行數是不會重置的。

關於這個題目,您可以參考此表:

Level消去 1 行消去 2 行消去 3 行消去 4 行0401003001200180200600240021203009003600316040012004800…732080024009600…

你必須透過這張表格得出的公式來以此類推到 level N

任務

用 Nintendo 的原始計分系統來計算俄羅斯方塊的分數

type Line = 0 | 1 | 2 | 3 | 4; type getScore = (list: Line[]) => number;

Input

範例:[4, 2, 2, 3, 3, 4, 2]
隨機長度的 array 且裡面只包含數字 04

Output

計算的最終分數。

Example

getScore([4, 2, 2, 3, 3, 4, 2]); // returns 4900

消去 4 行 +1200 (當前等級0)。分數:0 + 1200 = 1200

2. 消去 2 行 +100。分數:1200 + 100 = 1300

3. 消去 2 行 +100。分數:1300 + 100 = 1400

4. 消去 3 行 +300(當前等級仍為0)。分數:1400 + 300 = 1700
消除的總行數 11=(4 + 2 + 2 + 3),因此等級上升到1(每消除10行上升一次)

5. 消去 3 行 +600 (當前等級 1)。分數:1700 + 600 = 2300

6. 消去 4 行 +2400。分數:2300 + 2400 = 4700

7. 消去 2 行 +200。分數:4700 + 200 = 4900

Answer

function getScore(list) {    return score
}

看完題目的時候想說感覺蠻簡單的,實作上感覺有些邏輯會有點不熟悉,還是花了點時間想了一下。

馬上開始 !

1. 觀察分數如何得到

觀察一下行數&等級的表格,第 0 級消除1~4行後得到的分數是基礎值,接下來依照級數,每一級的分數會是 ( 消除x行的基礎分數 * (級數+1)* 2)
所以這邊得到幾個小結論
1. 消除第 0 級的 1~4行分數 => [40, 100, 300, 1200]
2. 計算分數的公式會是 ( 消除x行的基礎分數 * (級數+1)* 2)

2. 再來先假設只有傳入一個數字吧,會比較好思考。

 // 只消掉一行
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))

應該不難。

3. 傳入多個參數要怎麼進行?

從結果來看,因為要計算總合,這邊就直接聯想到 `reduce()`,還有一些需要特別注意的細節。
1. 消除分數會隨著等級提升而提高,但是以新數值傳入前的等級計算
2. 每一輪等級計算是以還沒加上傳入行數的等級為基礎

function 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

4. 小小檢討一下

後來看了一下其他前輩的算法之後發現,在計算等級的地方,我想得有點複雜
level = Math.floor(line/10)
上面這段其實可以改成
level = (line- line%10)/10
就不需要用到Math了。

後記

後來看到丟出這段題目的前輩的解法,沒看過Functional Programming,直接被嚇到XDD,程式碼如下:

// J3小
export function getScore(arr: number[]){
return arr.reduce(
({scores, totalLines}, lines)=>({
scores:
scores + [0, 40, 100, 300, 1200][lines] * (Math.floor(totalLines / 10) +1),
totalLines: totalLines + lines,
}),
{scores: 0, totalLines: 0}
).scores;
}

OS: J 3小 !??

慌張的我馬上去查了一下FP在幹嘛,學習清單又多一項可以學了 (擦汗..

PS. 直接跳過傳入資料的驗證 XD

以上就是 《俄羅斯方塊謎題 | JS地下城 — 番外篇 001》

本文章若有任何資訊誤植或侵權,煩請告知,我會立刻處理。

本篇文章也有發布在我的個人部落格,歡迎來交流。

--

--

Wen-Shiu Hsu | Kevin Hsu

隨意談談生活大小事 | 網頁前端 | 歡迎多多交流