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 }