461 lines
11 KiB
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
|
|
}
|