138 lines
3.4 KiB
Go
Executable File
138 lines
3.4 KiB
Go
Executable File
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
|
|
}
|