从零开始, 以双向链表实现 运势计算: 运势推算

164 阅读2分钟

本文已参与 「新人创作礼」 活动,一起开启掘金创作之路。

1.0 准备开始

我们先制定一个计算结构体,一切开始于此,我们首先需要知道参与计算的 算子有多少,我们就按最常用的数49来制定

type DataTao struct {
    DefMean    map[int]string // 卦象坐标名称
    DefValue   map[int]string // 卦象坐标值 4个
    GuaData    []int          // 卦象的 6爻初始值
    Indent     int            // 格式化输出间隔
    Env        int            // 影响偏差,Env 把一年分为 3个部分,每个部分4个月,这个值可以影响天地分开的比例,自己随意
    Total      int            // 大衍之数 个数
    PrintLevel int            // 计算过程显示控制,如果为 1 则显示
    Coordinate map[int]string //卦象坐标的 爻,古称
}

制作该计算对象的构造函数

    /*
    @param env 环境参数
    @param indent 格式化输出的缩进
    @param total 天地 大衍数 49
    */
    func MakeNewDataTao(env string, indent, total int) *DataTao {
        envNum := map[string]int{"A": 1, "B": 0, "C": 2}
        guaCoor := map[int]string{6: "六", 7: "七", 8: "八", 9: "九"}

        var envLevel = 0

        if indent <= 0 {
            indent = 8
        }

        if env != "" {
            envLevel = envNum[env]
        }

        if total < 49 {
            total = 49
        }

        newData := &DataTao{
            DefMean:    defMean,
            DefValue:   guaCoor,
            GuaData:    []int{},
            Indent:     indent,
            Env:        envLevel,
            Total:      total,
            PrintLevel: envNum["A"],
            Coordinate: Coordinates,
        }
        return newData
    }

1.1 开天辟地,创建爻变

创建天地大衍之数
// 创建一个新的天地列表 大衍之数,使用49
func (dt *DataTao) NewCircle() []int {
    var newCir []int
    for i := 0; i < dt.Total; i++ {
        newCir = append(newCir, i)
    }
    return newCir
}

由于每一变 除以4的余数可能为 0,此时需要拿走4个算子,所以,3变最多需要12个算子,而分天地,

//默认随机算法   计算后 将其值 限定为下限 12,上限 37
func (dt *DataTao) SplitNum(topNum int) int {
    /*
        Seed 使用提供的种子值将生成器初始化为确定性状态。
        Seed 不应与任何其他 Rand 方法同时调用。
    */
    rand.Seed(time.Now().UnixNano())
    top := topNum - 4
    sn := rand.Intn(top) + 4 // A random int in [4, 45]

    if dt.Env != 0 {
        if dt.Env == 1 {
            sn = sn + (dt.Env * 3)
        } else {
            sn = sn + (dt.Env * 2)
        }

    }
    if sn < 4 {
        sn = 4
    }

    if sn > topNum - 4 {
        sn = topNum - 4
    }

    logger.Printf("outcome sn:%v with topNum:%v\n", sn, topNum)
    return sn
}

1.1.1 创建爻变,得到三才

从天,地随机选择一方,拿出一个算子 作为天地人的 人才
// 分三才 从选定的一方 得一人
func (dt *DataTao) RandLis(lis []int) ([]int, int) {

    rand.Seed(time.Now().UnixNano())
    if len(lis) < 2 {
        return lis, 0
    }
    t := rand.Intn(len(lis) - 1)
    ren := lis[t]
    lis = append(lis[:t], lis[t+1:]...)
    return lis, ren

}

推算的主要过程就是爻变的操作,每一爻都需要有3次爻变,最后得出一爻,我们先实现一变 //做一变

/*
@param: lis, 天地混沌,需要分开的算子集合
@param: sn, 从算子集合的哪一个位置执行分开
// 做一变,为得一爻
*/
func (dt *DataTao) DoOneYao(lis []int, sn int) []int {

    //分天地
    tian := lis[:sn]
    di := lis[sn:]

    var ran int
    //从天地 取一人
    rand.Seed(time.Now().UnixNano())
    r := rand.Intn(2)
    if r == 0 {
        tian, ran = dt.RandLis(tian)
    } else {
        di, ran = dt.RandLis(di)
    }

    //一变
    var tia, d, newOrigin []int
    xt := len(tian) % 4
    if xt == 0 {
        //取 4个
        tia = tian[:4]
        tian = tian[4:]
    } else {
        tia = tian[:xt]
        tian = tian[xt:]
    }

    dtv := len(di) % 4
    if dtv == 0 {
        d = di[:4]
        di = di[4:]
    } else {
        d = di[:dtv]
        di = di[dtv:]
    }

    //返回一变
    newOrigin = append(tia, d...)
    newOrigin = append(newOrigin, ran)

    if dt.Env == dt.PrintLevel {
        SixYao = append(SixYao, newOrigin)
        logger.Println("余天:", tian, "\n余地:", di, "\n变数:", newOrigin, "人才:", ran, "\n新天地:", len(tian)+len(di))
        logger.Println("已变总数:", len(SixYao))
    }
    newDT := append(tian, di...)
    return newDT
}

每一个爻都需要对 天地大衍之数做三变,最后剩下的算子数 除以4 就是 一爻,算6次爻 那么就是一卦

// 连续三变 得一爻,返回新天地
func (dt *DataTao) TianDiYao(lis []int) ([]int, int) {
    /*
            分天地 进行 变一
                :param lis:
                :param sn:
                :return:  最后的 天,地,归档人列表, 和 爻 值
    */
    finalTiandi := lis
    for _, k := range []int{1, 2, 3} {
        if dt.Env == dt.PrintLevel {
            logger.Println("第", k, "变")
        }
        finalTiandi = dt.DoOneYao(finalTiandi, dt.SplitNum(len(finalTiandi)))
    }

    yao := len(finalTiandi) / 4
    if dt.Total > 49 {
        db := dt.Total / 49
        yao := yao / db
        if dt.Env == dt.PrintLevel {
            logger.Println("大衍之数:", dt.Total, "三变后的爻:", yao, "距离 倍数 db:", db, "新天地:", len(finalTiandi))
        }

    }
    if dt.Env == dt.PrintLevel {
        logger.Println("三变后的爻:", yao)
    }
    return finalTiandi, yao
}

1.1.2 创建爻变, 得到6爻 即一卦 计算6个爻 则需要 3变 6次,并使用双向链表保存结果

// 推演函数,开天辟地,并计算6爻
func (dt *DataTao) SuanGua() *dlist {
    // gua := []int{}
    logger.Printf("开始占卜运势...")
    for i := 1; i < 7; i++ {
        nc := dt.NewCircle()
        if dt.Env == dt.PrintLevel {
            logger.Println(len(nc), nc, dt.SplitNum(len(nc)))
        }
        ///分天地人
        ft, y := dt.TianDi(nc)
        if dt.Env == dt.PrintLevel {
            logger.Println("新天地:", ft)
            logger.Println(dt.Coordinate[i]+dt.DefValue[y], "\n第", i, "爻", y, dt.DefMean[y])
        }
        time.Sleep(time.Millisecond * 100)
        // gua = append(gua, y)
        ResultNodes.append(&node{number: y})
    }
    return ResultNodes
}

结语

本小节 我们实现了推演运势的过程,在下一小节,我们将实现对链表的数据读取 和 爻象的解读。

本文已参与 「新人创作礼」 活动,一起开启掘金创作之路。