用 Bitmap 與 AST 做一個配置化時長系統

本文通過編故事的方式講解 bitmap&AST 的一個應用場景。這個故事發生在一個網絡遊戲公司裏面,主要登場人物

左邊:導師,名字不重要

右邊:實習生,三多

三多在一家遊戲公司做實習生,一天下午他正在划水,被導師叫了過去:

三多心裏罵娘,但是一想到自己下個月又得交房租了,還是滿含淚水打開了需求文檔,需求文檔大概的意思如下:

三多開始一邊薅頭髮,一邊設計系統,幹到晚上 12 點,搞出了第一版系統架構圖:

其中 DB 表的 schema 爲:

dMILBr

於是三多第二天給導師看設計:

於是三多重新設計了技術方案:

三多把技術方案設計好後,就開始寫代碼,然後項目上線,一切順利,直到幾天後...

三多導師隨便抄起傢伙畫了個圖然後丟給三多讓他去實現:


於是三多實現了這套時長系統,由於系統能力非常靈活,老闆讓 PM 配置了一些非常複雜的時長表達式,被玩家們賜予了親切的稱號:耍猴公司~

下面這段代碼是個 AST 的最小 demo,有興趣的讀者可以看看:

package main

import (
 "fmt"
 "reflect"
 "strconv"
 "strings"
)

const (
 Number   = 0
 Operator = 1
)

type Node struct {
 Type  int
 Value string
 Left  *Node
 Right *Node
}

// input: 1 + 4 - 2
// result:
//     -
//        /   \
//     +  2
//      /   \
//    1  4
func getAst(expr string) *Node {

 operator := make(map[string]int)
 operator["+"] = Operator
 operator["-"] = Operator

 nodeList := make([]Node, 0)
 var root *Node

 expr = strings.Trim(expr, " ")
 words := strings.Split(expr, " ")
 for _, word := range words {

  var node Node

  if _, ok := operator[word]; ok {
   node.Type = Operator
  } else {
   node.Type = Number
  }
  node.Value = word
  nodeList = append(nodeList, node)
 }

 for i := 0; i < len(nodeList); i++ {
  if root == nil {
   root = &nodeList[i]
   continue
  }

  switch nodeList[i].Type {
  case Operator:
   nodeList[i].Left = root
   root = &nodeList[i]
  case Number:
   root.Right = &nodeList[i]
  }
 }

 return root
}

func getResult(node *Node) string {
 switch node.Type {
 case Number:
  return node.Value
 case Operator:
  return calc(getResult(node.Left), getResult(node.Right), node.Value)
 }
 return ""
}

func calc(left, right string, operator string) string {
 leftVal, _ := TransToInt(left)
 rightVal, _ := TransToInt(right)
 val := 0
 switch operator {
 case "+":
  val = leftVal + rightVal
 case "-":
  val = leftVal - rightVal
 }
 return TransToString(val)
}


func main() {
 expr := `1 + 4 - 2 + 100 - 20 + 12 `
 //expr := ` 1 + 4 `

 ast := getAst(expr)
 result := getResult(ast)

 fmt.Println(result)
}

func TransToString(data interface{}) (res string) {
 val := reflect.ValueOf(data)
 return strconv.FormatInt(val.Int(), 10)
}

func TransToInt(data interface{}) (res int, err error) {
 return strconv.Atoi(strings.TrimSpace(data.(string)))
}

歡迎加我的個人微信:709834997。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/th5HgpibwZkRlj1EzxmMTw