Skip to content

2020-11-19

/ 10 分鐘閱讀

題目如下。

Challenge

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

背景

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

關於計分制度

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

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

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

Level消去 1 行消去 2 行消去 3 行消去 4 行
0401003001200
1802006002400
21203009003600
316040012004800
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 且裡面只包含數字  0  到  4

Output

計算的最終分數。

Example

getScore([4, 2, 2, 3, 3, 4, 2]); // returns 4900
  1. 消去 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. 再來先假設只有傳入一個數字吧,會比較好思考。

    javascript
    // 只消掉一行
    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. 每一輪等級計算是以還沒加上傳入行數的等級為基礎
    javascript
    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,程式碼如下:

javascript
// J3小 XDD
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;
}

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

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


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

最後更新時間:

0 %
MIT Licensed | Copyright © 2025-present Wen-Hsiu's Blog