iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
JavaScript

重新拿回思考力!一起來用 JavaScript 打造 CLI 好玩遊戲區!系列 第 10 篇

Day10 爆爆王2:從結果反推函式的練習

  • 分享至 

  • xImage
  •  

今天我們要來寫生成箱子的邏輯,如同昨天所說的,因為箱子不管哪一個的行為都是一樣的,所以我們不用從 box1 寫到 box10,我們可以試著用一個函式來生成所有的箱子。

以終為始思考

首先來想想:我們期望傳入怎樣的內容,並且輸出怎樣的資料格式,先定義好這個方向之後,再來思考內部的邏輯。

https://ithelp.ithome.com.tw/upload/images/20260922/20182439K6hKh8Xs2T.png

比照 pickRandomEmptyCell 函式,我想一樣把地圖以及要避免的座標傳進去,但是要再加上這次想生成幾個箱子,並且要以陣列回傳箱子們的座標。

預期使用的形式是 let boxes = createBoxes(map,10,[player,enemy1,enemy2,enemy3]);

那我們就來寫這個函式吧,還不知道怎麼寫也沒關係,我們先把 input 、output 的內容定下來,也順便在裡面用自然語言補上我們心中的步驟:

function createBoxes(map,boxesNum, occupied = []) {

    // 用來儲存箱子們的座標
    let boxes = [];

    // 找到所有的空格

    // 隨機選 10 個位置

    return boxes;
}

接著再逐一來看每一個問題

要如何找到所有的空格

這個在 pickRandomEmptyCell 已經有實作過一次,可以拿來用

function createBoxes(map,boxesNum, occupied = []) {

    let boxes = [];

    // 找到所有的空格
    const emptyCell = [];

    for (let y = 0; y < map.length; y++) {

        for (let x = 0; x < map[y].length; x++) {
            // 判斷是不是已被占用
            const isOccupied = occupied.some(cell => cell.x === x && cell.y === y);
            // 如果該位置是空的而且尚未被占用才將這個數值儲存到 emptyCell
            if (map[y][x] === " " && !isOccupied) {
                emptyCell.push({ x, y })
            }
        }
    }

    // 隨機選 10 個位置

    // 存進 boxes

    return boxes;
}

如何隨機選 10 個位置

解決這個問題時發現腦袋實在是沒有想法,我們也不要卡在這裡,可以試著去吸取一下其他工程師的日月精華,感謝現在有 AI 摘要,可以快速幫我們找出最佳解法,當然你問 GPT、Gemini、Claude 也可以!

https://ithelp.ithome.com.tw/upload/images/20260922/2018243915XPCs5L6T.png

但我們先理解一下這個寫法,判斷哪些是我們需要的:

  1. 在這一段程式碼中首先它複製陣列,是為了避免修改到原本的陣列→ 我們不需要,因為 emptyCell 已經是我們可以拿來隨意處理的內容。
  2. 把這個陣列用 for 迴圈洗牌 → 看到這邊還沒辦法知道他要幹嘛,所以繼續看。
  3. 洗牌之後取前 10 個 → 到這邊我們就知道洗牌是為了之後可以直接取前十個,所以最後這兩個步驟,我們必須要保留

那我們就來寫吧!

function createBoxes(map,boxesNum, occupied = []) {

    // 用來儲存箱子們的座標
    let boxes = [];

    // 找到所有的空格
    // ... 這邊就不動

    // 隨機選 10 個位置
    for (let i = emptyCell.length -1; i > 0; i --) { // 這裡是由大到小遞減的迴圈
        const j = Math.floor(Math.random() * (i+1)); // 隨機在小於等於 i 的範圍內選一個數字
        [emptyCell[i],emptyCell[j]] = [emptyCell[j],emptyCell[i]]; // 兩者交換
    }

    // 存進 boxes,這裡要記得帶入 boxesNum
    boxes = emptyCell.slice(0,boxesNum);

    return boxes;
}

也可以更精簡的直接拿掉 boxes 變數,並 return emptyCell.slice(0,boxesNum) 就好唷。不過為了這邊講解順序的連貫性,我還是先保留這個寫法。

如果你想要的話,也可以在洗牌前後都 console.log 出來看看是不是真的有洗到牌。

那麼我們就在 render 加上箱子的印出

else if (boxes.some(box => box.x === x && box.y === y)) {
  row += `\x1b34mX\x1b[0m` // 用藍色和 X 來呈現箱子
}

執行看看

https://ithelp.ithome.com.tw/upload/images/20260922/20182439bbw48Rncmo.png

恭喜我們!這樣就成功完成了隨機地圖的製作了,明天我們會來完成監聽使用者動作等基礎設施,如果你可以的話,試著先完成到監聽使用者的動作吧!

明天見!

如果你想要瀏覽完整的程式碼,可以參考這裡:第十天程式碼


上一篇
Day9 爆爆王1:制定練習目標與開發邊界
下一篇
Day11 爆爆王 3:從監聽動作到儀表板印出,Terminal 環境小複習
系列文
重新拿回思考力!一起來用 JavaScript 打造 CLI 好玩遊戲區! 共 12 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言