go_dreamfactory/modules/entertainment/xxlPlat.go
2024-01-22 14:47:53 +08:00

1622 lines
36 KiB
Go

package entertainment
import (
"crypto/rand"
"fmt"
"go_dreamfactory/comm"
"go_dreamfactory/pb"
cfg "go_dreamfactory/sys/configure/structs"
"go_dreamfactory/utils"
"math/big"
)
const (
Width = 7
Height = 7
Total = Width * Height
FiveType = 3 // 5消类型
FourUType = 1 // 4消上下类型
FourLType = 2 // 4消左右类型
BoomType = 4 // 炸弹类型
FireUp = 5 //上烟火
FireDown = 6 //下烟火
FireLeft = 7 //左烟火
FireRight = 8 //右烟火
)
type Girde struct {
oid int32 // 唯一ID
color int32 // 颜色
cid int32 // 配置表id
score int32 // 分数
special int32 // 消除特效
}
//地图数据
type MapData struct {
Plat []*pb.GirdeData // 地图
oid int32 // 唯一id
module *Entertainment
operElem []int32 // 当前移动的元素
iType int32 // 玩法类型
}
// 1~6随机一个数
func (this *MapData) GetRandType() int32 {
return this.module.configure.GetGameNormalElem() // 权重随机
}
// 玩法带入
func (this *MapData) CreateGride(count int) (girdes []*pb.GirdeData) {
var (
id int32
conf *cfg.GameBlockData
err error
) // 权重带入
for i := 0; i < count; i++ {
this.oid++
girde := &pb.GirdeData{ // 默认值
Oid: this.oid,
Color: 1,
Cid: 1,
Score: 1,
Special: 0,
}
id = this.GetRandType()
if conf, err = this.module.configure.GetGameBlockByKey(id); err == nil {
girde.Color = conf.Color
girde.Cid = conf.Key
girde.Special = conf.Type
girde.Score = conf.Score
girdes = append(girdes, girde)
}
}
return
}
// 生成自定义地图
func (this *MapData) SetMap() {
sz2 := []int32{
3, 1, 2, 2, 1, 3, 1,
5, 1, 2, 4, 1, 2, 2,
2, 4, 3, 1, 3, 1, 6,
1, 3, 4, 5, 1, 3, 6,
2, 1, 1, 2, 1, 1, 4,
1, 6, 3, 26, 3, 4, 3,
3, 3, 1, 2, 1, 1, 5,
}
var pos int
for index := Width - 1; index >= 0; index-- {
for j := 0; j < Height; j++ {
Color := sz2[pos]
Cid := sz2[pos]
if sz2[pos] > 6 { // 特殊元素
conf, err := this.module.configure.GetGameBlockByKey(sz2[pos])
if err == nil {
Color = conf.Color
Cid = conf.Key
this.Plat[index+j*Height].Special = conf.Type
}
}
this.Plat[index+j*Height].Color = Color
this.Plat[index+j*Height].Cid = Cid
pos++
}
}
this.CheckAndRefreshPlat()
// this.SetIndelibilityPlat()
}
// 初始化地图数据
func (this *MapData) InitMap(module *Entertainment, iType int32) {
this.module = module
this.iType = iType
this.oid = 1000 // 方便观察 从1000开始
this.Plat = make([]*pb.GirdeData, Width*Height)
for i, v := range this.CreateGride(Total) {
this.Plat[i] = v
}
if iType > 1 {
var sp int32
var mp map[int32]struct{}
mp = make(map[int32]struct{}, 0)
for {
n1, _ := rand.Int(rand.Reader, big.NewInt(Total))
mp[int32(n1.Int64())] = struct{}{}
if len(mp) >= 2 {
break
}
}
for key := range mp {
if iType == 3 {
sp = 4
} else if iType == 4 {
n1, _ := rand.Int(rand.Reader, big.NewInt(4)) // 随机一个消除类型
sp = int32(n1.Int64()) + 5
}
if conf, err := this.module.configure.GetGameBlock(this.Plat[key].Color, sp); err == nil {
this.Plat[key].Cid = conf.Key
this.Plat[key].Special = conf.Type
this.Plat[key].Score = conf.Score
}
}
}
this.SetIndelibilityPlat()
//this.SetMap()
// this.Plat = this.GetPalatData()
}
// 交换之前先判断是不是特殊元素的交换
func (this *MapData) CheckSpecialElemChange(oldId, newId int32, color int32) (bSwap bool, szMap []*pb.MapData) {
this.operElem = []int32{} // 初始化
if (oldId%Height+1 < Total && oldId+1 == newId) ||
(oldId%Height > 0 && oldId-1 == newId) ||
(oldId+Width < Total && oldId+Width == newId) ||
(oldId-Width >= 0 && oldId-Width == newId) {
bSwap = true
x := make(map[int]struct{})
if this.Plat[newId].Special != 0 && this.Plat[oldId].Special != 0 { // 都不为0
tmp := new(pb.GirdeData)
*tmp = *this.Plat[newId]
this.Plat[newId] = this.Plat[oldId]
this.Plat[oldId] = tmp
this.operElem = append(this.operElem, newId)
this.operElem = append(this.operElem, oldId)
x = this.SpecialElem(int(oldId), this.Plat[oldId].Special)
xc := this.SpecialElem(int(newId), this.Plat[newId].Special)
for k := range xc {
x[k] = struct{}{}
}
var energy int32
var curScore int32
for id := range x {
if this.Plat[id].Color == color {
energy++
}
curScore += this.Plat[id].Score
this.Plat[id] = &pb.GirdeData{}
this.operElem = append(this.operElem, int32(id))
}
if this.DropGirde() {
szMap = append(szMap, &pb.MapData{
Data: this.GetPalatData(),
CurSocre: curScore,
CurEnergy: energy,
})
}
} else {
bSwap = false
}
}
return
}
// 交换2个元素(参数 oid )
func (this *MapData) SwapGirde(oldId, newId int32) (bSwap bool) {
this.operElem = []int32{} // 初始化
if (oldId%Height+1 < Total && oldId+1 == newId) ||
(oldId%Height > 0 && oldId-1 == newId) ||
(oldId+Width < Total && oldId+Width == newId) ||
(oldId-Width >= 0 && oldId-Width == newId) {
bSwap = true
tmp := new(pb.GirdeData)
*tmp = *this.Plat[newId]
this.Plat[newId] = this.Plat[oldId]
this.Plat[oldId] = tmp
this.operElem = append(this.operElem, newId)
this.operElem = append(this.operElem, oldId)
}
//this.Debugf()
return
}
func (this *MapData) Debugf() {
fmt.Printf("================\n")
var v int
for index := Width - 1; index >= 0; index-- {
for j := 0; j < Height; j++ {
v = index + j*7
fmt.Printf("%d:%d ", v, this.Plat[index+j*Height].Cid)
}
fmt.Printf("\n")
}
}
// 检查5消 (s 是生成新的一个新的元素 key 下标 value 消除后效果类型)
func (this *MapData) Check5X() (bEliminate bool, xiaochu []int, s map[int]int) {
//var xiaochu []int // 即将消除的key
s = make(map[int]int)
for k, v := range this.Plat {
if v.Cid == 0 {
continue
}
x := int32(k % Height) // x
if x+4 < Height {
k1 := this.Plat[k].Color
k2 := this.Plat[k+1].Color
k3 := this.Plat[k+2].Color
k4 := this.Plat[k+3].Color
k5 := this.Plat[k+4].Color
if k1 == k2 && k3 == k4 && k5 == k1 && k2 == k3 {
s[k+2] = FiveType
xiaochu = append(xiaochu, []int{k, k + 1, k + 2, k + 3, k + 4}...)
this.Plat[k].Cid = 0
this.Plat[k+1].Cid = 0
this.Plat[k+2].Cid = 0
this.Plat[k+3].Cid = 0
this.Plat[k+4].Cid = 0
bEliminate = true
}
}
if k+4*Width < Total {
k1 := this.Plat[k].Color
k2 := this.Plat[k+Width].Color
k3 := this.Plat[k+2*Width].Color
k4 := this.Plat[k+3*Width].Color
k5 := this.Plat[k+4*Width].Color
if k1 == k2 && k3 == k4 && k5 == k1 && k2 == k3 {
s[k+2*Width] = FiveType
xiaochu = append(xiaochu, []int{k, k + Width, k + 2*Width, k + 3*Width, k + 4*Width}...)
this.Plat[k].Cid = 0
this.Plat[k+Width].Cid = 0
this.Plat[k+2*Width].Cid = 0
this.Plat[k+3*Width].Cid = 0
this.Plat[k+4*Width].Cid = 0
bEliminate = true
}
}
}
// // 校验上下左右
// for j := 0; j < Width; j++ {
// for k := 0; k < Height; k++ {
// pos := j*Width + k
// if pos+2 < Height {
// k1 := this.Plat[pos].Color
// k2 := this.Plat[pos+1].Color
// k3 := this.Plat[pos+2].Color
// var k4 int32
// var k5 int32
// if k1 == k2 && k3 == k1 { // 三个颜色相等
// tmp := pos
// index := 0
// for {
// index++
// if tmp/Width-2 >= 0 { // k1 的左右
// k4 = this.Plat[tmp/Width-1].Color
// k5 = this.Plat[tmp/Width-2].Color
// if k1 == k4 && k1 == k5 {
// bEliminate = true
// s[tmp] = FiveType
// this.Plat[pos].Cid = 0
// this.Plat[pos+1].Cid = 0
// this.Plat[pos+2].Cid = 0
// this.Plat[tmp/Width-1].Cid = 0
// this.Plat[tmp/Width-2].Cid = 0
// }
// }
// if tmp/Width+2 < Width {
// k4 = this.Plat[tmp/Width+1].Color
// k5 = this.Plat[tmp/Width+2].Color
// if k1 == k4 && k1 == k5 {
// bEliminate = true
// s[tmp] = FiveType
// this.Plat[pos].Cid = 0
// this.Plat[pos+1].Cid = 0
// this.Plat[pos+2].Cid = 0
// this.Plat[tmp/Width+1].Cid = 0
// this.Plat[tmp/Width+2].Cid = 0
// }
// }
// tmp = pos + 2
// if index == 2 {
// break
// }
// }
// }
// }
// }
// }
return
}
func (this *MapData) Check4X() (bEliminate bool, xiaochu []int, s map[int]int) {
var (
newElem int // 生成的一个新的元素CID
)
s = make(map[int]int)
for k, v := range this.Plat {
if v.Cid == 0 {
continue
}
x := int32(k % Height) // x
newElem = 0
if x+3 < Height {
k1 := this.Plat[k].Color
k2 := this.Plat[k+1].Color
k3 := this.Plat[k+2].Color
k4 := this.Plat[k+3].Color
if k1 == k2 && k3 == k4 && k2 == k3 {
for _, v1 := range this.operElem {
for i := 0; i <= 3; i++ {
if int(v1) == k+i {
newElem = int(v1)
break
}
}
if newElem != 0 {
break
}
}
if newElem == 0 {
newElem = k + 2 // 给个默认值
}
// 如果当前生成的也是一个特殊的元素 直接消除
if this.Plat[newElem].Special == 0 {
s[newElem] = FourUType
}
xiaochu = append(xiaochu, []int{k, k + 1, k + 2, k + 3}...)
for _, v := range xiaochu {
this.Plat[v].Cid = 0
}
bEliminate = true
}
}
if k+3*Width < Total {
k1 := this.Plat[k].Color
k2 := this.Plat[k+Width].Color
k3 := this.Plat[k+2*Width].Color
k4 := this.Plat[k+3*Width].Color
if k1 == k2 && k3 == k4 && k2 == k3 {
for _, v1 := range this.operElem {
for i := 0; i <= 3; i++ {
if int(v1) == k+i*Width {
newElem = int(v1) // 创建一个特殊的元素
break
}
}
if newElem != 0 {
break
}
}
if newElem == 0 {
newElem = k + 2*Width // 给个默认值
}
// 如果当前生成的也是一个特殊的元素 直接消除
if this.Plat[newElem].Special == 0 {
s[newElem] = FourLType
}
xiaochu = append(xiaochu, k+Width)
xiaochu = append(xiaochu, []int{k, k + Width, k + 2*Width, k + 3*Width}...)
for _, v := range xiaochu {
this.Plat[v].Cid = 0
}
bEliminate = true
}
}
}
return
}
func (this *MapData) Check3X() (bEliminate bool, xiaochu []int) {
//var xiaochu []int // 即将消除的key
for k, v := range this.Plat {
b := false
for _, e := range this.operElem {
if e == int32(k) {
b = true
break
}
}
if v.Cid == 0 && !b {
continue
}
x := int32(k % Height) // x
if x+2 < Height {
k1 := this.Plat[k].Color
k2 := this.Plat[k+1].Color
k3 := this.Plat[k+2].Color
if k1 == k2 && k2 == k3 {
xiaochu = append(xiaochu, []int{k, k + 1, k + 2}...)
this.Plat[k].Cid = 0
this.Plat[k+1].Cid = 0
this.Plat[k+2].Cid = 0
bEliminate = true
}
}
if k+2*Width < Total {
k1 := this.Plat[k].Color
k2 := this.Plat[k+Width].Color
k3 := this.Plat[k+2*Width].Color
if k1 == k2 && k2 == k3 {
xiaochu = append(xiaochu, []int{k, k + Width, k + 2*Width}...)
this.Plat[k].Cid = 0
this.Plat[k+Width].Cid = 0
this.Plat[k+2*Width].Cid = 0
bEliminate = true
}
}
}
return
}
// 校验地图可消除的 判断各组上面2个和右边两个是否三个相等
// xc 判断用来是否加体力
func (this *MapData) CheckMap(color int32, bSkill bool) (szMap []*pb.MapData, xc bool) {
var (
tXiaochu map[int]struct{}
curScore int32
energy int32
new map[int]int
x map[int]struct{}
//s map[int]int
)
for {
new = make(map[int]int)
x = make(map[int]struct{})
tXiaochu = make(map[int]struct{})
curScore = 0
energy = 0
//s = make(map[int]int)
for i := 1; i <= 6; i++ {
xc, s := this.CheckElem(int32(i))
for k, v := range s {
new[k] = v
}
for _, v := range xc {
for _, v1 := range v {
tXiaochu[v1] = struct{}{}
}
}
}
for id := range tXiaochu {
if _, ok := new[id]; ok {
if this.Plat[id].Color == color {
energy++
}
curScore += this.Plat[id].Score
this.oid++ // 生成一个新的类型元素
if this.module == nil { // 稍后删掉 方便测试
this.Plat[id] = &pb.GirdeData{
Oid: this.oid,
Color: this.Plat[id].Color,
Cid: 2*(this.Plat[id].Color-1) + 6 + int32(new[id]),
Score: 1,
Special: int32(new[id]),
}
} else {
if s := this.Plat[id].Special; s != 0 {
for key := range this.SpecialElem(id, s) {
x[key] = struct{}{}
}
x[id] = struct{}{}
}
if conf, err := this.module.configure.GetGameBlock(this.Plat[id].Color, int32(new[id])); err == nil {
this.Plat[id] = &pb.GirdeData{
Oid: this.oid,
Color: this.Plat[id].Color,
Cid: conf.Key,
Score: conf.Score,
Special: conf.Type,
}
}
}
continue
}
if s := this.Plat[id].Special; s != 0 {
for key := range this.SpecialElem(id, s) {
x[key] = struct{}{}
}
}
x[id] = struct{}{}
}
for id := range x {
if this.Plat[id].Color == color {
energy++
}
curScore += this.Plat[id].Score
this.Plat[id] = &pb.GirdeData{}
this.operElem = append(this.operElem, int32(id))
}
if this.DropGirde() {
if !bSkill {
energy = 0
}
szMap = append(szMap, &pb.MapData{
Data: this.GetPalatData(),
CurSocre: curScore,
CurEnergy: energy,
})
}
// 检查掉落
this.operElem = []int32{} // 初始化操作元素
if curScore == 0 {
break
}
}
return
}
// 下落 生成新的格子 (返回掉落所获得的分数)
func (this *MapData) DropGirde() bool {
// 需要填充的格子
var fill []int
bDrop := false
for i := 0; i < Width; i++ {
for j := 0; j < Height; j++ {
index := i*Width + j
if this.Plat[index].Cid == 0 { // 说明这列有空
bDrop = true
var add int
for m := j + 1; m < Height; m++ {
k1 := i*Width + m
if this.Plat[k1].Cid != 0 {
this.Plat[index] = this.Plat[k1]
index++
add++
}
}
for m := j + add; m < Height; m++ {
k1 := i*Width + m
fill = append(fill, k1)
}
break
}
}
}
if len(fill) == 0 {
return bDrop
}
sz := this.CreateGride(len(fill))
for pos, id := range fill {
this.Plat[id] = sz[pos]
}
if this.iType > 1 {
var sp int32
var mp map[int]struct{}
mp = make(map[int]struct{}, 0)
var count int32
for pos, v := range this.Plat {
if this.iType == 4 {
if v.Special == 5 || v.Special == 6 ||
v.Special == 7 || v.Special == 8 {
mp[pos] = struct{}{}
count++
if count >= 2 {
break
}
}
} else if this.iType == 3 {
if v.Special == 4 {
mp[pos] = struct{}{}
count++
if count >= 2 {
break
}
}
}
}
if len(mp) < 2 {
ilen := 2 - len(mp)
mp = make(map[int]struct{}, ilen)
for i := 0; i < ilen; i++ {
n1, _ := rand.Int(rand.Reader, big.NewInt(int64(len(fill))))
mp[fill[n1.Int64()]] = struct{}{}
}
for key := range mp {
if this.iType == 3 {
sp = 4
} else if this.iType == 4 {
n1, _ := rand.Int(rand.Reader, big.NewInt(4)) // 随机一个消除类型
sp = int32(n1.Int64()) + 5
}
if conf, err := this.module.configure.GetGameBlock(this.Plat[key].Color, sp); err == nil {
this.Plat[key].Cid = conf.Key
this.Plat[key].Special = conf.Type
this.Plat[key].Score = conf.Score
} else { // 错误打印
this.module.Errorf("cond conf err :%v,color:%d", err, this.Plat[key].Color)
}
}
}
}
return bDrop
}
// 深拷贝
func (this *MapData) GetPalatData() (data []*pb.GirdeData) {
for _, v := range this.Plat {
data = append(data, &pb.GirdeData{
Oid: v.Oid,
Color: v.Color,
Cid: v.Cid,
Score: v.Score,
Special: v.Special,
})
}
return data
}
// ai操作
func (this *MapData) AiSwapGirde() (szMap []*pb.MapData, oid1 int32, oid2 int32, bAddPs bool) {
for pos := 0; pos < Total; pos++ {
y := pos % Height
if y < Height-1 {
if b := this.SwapGirde(int32(pos), int32(pos+1)); b {
oid1 = this.Plat[pos+1].Oid
oid2 = this.Plat[pos].Oid
if m, b := this.CheckMap(2, true); len(m) == 0 {
this.SwapGirde(int32(pos+1), int32(pos))
this.operElem = []int32{}
oid1 = 0
oid2 = 0
} else {
szMap = append(szMap, m...)
bAddPs = b
break
}
}
}
if pos/Width+1 < Width {
if b := this.SwapGirde(int32(pos), int32(pos+Width)); b {
oid1 = this.Plat[pos+Width].Oid
oid2 = this.Plat[pos].Oid
if m, b := this.CheckMap(2, true); len(m) == 0 {
this.SwapGirde(int32(pos+Width), int32(pos))
this.operElem = []int32{}
oid1 = 0
oid2 = 0
} else {
szMap = append(szMap, m...)
bAddPs = b
break
}
}
}
}
return
}
// 释放技能 技能id 和参数
func (this *MapData) SkillUp(pos int32, color int32, skillid int32, value int32, bDrop bool) (x map[int]struct{}, szMap []*pb.MapData) {
var (
skillScore int32 // 技能获得的分数
skillEnergy int32 // 技能获得的能量
ids []int
)
x = make(map[int]struct{})
switch skillid {
case 1:
ids = utils.RandomNumbers(0, Total-1, int(value))
case 2:
for i := 0; i < Height; i++ {
ids = append(ids, 3*Width+i)
}
case 3: // 将随机6个宝石染成当前盘面上颜色最多的宝石
this.SkillChangeColor(value)
bDrop = false
szMap = append(szMap, &pb.MapData{
Data: this.GetPalatData(),
CurSocre: skillScore,
CurEnergy: skillEnergy,
})
if list, _ := this.CheckMap(color, false); len(list) > 0 {
szMap = append(szMap, list...)
}
case 4:
x := int(pos / Width)
y := int(pos % Height)
for i := 1; i < 7; i++ {
if x-i >= 0 && y+i < Height { // 左上
ids = append(ids, (x-i)*Width+(y+i))
}
if x-i >= 0 && y-i >= 0 { // 左下
ids = append(ids, (x-i)*Width+(y-i))
}
if x+i < Width && y+i < Height { // 右上
ids = append(ids, (x+i)*Width+(y+i))
}
if x+i < Width && y-i >= 0 { // 右下
ids = append(ids, (x+i)*Width+(y-i))
}
}
case 5:
ids = append(ids, int(pos)) // 包含自己
x := int(pos / Width)
y := int(pos % Height)
if x-1 >= 0 { // 左
ids = append(ids, (x-1)*Width+(y))
}
if y-1 >= 0 { // 下
ids = append(ids, (x)*Width+(y-1))
}
if y+1 < Height { // 上
ids = append(ids, (x)*Width+(y+1))
}
if x+1 < Width { // 右
ids = append(ids, (x+1)*Width+(y))
}
if x-1 >= 0 && y+1 < Height { // 左上
ids = append(ids, (x-1)*Width+(y+1))
}
if x-1 >= 0 && y-1 >= 0 { // 左下
ids = append(ids, (x-1)*Width+(y-1))
}
if x+1 < Width && y+1 < Height { // 右上
ids = append(ids, (x+1)*Width+(y+1))
}
if x+1 < Width && y-1 >= 0 { // 右下
ids = append(ids, (x+1)*Width+(y-1))
}
case 8:
for k := range this.SkillManYan(pos, 0) {
ids = append(ids, k) // 转换成最终消除的坐标
}
ids = append(ids, int(pos)) // 包含自己
default:
this.module.Errorf("not found skill:%d", skillid)
return
}
for _, id := range ids {
if s := this.Plat[id].Special; s != 0 {
for k := range this.SpecialElem(id, s) {
x[k] = struct{}{}
}
}
x[id] = struct{}{}
}
if bDrop {
for key := range x {
if this.Plat[key].Color == color {
skillEnergy += 1
}
skillScore += this.Plat[key].Score
this.Plat[key] = &pb.GirdeData{}
}
if this.DropGirde() {
szMap = append(szMap, &pb.MapData{
Data: this.GetPalatData(),
CurSocre: skillScore,
CurEnergy: skillEnergy,
})
if list, _ := this.CheckMap(color, false); len(list) > 0 {
szMap = append(szMap, list...)
}
}
}
return
}
// 校验当前地图 有没有能消除的
func (this *MapData) CheckAndRefreshPlat() (bEliminate bool) {
bEliminate = false
for k, v := range this.Plat {
if v.Color == 0 {
continue
}
x := int32(k % Height)
y := int32(k / Height)
if x+2 < Height { // 上
k1 := this.Plat[k].Color
k2 := this.Plat[k+1].Color
if k1 == k2 { // 校验k3 左边和右边
if true {
pos := k + 2
if pos/Width-1 >= 0 { // 左
p := this.Plat[pos-Width].Color
if p == k1 {
bEliminate = true
return
}
}
if pos/Width+1 < Width { // 右
p := this.Plat[pos+Width].Color
if p == k1 {
bEliminate = true
return
}
}
if pos%Height+1 < Height { // 上
p := this.Plat[pos+1].Color
if p == k1 {
bEliminate = true
return
}
}
}
// xia
pos := k - 1
if x > 0 {
if pos%Height >= 0 { // 左右
if pos/Width-1 >= 0 { //左
p := this.Plat[pos-Width].Color
if p == k1 {
bEliminate = true
return
}
}
if pos/Width+1 < Width { // 右
p := this.Plat[pos+Width].Color
if p == k1 {
bEliminate = true
return
}
}
}
}
if x > 1 {
p := this.Plat[pos-1].Color
if p == k1 {
bEliminate = true
return
}
}
}
}
if y+2 < Height { // 左
k1 := this.Plat[k].Color
k2 := this.Plat[k+Width].Color
if k1 == k2 { // 校验k3 左边和右边
if true {
pos := k + 2*Width
if pos/Width+1 < Width { // 右
p := this.Plat[pos+Width].Color
if p == k1 {
bEliminate = true
return
}
}
if pos%Height+1 < Width { // 上
p := this.Plat[pos+1].Color
if p == k1 {
bEliminate = true
return
}
}
if pos%Height-1 >= 0 {
p := this.Plat[pos-1].Color
if p == k1 {
bEliminate = true
return
}
}
}
if true {
pos := k - Width
if pos >= 0 {
if pos%Height+1 < Width { // 上
p := this.Plat[pos+1].Color
if p == k1 {
bEliminate = true
return
}
}
if pos%Height-1 >= 0 { // 下
p := this.Plat[pos-1].Color
if p == k1 {
bEliminate = true
return
}
}
}
if pos/Height-1 >= 0 {
p := this.Plat[pos-Height].Color
if p == k1 {
bEliminate = true
return
}
}
}
}
}
}
for k, v := range this.Plat {
if v.Color == 0 {
continue
}
// x := int32(k % Height) // x
y := int32(k / Height) // y
if y+2 < Width {
k1 := this.Plat[k].Color
k2 := this.Plat[k+2*Width].Color
pos := k + Width
if k1 == k2 {
// 上
if pos%Height+1 < Height {
p := this.Plat[pos+1].Color
if p == k1 {
bEliminate = true
return
}
}
if pos%Height-1 >= 0 {
p := this.Plat[pos-1].Color
if p == k1 {
bEliminate = true
return
}
}
}
}
}
// 上下检测中间元素左右互换
for k, v := range this.Plat {
if v.Color == 0 {
continue
}
if k%Height+2 < Height {
k1 := this.Plat[k].Color
k2 := this.Plat[k+2].Color
pos := k + 1
if k1 == k2 {
if pos/Height+1 < Width { // 右
p := this.Plat[pos+Width].Color
if p == k1 {
bEliminate = true
return
}
}
if pos/Height-1 >= 0 { // 右
p := this.Plat[pos-Width].Color
if p == k1 {
bEliminate = true
return
}
}
}
}
}
if !bEliminate {
fmt.Printf("=====地图数据不能交换===========\n")
this.Debugf()
}
return
}
// 生成一个不能消除的地图
func (this *MapData) SetIndelibilityPlat() {
for k, v := range this.Plat {
if v.Color == 0 {
continue
}
x := int32(k % Height) // x
if x+2 < Height {
k1 := this.Plat[k].Color
k2 := this.Plat[k+1].Color
k3 := this.Plat[k+2].Color
if k1 == k2 && k2 == k3 {
if this.Plat[k+2].Special == 0 {
newId := k + 2
oldId := Total - 1
for i := 0; i < Total; i++ {
if this.Plat[oldId].Color == k3 { // 找到颜色不一样的
if oldId > 0 {
oldId -= 1
}
} else {
break
}
}
tmp := new(pb.GirdeData)
*tmp = *this.Plat[newId]
this.Plat[newId] = this.Plat[oldId]
this.Plat[oldId] = tmp
}
}
}
if k+2*Width < Total {
k1 := this.Plat[k].Color
k2 := this.Plat[k+Width].Color
k3 := this.Plat[k+2*Width].Color
if k1 == k2 && k2 == k3 {
if this.Plat[k+2*Width].Special == 0 { // 找最后一个交换
newId := k + 2*Width
oldId := Total - 1
for i := 0; i < Total; i++ {
if this.Plat[oldId].Color == k3 { // 找到颜色不一样的
oldId -= 1
} else {
break
}
}
tmp := new(pb.GirdeData)
*tmp = *this.Plat[newId]
this.Plat[newId] = this.Plat[oldId]
this.Plat[oldId] = tmp
}
}
}
}
for {
if b, _ := this.Check3X(); b {
fmt.Printf("plat init\n")
if _, xc := this.CheckMap(0, false); !xc {
break
}
} else {
break
}
}
this.Plat = this.GetPalatData()
}
// 重新洗牌
func (this *MapData) RedsetPlatData() {
for i := 0; i < Total-1; i++ {
targetId := comm.GetRandNum(0, Total-1)
if i == int(targetId) {
continue
}
tmp := new(pb.GirdeData)
*tmp = *this.Plat[i]
this.Plat[i] = this.Plat[targetId]
this.Plat[targetId] = tmp
}
this.SetIndelibilityPlat()
}
//四周蔓延 第一次100% 第二次 60% 第三次 30% 第四次 10% 最多4次
func (this *MapData) SkillManYan(pos int32, count int32) (m map[int]struct{}) {
m = make(map[int]struct{}, 0)
var sz []int
var percent int32
var cur []int
// 先找出可以蔓延的方向
x := int(pos / Width)
y := int(pos % Height)
if x-1 >= 0 { // 左
sz = append(sz, (x-1)*Width+(y))
}
if y-1 >= 0 { // 下
sz = append(sz, (x)*Width+(y-1))
}
if y+1 < Height { // 上
sz = append(sz, (x)*Width+(y+1))
}
if x+1 < Width { // 右
sz = append(sz, (x+1)*Width+(y))
}
if count == 0 { // 蔓延技能概率调整支持配置
percent = 100
} else if count == 1 {
percent = 60
} else if count == 2 || count == 3 {
percent = 30
} else {
return
}
szid := utils.RandomNumbers(0, len(sz), 2)
for _, v := range szid {
if percent >= comm.GetRandNum(0, 100) {
m[sz[v]] = struct{}{}
cur = append(cur, sz[v])
}
}
count++
for _, k := range cur {
for k1 := range this.SkillManYan(int32(k), count) { // 递归蔓延
m[k1] = struct{}{}
}
}
return
}
// 获取BoomType 类型周围的所有元素(pos 四周+ 四周的上下左右)
func (this *MapData) GetBoomElem(pos int) (elem []int) {
x := int(pos / Width)
y := int(pos % Height)
if x-1 >= 0 { // 左
elem = append(elem, (x-1)*Width+(y))
}
if y-1 >= 0 { // 下
elem = append(elem, (x)*Width+(y-1))
}
if y+1 < Height { // 上
elem = append(elem, (x)*Width+(y+1))
}
if x+1 < Width { // 右
elem = append(elem, (x+1)*Width+(y))
}
if x-1 >= 0 && y+1 < Height { // 左上
elem = append(elem, (x-1)*Width+(y+1))
}
if x-1 >= 0 && y-1 >= 0 { // 左下
elem = append(elem, (x-1)*Width+(y-1))
}
if x+1 < Width && y+1 < Height { // 右上
elem = append(elem, (x+1)*Width+(y+1))
}
if x+1 < Width && y-1 >= 0 { // 右下
elem = append(elem, (x+1)*Width+(y-1))
}
///
if x-2 >= 0 { // 左左
elem = append(elem, (x-2)*Width+(y))
}
if y-2 >= 0 { // 下下
elem = append(elem, (x)*Width+(y-2))
}
if y+2 < Height { // 上上
elem = append(elem, (x)*Width+(y+2))
}
if x+2 < Width { // 右右
elem = append(elem, (x+2)*Width+(y))
}
return
}
func (this *MapData) GetFireBoom(pos int, itype int32) (elem []int) {
x := int(pos / Width)
y := int(pos % Height)
if itype == FireUp || itype == FireDown || itype == FireLeft || itype == FireRight {
elem = append(elem, pos)
}
switch itype {
case FireUp: //上烟火
for i := 0; i < Height; i++ {
if y+1 < Height { // 上上
elem = append(elem, (x)*Width+(y+1))
y += 1
}
}
case FireDown: //下烟火
for i := 0; i < Height; i++ {
if y-1 >= 0 { // 下下
elem = append(elem, (x)*Width+(y-1))
y -= 1
}
}
case FireLeft: //左烟火
for i := 0; i < Height; i++ {
if x-1 >= 0 { // 左左
elem = append(elem, (x-1)*Width+(y))
x -= 1
}
}
case FireRight: //右烟火
for i := 0; i < Height; i++ {
if x+1 < Width { // 右右
elem = append(elem, (x+1)*Width+(y))
x += 1
}
}
}
return
}
// 特殊类型元素 统一处理
func (this *MapData) SpecialElem(id int, s int32) (x map[int]struct{}) {
if s <= 0 {
return
}
x = make(map[int]struct{})
if s == FourUType { // 4消上下类型
for i := 0; i < Height; i++ { // id 的一条线位置
x[(id/Width)*Height+i] = struct{}{}
}
} else if s == FourLType { // 左右类型
for i := 0; i < Width; i++ { // id 的一条线位置
x[id%Height+i*Width] = struct{}{}
}
} else if s == FiveType { // 随机消除
// 获取配置
if c, _ := this.module.configure.GetGameBlock(this.Plat[id].Color, FiveType); c != nil {
ids := utils.RandomNumbers(0, Total-1, int(c.Value))
for _, v := range ids {
x[v] = struct{}{}
}
}
} else if s == BoomType { // 炸弹类型 带走周围一圈+ 上下左右
for _, key := range this.GetBoomElem(id) {
x[key] = struct{}{}
}
} else if s == FireUp || s == FireDown || s == FireLeft || s == FireRight { // 烟花技能
for _, key := range this.GetFireBoom(id, s) {
x[key] = struct{}{}
}
}
this.Plat[id].Special = 0
x[id] = struct{}{}
for k := range x {
if k == id {
continue
}
if this.Plat[k].Special != 0 {
ids := this.SpecialElem(k, this.Plat[k].Special) // 递归调用
for key := range ids {
x[key] = struct{}{}
}
}
}
return
}
func (this *MapData) HitElem(color int32, curid int32) (szMap []*pb.MapData) {
var energy int32
var curScore int32
if this.Plat[curid].Special == 0 {
if this.Plat[curid].Color == color {
energy++
}
curScore = this.Plat[curid].Score
this.Plat[curid] = &pb.GirdeData{}
if this.DropGirde() {
szMap = append(szMap, &pb.MapData{
Data: this.GetPalatData(),
CurSocre: curScore,
CurEnergy: energy,
})
}
sz, _ := this.CheckMap(color, false)
szMap = append(szMap, sz...)
} else {
x := this.SpecialElem(int(curid), this.Plat[curid].Special)
for id := range x {
if this.Plat[id].Color == color {
energy++
}
curScore += this.Plat[id].Score
this.Plat[id] = &pb.GirdeData{}
this.operElem = append(this.operElem, int32(id))
}
if this.DropGirde() {
szMap = append(szMap, &pb.MapData{
Data: this.GetPalatData(),
CurSocre: curScore,
CurEnergy: energy,
})
}
sz, _ := this.CheckMap(color, false)
szMap = append(szMap, sz...)
}
return
}
func (this *MapData) ShuffleElem() {
for i := 0; i < Total; i++ {
n1, _ := rand.Int(rand.Reader, big.NewInt(Total))
newId := n1.Int64()
if i != int(n1.Int64()) {
tmp := new(pb.GirdeData)
*tmp = *this.Plat[newId]
this.Plat[newId] = this.Plat[i]
this.Plat[i] = tmp
}
}
this.SetIndelibilityPlat()
}
func (this *MapData) HitCrossElem(color int32, curid int32) (szMap []*pb.MapData) {
var (
ids []int // 十字id
energy int32
curScore int32
xc map[int]struct{}
)
x := int(curid / Width)
y := int(curid % Height)
xc = make(map[int]struct{}, 0)
for i := 0; i < Height; i++ { // 上下
if y+i < Height {
ids = append(ids, x*Width+(y+i))
}
if y-i > 0 {
ids = append(ids, x*Width+(y-i))
}
}
for i := 0; i < Height; i++ { // 左右
if x+i < Width {
ids = append(ids, (x+i)*Width+(y))
}
if x-i >= 0 {
ids = append(ids, (x-i)*Width+(y))
}
}
for _, v := range ids {
if this.Plat[curid].Special == 0 {
xc[v] = struct{}{}
} else {
for key := range this.SpecialElem(int(v), this.Plat[v].Special) {
xc[key] = struct{}{}
}
}
}
for id := range xc {
if this.Plat[id].Color == color {
energy++
}
curScore += this.Plat[id].Score
this.Plat[id] = &pb.GirdeData{}
this.operElem = append(this.operElem, int32(id))
}
if this.DropGirde() {
szMap = append(szMap, &pb.MapData{
Data: this.GetPalatData(),
CurSocre: curScore,
CurEnergy: energy,
})
}
return
}
func (this *MapData) checkSp(e []int) (oid int32) {
oid = -1
for _, v := range this.operElem {
for _, v1 := range e {
if v == int32(v1) {
oid = v
break
}
}
}
return
}
// 检测一个元素
func (this *MapData) CheckElem(color int32) (xc [][]int, sp map[int]int) {
var (
w [14][]int32
s1 [][]int // heng
s2 [][]int // shu
)
sp = make(map[int]int)
for pos, v := range this.Plat {
x := pos / Width
y := pos % Height
for i := 0; i < 7; i++ {
if x == i {
if v.Color == color {
w[i+7] = append(w[i+7], v.Color)
} else {
w[i+7] = append(w[i+7], 0)
}
}
if y == i {
if v.Color == color {
w[y] = append(w[y], v.Color)
} else {
w[y] = append(w[y], 0)
}
}
}
}
for i := 0; i < 14; i++ {
var s []int
for j := 0; j < 7; j++ {
if j+4 < 7 { // 5
if w[i][j] != 0 && w[i][j] == w[i][j+1] && w[i][j+2] == w[i][j+3] && w[i][j+3] == w[i][j+4] && w[i][j] == w[i][j+2] { // 1=2 3=4 4=5 1 =3
//5
if i >= 7 {
s = append(s, (i-7)*7+j)
s = append(s, (i-7)*7+j+1)
s = append(s, (i-7)*7+j+2)
s = append(s, (i-7)*7+j+3)
s = append(s, (i-7)*7+j+4)
s1 = append(s1, s)
} else {
s = append(s, (j)*7+i)
s = append(s, (j+1)*7+i)
s = append(s, (j+2)*7+i)
s = append(s, (j+3)*7+i)
s = append(s, (j+4)*7+i)
s2 = append(s2, s)
}
break
}
}
if j+3 < 7 { // 4
if w[i][j] != 0 && w[i][j] == w[i][j+1] && w[i][j+2] == w[i][j+3] && w[i][j] == w[i][j+2] { // 1=2 3=4 1 =3
//4
if i >= 7 {
s = append(s, (i-7)*7+j)
s = append(s, (i-7)*7+j+1)
s = append(s, (i-7)*7+j+2)
s = append(s, (i-7)*7+j+3)
s1 = append(s1, s)
} else {
s = append(s, (j)*7+i)
s = append(s, (j+1)*7+i)
s = append(s, (j+2)*7+i)
s = append(s, (j+3)*7+i)
s2 = append(s2, s)
//oid := this.checkSp(s)
// if 0 < oid {
// sp[int(oid)] = FourLType
// } else {
// sp[(j+1)*7+i] = FourLType
// }
}
break
}
}
if j+2 < 7 { // 3
if w[i][j] != 0 && w[i][j] == w[i][j+1] && w[i][j] == w[i][j+2] { // 1=2 1 =3
//3
if i >= 7 {
s = append(s, (i-7)*7+j)
s = append(s, (i-7)*7+j+1)
s = append(s, (i-7)*7+j+2)
s1 = append(s1, s)
} else {
s = append(s, (j)*7+i)
s = append(s, (j+1)*7+i)
s = append(s, (j+2)*7+i)
s2 = append(s2, s)
}
break
}
}
}
}
for _, v := range s1 {
t, xj, new := CheckInSlice(v, s2) // 横竖相交
if len(t) > 0 {
xc = append(xc, t)
sp[xj] = FiveType
s2 = new[0:][0:]
} else {
if len(v) >= 5 {
sp[v[len(v)/2]] = FiveType
} else if len(v) >= 4 {
oid := this.checkSp(v)
if 0 < oid {
sp[int(oid)] = FourUType
} else {
sp[v[len(v)/2]] = FourUType
}
}
xc = append(xc, v)
}
}
for _, v := range s2 {
if len(v) >= 5 {
sp[v[len(v)/2]] = FiveType
} else if len(v) >= 4 {
oid := this.checkSp(v)
if 0 < oid {
sp[int(oid)] = FourLType
} else {
sp[v[len(v)/2]] = FourLType
}
}
xc = append(xc, v)
}
return
}
func CheckInSlice(s []int, sz [][]int) (si []int, xj int, newMatrix [][]int) {
newMatrix = make([][]int, len(sz))
for i := 0; i < len(sz); i++ {
newMatrix[i] = make([]int, len(sz[0]))
}
copy(newMatrix, sz)
for _, index := range s {
for pos, v := range sz {
bfound := false
for _, vs2 := range v {
if index == vs2 {
bfound = true
xj = index // 相交的点
si = append(si, v...)
si = append(si, s...)
break
}
}
if bfound {
newMatrix = append(newMatrix[:pos], newMatrix[pos+1:]...)
break
}
}
}
return
}
// 将随机6个宝石染成当前盘面上颜色最多的宝石 (count 替换的数量)
func (this *MapData) SkillChangeColor(count int32) {
var (
// 替换成的颜色
color int32
elemCount map[int32]int32
)
elemCount = make(map[int32]int32, 0)
for _, v := range this.Plat {
elemCount[v.Color] += 1
}
for _, v := range elemCount {
if color < v {
color = v
}
}
for k, v := range elemCount {
if color == v {
color = k
break
}
}
for i := 0; i < int(count); i++ {
targetId := comm.GetRandNum(0, Total-1)
if this.Plat[targetId].Color == color {
i--
} else {
if this.Plat[targetId].Special == 0 {
this.Plat[targetId].Color = color // 变更颜色
this.Plat[targetId].Cid = color // 变更颜色
this.oid++
this.Plat[targetId].Oid = this.oid // 变唯一id
}
}
}
return
}