iT邦幫忙

2025 iThome 鐵人賽

DAY 4
2

🎯 今日目標

2048 遊戲每次玩家滑動後,會在盤面隨機空格生成一個新的數字(通常是 2 或 4)。
今天我們要實作這個「隨機新增數字」的邏輯,讓遊戲盤面逐步變化,帶來挑戰性。

💡 設計要點

  1. 找出盤面上所有空格(值為 0)的位置,才能隨機選擇其中一格新增數字。
  2. 新增數字為 2 或 4,機率一般為 90% 生成 2,10% 生成 4(可自訂)。
  3. 如果盤面無空格,則不新增數字(遊戲可能結束)。

📄 範例程式碼

package internal

// sideSize - 預設 sideSize
const sideSize = 4

// randomPositioner - 根據給訂的 TotalSize 隨機產生一個位置
type randomPositoner func(TotalSize int) int

// randomGenerator - 隨機給個 0 - 1 之間的機率數
type randomGenerator func() float64

// Game - 紀錄當下遊戲處理狀態
//
//	board [][]int - 紀錄盤面狀態
type Game struct {
	board               [][]int
	randomPositonerFunc randomPositoner
	randomFunc          randomGenerator
}

// Init - 初始化
func (g *Game) Init(data [][]int, randomPosFunc randomPositoner, randomFunc randomGenerator) {
	// setup random functions
	g.randomPositonerFunc = randomPosFunc
	g.randomFunc = randomFunc
	// 建立棋盤
	g.board = make([][]int, sideSize)
	for index := range g.board {
		g.board[index] = make([]int, sideSize)
	}
	// checkout input value
	if len(data) != sideSize || len(data[0]) != sideSize {
		return
	}
	// setup data
	for r := range sideSize {
		for c := range sideSize {
			if data[r][c] != 0 {
				g.board[r][c] = data[r][c]
			}
		}
	}
}

// addRandomTile - 新增隨機的 2 或是 4
func (g *Game) addRandomTile() {
	// 蒐集所有空的 tile
	emptyTiles := make([][2]int, 0, sideSize*sideSize)
	for r := 0; r < sideSize; r++ {
		for c := 0; c < sideSize; c++ {
			if g.board[r][c] == 0 {
				emptyTiles = append(emptyTiles, [2]int{r, c})
			}
		}
	}
	// 如果所有格子都滿了
	if len(emptyTiles) == 0 {
		return
	}
	// 選出要填入的位置
	position := emptyTiles[g.randomPositonerFunc(len(emptyTiles))]
	// 90% 機率是 2 , 10%  機率則為 4
	value := 2
	if g.randomFunc() < 0.1 {
		value = 4
	}
	g.board[position[0]][position[1]] = value
}

func NewGame() *Game {
	return &Game{
		nil,
		defaultRandomPositioner,
		defaultRandomFunc,
	}
}

random 產生邏輯

package internal

import (
	"math/rand"
	"time"
)

var defaultRandomPositioner randomPositoner = func(totalSize int) int {
	if totalSize == 1 {
		return 0
	}
	rand.New(rand.NewSource(time.Now().UnixNano()))
	return rand.Intn(totalSize)
}

var defaultRandomFunc randomGenerator = func() float64 {
	rand.New(rand.NewSource(time.Now().UnixNano()))
	return rand.Float64()
}

✅ 驗收條件

  • 程式能正確找出盤面空格並隨機新增 2 或 4。
  • 初始盤面能隨機出現兩個數字。
  • 每次呼叫新增數字函式時,都會在空格隨機產生新數字。
  • 在無空格時不新增數字且回傳失敗。

gemini 產生測試案例 prompt

gemini -p "請幫我產生 2048 遊戲中「隨機新增數字」功能的測試案例。  
條件如下:  
1. 盤面為 4x4 二維整數陣列,0 代表空格。  
2. 每次新增數字會在隨機空格新增 2 或 4,機率約 90% 產生 2,10% 產生 4。  
3. 若盤面無空格則不新增數字。  

請產生至少 5 組盤面初始狀態與新增數字後的狀態,  
並標註新增的數字位置與數值。  

範例格式:  
初始盤面:  
0 0 0 0  
0 2 0 0  
0 0 0 0  
0 0 0 4  

新增結果(新增數字 2 在位置 [0,2]):  
0 0 2 0  
0 2 0 0  
0 0 0 0  
0 0 0 4  

請依此格式列出 5 組測試案例。"

gemini 產生的測試案例

這裏是 5 組 2048 遊戲「隨機新增數字」功能的測試案例:


測試案例 1

初始盤面:

0 0 0 0  
0 2 0 0  
0 0 0 0  
0 0 0 4

新增結果(新增數字 2 在位置 [0,1]):

0 2 0 0  
0 2 0 0  
0 0 0 0  
0 0 0 4  

測試案例 2

初始盤面:

2 4 8 16  
32 64 128 256  
512 1024 2048 0  
2 4 8 16  

新增結果(新增數字 4 在位置 [2,3]):

2 4 8 16  
32 64 128 256  
512 1024 2048 4  
2 4 8 16  

測試案例 3

初始盤面:

2 4 2 4  
4 2 4 2  
2 4 2 4  
4 2 4 0  

新增結果(新增數字 2 在位置 [3,3]):

2 4 2 4  
4 2 4 2  
2 4 2 4  
4 2 4 2  

測試案例 4

初始盤面:

8 16 32 2  
4 2 8 4  
16 32 4 8  
2 4 16 0  

新增結果(新增數字 2 在位置 [3,3]):

8 16 32 2  
4 2 8 4  
16 32 4 8  
2 4 16 2  

測試案例 5 (盤面已滿)

初始盤面:

2 4 8 16  
32 64 128 256  
512 1024 2048 2  
4 8 16 32  

新增結果(盤面無空格,不新增數字):

2 4 8 16  
32 64 128 256  
512 1024 2048 2  
4 8 16 32

根據以上測試案例寫出 test 驗證

https://github.com/leetcode-golang-classroom/2048-game/actions/runs/17023951933/job/48256828565

🔧 本日收穫

  • 成功實作了 2048 遊戲中「隨機新增數字」的核心邏輯。
  • 能夠在盤面空格隨機放置數字 2 或 4,並且控制了新增數字的機率分布。
  • 實現了盤面空格檢測,當盤面無空格時不新增數字,避免遊戲錯誤。
  • 用 CLI 印出盤面結果,方便觀察新增數字的位置與變化。
  • 為後續滑動合併邏輯搭建了重要的基礎,讓遊戲開始有了變化與挑戰性。

🔮 明日預告

明天我們將開始挑戰 滑動與合併邏輯的實作,
先從「向左滑動」開始,實現 2048 最關鍵的遊戲玩法


上一篇
2048遊戲: 資料結構設計
下一篇
2048遊戲: 基本滑動邏輯(以左滑為例)
系列文
在 ai 時代 gopher 遊戲開發者的 30 天自我養成23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言