game/server/logic/grid.go

138 lines
3.4 KiB
Go

package logic
import (
"math/rand"
"wuziqi-server/core"
)
// GenerateGrid 创建一个新的随机网格
func GenerateGrid(gridSize int, bombCount int, itemMin int, itemMax int, enabledItems map[string]bool, itemWeights map[string]int, allItemTypes []string) []*core.GridCell {
totalCells := gridSize * gridSize
grid := make([]*core.GridCell, totalCells)
for i := 0; i < totalCells; i++ {
grid[i] = &core.GridCell{Type: "empty", Revealed: false}
}
// 放置炸弹
bombsPlaced := 0
for bombsPlaced < bombCount && bombsPlaced < totalCells {
idx := rand.Intn(totalCells)
if grid[idx].Type == "empty" {
grid[idx].Type = "bomb"
bombsPlaced++
}
}
// 过滤启用的道具
var pool []string
if len(enabledItems) > 0 {
for _, it := range allItemTypes {
if enabled, ok := enabledItems[it]; ok && enabled {
weight := 10
if w, ok := itemWeights[it]; ok && w > 0 {
weight = w
}
for i := 0; i < weight; i++ {
pool = append(pool, it)
}
}
}
}
if len(pool) == 0 {
pool = allItemTypes
}
// 放置道具
itemCount := rand.Intn(itemMax-itemMin+1) + itemMin
itemsPlaced := 0
for itemsPlaced < itemCount && (bombsPlaced+itemsPlaced) < totalCells {
idx := rand.Intn(totalCells)
if grid[idx].Type == "empty" {
grid[idx].Type = "item"
grid[idx].ItemID = pool[rand.Intn(len(pool))]
itemsPlaced++
}
}
// 计算邻居
for i := 0; i < totalCells; i++ {
if grid[i].Type == "bomb" {
continue
}
count := 0
neighbors := GetNeighborIndices(i, gridSize)
for _, neighborIdx := range neighbors {
if grid[neighborIdx].Type == "bomb" {
count++
}
}
grid[i].NeighborBombs = count
}
return grid
}
func GetNeighborIndices(index int, gridSize int) []int {
neighbors := []int{}
row := index / gridSize
col := index % gridSize
for r := row - 1; r <= row+1; r++ {
for c := col - 1; c <= col+1; c++ {
if (r == row && c == col) || r < 0 || r >= gridSize || c < 0 || c >= gridSize {
continue
}
neighbors = append(neighbors, r*gridSize+c)
}
}
return neighbors
}
// RevealSafeArea 使用泛洪填充算法揭示连续的空位
// 标准扫雷规则:揭示边界的数字格子,但不从它们继续扩展
// 道具和炸弹都不会被揭示,它们阻断泛洪填充
func RevealSafeArea(state *core.GameState, startIndex int) []int {
revealed := []int{}
visited := make(map[int]bool)
// 起始格子可能已经被揭示(在调用前被设置),
// 我们需要从它的邻居开始扩展
startCell := state.Grid[startIndex]
visited[startIndex] = true
// 初始化队列
var queue []int
if startCell.NeighborBombs == 0 {
// 起始格子是空白格(无数字),从邻居开始扩展
queue = GetNeighborIndices(startIndex, state.GridSize)
}
// 如果起始格子有数字,不扩展邻居
for len(queue) > 0 {
idx := queue[0]
queue = queue[1:]
if visited[idx] {
continue
}
visited[idx] = true
cell := state.Grid[idx]
// 如果已揭示、是炸弹或道具则跳过(道具和炸弹阻断泛洪填充)
if cell.Revealed || cell.Type == "bomb" || cell.Type == "item" {
continue
}
// 揭示空格子(包括有数字的边界格子)
cell.Revealed = true
revealed = append(revealed, idx)
// 只有无炸弹邻居的空位才继续扩展
if cell.NeighborBombs == 0 {
neighbors := GetNeighborIndices(idx, state.GridSize)
queue = append(queue, neighbors...)
}
}
return revealed
}