game_sync/gamesrv/slotspkg/slots/entity/node.go

461 lines
11 KiB
Go

package entity
import (
"mongo.games.com/game/gamesrv/slotspkg/internal/exported/excel2go/structs"
"mongo.games.com/game/gamesrv/slotspkg/internal/generic/errors"
"mongo.games.com/game/gamesrv/slotspkg/internal/generic/key"
"mongo.games.com/game/gamesrv/slotspkg/internal/module/shared"
"mongo.games.com/goserver/core/logger"
"strconv"
)
const (
// WalkRootFirst walks root first, recurses from root
WalkRootFirst int64 = 1
// WalkRootLast walks root last, recurses from farest leaf
WalkRootLast int64 = 2
)
// GetNode finds node by nodeID
func (e *Entity) GetNode(nodeID int64) *shared.Node {
for _, node := range e.NodeTree.Nodes {
if node.ID == nodeID {
return node
}
}
panic(errors.NodeNotFound.ErrorWith(strconv.FormatInt(nodeID, 10)))
}
// IsEmpty returns if the NodeTree is empty
func (e *Entity) IsEmpty() bool {
return len(e.NodeTree.Nodes) == 0
}
// IsClosing returns if node is in `NodeTree.Closing` slice
func (e *Entity) IsClosing(node *shared.Node) bool {
for _, closed := range e.NodeTree.Closing {
if node.ID == closed {
return true
}
}
return false
}
// CursorNode returns the `Cursor` node in `NodeTree`
func (e *Entity) CursorNode() *shared.Node {
return e.GetNode(e.NodeTree.Cursor)
}
// NextNode returns the `Next` node in `NodeTree`
func (e *Entity) NextNode() *shared.Node {
return e.GetNode(e.NodeTree.Next)
}
// RootNode returns the `Root` node in `NodeTree`
func (e *Entity) RootNode() *shared.Node {
return e.GetNode(e.NodeTree.Root)
}
// ParentNode returns the `Parent` node of `Cursor` node in `NodeTree`
func (e *Entity) ParentNode() *shared.Node {
return e.GetNode(e.GetNode(e.NodeTree.Cursor).Parent)
}
// AncestorNode returns the `Ancestor` Node of `Cursor` Node in `NodeTree`
func (e *Entity) AncestorNode() *shared.Node {
switch e.CursorNode().Type {
case key.BaseSpin, key.FreeSpin, key.Root:
return e.RootNode()
default:
return e.recursiveGetAncestor(e.CursorNode())
}
}
func (e *Entity) recursiveGetAncestor(node *shared.Node) *shared.Node {
node = e.GetNode(node.GetParent())
nodeType := node.GetType()
switch nodeType {
case key.BaseSpin, key.FreeSpin, key.Root:
return node
default:
return e.recursiveGetAncestor(node)
}
}
// ClosingNodes returns the `Closing` node in `NodeTree`
func (e *Entity) ClosingNodes() []*shared.Node {
closingNodes := make([]*shared.Node, len(e.NodeTree.Closing))
for i, closing := range e.NodeTree.Closing {
closingNodes[i] = e.GetNode(closing)
}
return closingNodes
}
// InitRootNode add root node to node tree
func (e *Entity) InitRootNode() int64 {
ID := e.NodeTree.Incr
e.NodeTree.Cursor = ID
e.NodeTree.Next = ID
e.NodeTree.Root = ID
e.NodeTree.Nodes = append(e.NodeTree.Nodes, &shared.Node{
ID: ID,
Parent: ID,
Children: make([]int64, 0),
Type: key.Root,
Formations: make([]*shared.Formation, 0),
Features: make([]*shared.Feature, 0),
})
return ID
}
func (e *Entity) InitAct() {
e.NodeTree.Act = &shared.Act{
BetSizeIndex: 0,
BetLevelIndex: 0,
BetLineIndex: 0,
Ratio: 1,
}
FirstBet := e.Shell.DataSet.GetMachineSheet(e.Theme, "Bet", "FirstBet", 0)
if FirstBet != nil {
FirstBetMap := FirstBet.(map[int64]*structs.FirstBet)
e.NodeTree.Act.BetSizeIndex = FirstBetMap[1].BetSizeIndex
e.NodeTree.Act.BetLevelIndex = FirstBetMap[1].BetLevelIndex
}
}
func (e *Entity) UpdateAct(act *shared.Act) {
e.NodeTree.Act = act
}
func (e *Entity) addChildNodeBySide(parent int64, typ string,
progress int64, rightSide bool) *shared.Node {
if progress == 0 {
panic(errors.NewNodeZeroProgress.Error())
}
e.NodeTree.Incr++
nodeID := e.NodeTree.Incr
parentNode := e.GetNode(parent)
if rightSide {
parentNode.Children = append(parentNode.Children, nodeID)
} else {
parentNode.Children = append([]int64{nodeID}, parentNode.Children...)
}
formations := make([]*shared.Formation, 0)
spinType := e.MachineDesc.GetSpinType(typ)
formationSeqDescs := e.NodeDesc.GetFormationSeqDescs(typ)
for _, desc := range formationSeqDescs {
formation := &shared.Formation{
SpinType: desc.SpinType,
ID: desc.ID,
NodeType: desc.NodeType,
SeqID: desc.SeqID,
NodeID: nodeID,
}
formations = append(formations, formation)
}
node := &shared.Node{
ID: nodeID,
Parent: parent,
Children: make([]int64, 0),
Type: typ,
SpinType: spinType,
Formations: formations,
Features: make([]*shared.Feature, 0),
Bet: parentNode.Bet,
ProgressMax: progress,
NeedPrepare: false,
Prepared: false,
}
e.NodeTree.Nodes = append(e.NodeTree.Nodes, node)
return node
}
// AddChildNode add new node to node tree
func (e *Entity) AddChildNode(parent int64, typ string,
progress int64) *shared.Node {
return e.addChildNodeBySide(parent, typ, progress, true)
}
// AddChildNode add new node to node tree
func (e *Entity) AddChildNodeAtLeft(parent int64, typ string,
progress int64) *shared.Node {
return e.addChildNodeBySide(parent, typ, progress, false)
}
// UpdateNode2NewType update cursor to new node
func (e *Entity) UpdateNode2NewType(nodeId int64, typ string, progress int64) *shared.Node {
node := e.GetNode(nodeId)
if node == nil {
logger.Logger.Errorf("UpdateNode2NewType err: node == nil nodeid=(%v)", nodeId)
return nil
}
node.Type = typ
node.SpinType = e.MachineDesc.GetSpinType(typ)
node.ProgressMax = progress
node.NoBase = true
e.NextNodeDesc = e.GetNodeDesc(node)
e.PrepareNextOriginFormations()
formations := make([]*shared.Formation, 0)
formationSeqDescs := e.NodeDesc.GetFormationSeqDescs(typ)
for _, desc := range formationSeqDescs {
formation := &shared.Formation{
SpinType: desc.SpinType,
ID: desc.ID,
NodeType: desc.NodeType,
SeqID: desc.SeqID,
NodeID: node.ID,
}
formations = append(formations, formation)
}
node.Formations = formations
return node
}
// PruneNode prunes a node from tree
func (e *Entity) PruneNode(node *shared.Node) {
for _, child := range node.Children {
childNode := e.GetNode(child)
e.PruneNode(childNode)
}
parentNode := e.GetNode(node.Parent)
for index, child := range parentNode.Children {
if child == node.ID {
parentNode.Children = append(parentNode.Children[:index],
parentNode.Children[index+1:]...)
break
}
}
for index, n := range e.NodeTree.Nodes {
if n.ID == node.ID {
e.NodeTree.Nodes = append(e.NodeTree.Nodes[:index],
e.NodeTree.Nodes[index+1:]...)
break
}
}
}
// Walk walks all nodes in node tree
// return true means stopping right now; false means continuing
func (e *Entity) Walk(f func(node *shared.Node) bool) bool {
for _, node := range e.NodeTree.Nodes {
if f(node) {
return true
}
}
return false
}
// WalkTree walks nodes from root node
func (e *Entity) WalkTree(direction int64, f func(node *shared.Node) bool) bool {
return e.WalkTreeNode(e.RootNode(), direction, f)
}
// WalkTreeNode walks nodes from parent node
// return true means stopping right now; false means continuing
func (e *Entity) WalkTreeNode(
node *shared.Node,
direction int64,
f func(node *shared.Node) bool,
) bool {
switch direction {
case WalkRootFirst:
if f(node) {
return true
}
for _, child := range node.Children {
childNode := e.GetNode(child)
if e.WalkTreeNode(childNode, direction, f) {
return true
}
}
case WalkRootLast:
for _, child := range node.Children {
childNode := e.GetNode(child)
if e.WalkTreeNode(childNode, direction, f) {
return true
}
}
if f(node) {
return true
}
}
return false
}
// GetChildrenNodes gets children nodes of one nodes
func (e *Entity) GetChildrenNodes(node *shared.Node) []*shared.Node {
nodes := make([]*shared.Node, 0)
for _, childNodeID := range node.Children {
nodes = append(nodes, e.GetNode(childNodeID))
}
return nodes
}
// MustNext must return a node
// add a new node if all nodes is accomplished
func (e *Entity) MustNext() {
if next := e.Next(); next != nil {
if !e.CheatNextNodeOnMustNext() {
e.NodeTree.Next = next.ID
}
return
}
e.AddChildNode(e.NodeTree.Root, key.BaseSpin, 1)
if next := e.Next(); next != nil {
e.NodeTree.Next = next.ID
return
}
panic(errors.NextNodeNotFound.Error())
}
// Next finds Next node in `NodeTree`
func (e *Entity) Next() *shared.Node {
node := e.CursorNode()
e.NodeTree.Closing = make([]int64, 0)
if next := e.nextChildren(node); next != nil {
return next
}
if next := e.nextSelf(node); next != nil {
return next
}
if next := e.nextParent(node); next != nil {
return next
}
return nil
}
// nextChildren finds node in children that is not accomplished
func (e *Entity) nextChildren(node *shared.Node) (next *shared.Node) {
for _, child := range node.Children {
childNode := e.GetNode(child)
if e.IsClosing(childNode) { // Forbid repeated `next`.
continue
}
if next := e.nextChildren(childNode); next != nil {
return next
}
if next := e.nextSelf(childNode); next != nil {
return next
}
}
return nil
}
// nextSelf finds node in self node that is not accomplished
func (e *Entity) nextSelf(node *shared.Node) (next *shared.Node) {
if e.IsClosing(node) { // Forbid repeated `next`.
return nil
}
if e.IsFinished(node) {
e.NodeTree.Closing = append(e.NodeTree.Closing, node.ID)
return nil
}
return node
}
// nextParent recursively next every node below this node,
// including all descendents.
func (e *Entity) nextParent(node *shared.Node) (next *shared.Node) {
if node.ID == 0 || node.Type == key.Root {
return nil
}
nodeParent := e.GetNode(node.Parent)
if nodeParent == nil {
panic(errors.NodeNotFound.Error())
}
if next := e.nextChildren(nodeParent); next != nil {
return next
}
if next := e.nextSelf(nodeParent); next != nil {
return next
}
if next := e.nextParent(nodeParent); next != nil {
return next
}
return nil
}
// MoveNext move `Cursor` to `Next` when receive a request
func (e *Entity) MoveNext() {
e.PruneNodeFeatures(e.CursorNode())
if !e.CheatNextNodeOnMoveNext() {
e.NodeTree.Cursor = e.NodeTree.Next
}
e.PruneNodeFeatures(e.CursorNode())
for _, closingNode := range e.ClosingNodes() {
e.PruneNode(closingNode)
}
}
func (e *Entity) RecheckClosing() {
closing := make([]int64, len(e.NodeTree.Closing))
copy(closing, e.NodeTree.Closing)
e.NodeTree.Closing = make([]int64, 0)
for _, nodeID := range closing {
node := e.GetNode(nodeID)
if next := e.nextChildren(node); next != nil {
continue
}
if next := e.nextSelf(node); next != nil {
continue
}
}
}
func (e *Entity) CheatNextNodeOnMoveNext() bool {
v, ok := e.Data[key.MachineNextNodeID]
if !ok {
return false
}
nodeID := v.(int64)
if nodeID == 0 {
return false
}
e.NodeTree.Cursor = nodeID
e.NodeTree.Next = nodeID
e.RecheckClosing()
delete(e.Data, key.MachineNextNodeID)
return true
}
func (e *Entity) CheatNextNodeOnMustNext() bool {
v, ok := e.Data[key.MachineNextNodeID]
if !ok {
return false
}
nodeID := v.(int64)
if nodeID == 0 {
return false
}
e.NodeTree.Next = nodeID
delete(e.Data, key.MachineNextNodeID)
return true
}
func (e *Entity) PrepareStep() {
e.NodeTree.Step = e.NodeTree.Step + 1
}