角色培养问题

某游戏的角色强弱由武力,统率,智力,敏捷和运气这五个指标决定。该游戏会出现十三个特殊情景,每当进入这些情景玩家就会面临多个选择并需要从中挑选一个出来。根据游戏的攻略,每一个选项都会对某角色的武力,统率,智力,敏捷和运气产生不同程度的影响,具体的数据如下图所示:

现要求计算出每一个组合的路径图以及对五围的累计影响,如下图所示:

从直觉出发,这个问题应该使用Table.AddColumn()或者List.TransformMany()产生笛卡尔积进行解答。遗憾的是, 即使只有十三个情景, 采用这种思路进行解题的运行时间会长得令人难以接受。因此,有必要从另一个角度理解这个问题:从游戏的角度出发,每一个情景的出现实际上是有先后的次序。如果我们把先后的次序理解为一种从属的关系(比如:情景二从属于情景一,情景三从属于情景二,如此类推),不难发现应该借鉴BOM树形结构分解(详情请查阅施阳老师同标题的文章)的思路进行解题。为了方便进行分步解释,问题会暂时化简为只有两个特殊情景,并为了与最终答案保持一致,会保留一些多余的步骤。第一步,需要定义如下常数串列:

    
    Constant_List =
        {
            "武力",
            "统率",
            "智力",
            "敏捷",
            "运气"
        }

第二步,需要把武力,统率,智力,敏捷和运气这五列通过Table.CombineColumnsToRecord()转化为内嵌的记录:

    
    Columns_To_Record =
        Table.CombineColumnsToRecord(
            Dataset,
            "nList",
            Constant_List
        )

第三步,需要通过Table.TransformColumns()把内嵌的记录转化为内嵌的复合串列:

    Record_To_nList =
        Table.TransformColumns(
            Columns_To_Record,
            {
                "nList",
                each {Record.ToList(_)},
                type list
            }
        )

第四步,把情景一的选择分离出来并更改部分列名:

    fScenario =
        Table.RenameColumns(
            Table.SelectRows(
                Record_To_nList,
                each [情景] = 1
            ),
            {
                {
                    "选项",
                    "路径"
                },
                {
                    "nList",
                    "五围"
                }
            }
        )

第五步,把其他情景的选项分离出来:

    oScenario =
        Table.SelectRows(
            Record_To_nList,
            each [情景] ˃ 1
        )

第六步,通过Table.AddColumn()为大于1的情景计算出上一情景:

    Previous_Scenarios =
        Table.AddColumn(
            oScenario,
            "上一情景",
            each [情景] - 1,
            Int64.Type
        )

第七步,以内连接把第六步所得的表格与第四步所得的表格连接起来, 匹配的行会以表格的形式内嵌于nTable列:

    InnerJoin =
        Table.NestedJoin(
            Previous_Scenarios,
            "上一情景",
            fScenario,
            "情景",
            "nTable",
            JoinKind.Inner
        )

第八步,展开nTable列中的部分列并为这些列更改名字:

    Expansion =
        Table.ExpandTableColumn(
            InnerJoin,
            "nTable",
            {
                "路径",
                "五围"
            },
            {
                "上一路径",
                "上一五围"
            }
        )

第九步,计算路径图:

    Add_Path =
        Table.AddColumn(
            Expansion,
            "路径",
            each
                Text.Combine(
                    {
                        [上一路径],
                        [选项]
                    },
                    "|"
                ),
            type text
        )

第十步,通过List.Combine()组合当前的五围数据与之前的五围数据:

    Add_Summation =
        Table.AddColumn(
            Add_Path,
            "五围",
            each
                List.Combine(
                    {
                        [上一五围],
                        [nList]
                    }
                ),
            type list
        )

第十一步,通过Table.SelectColumn()移除情景,路径和五围之外的列。

    RemoveCols =
        Table.SelectColumns(
            Add_Summation,
            {
                "情景",
                "路径",
                "五围"
            }
        )

第十二步,利用List.Zip()实现行列转换后计算对五围的累计影响并转化结果为内嵌的记录:

    TransCol =
        Table.TransformColumns(
            RemoveCols,
            {
                "五围",
                (x)=˃
                    Record.FromList(
                        List.Transform(
                            List.Zip(
                                x
                            ),
                            (y)=˃ List.Sum(y)
                        ),
                        Constant_List
                    ),
                type record
            }
        )

第十三步,展开内嵌记录中的所有字段:

Expand_Records =
    Table.ExpandRecordColumn(
        TransCol,
        "五围",
        Constant_List
    )

第十四步,移除情景列:

    RemoveCol =
        Table.RemoveColumns(
            Expand_Records,
            "情景"
        )

第十五步,修改新列的数据类型:

    DataType =
        Table.TransformColumnTypes(
            RemoveCol,
            List.Zip(
                {
                    Constant_List,
                    List.Repeat(
                        {Int64.Type},
                        List.Count(Constant_List)
                    )
                }
            )
        )

回到原来十三个情景的问题上,只需要利用List.Accumulate()重复以上的第七到第十一步就可以完成解答,完整代码如下:

let
    Constant_List =
        {
            "武力",
            "统率",
            "智力",
            "敏捷",
            "运气"
        },
        
    Columns_To_Record =
        Table.CombineColumnsToRecord(
            Dataset,
            "nList",
            Constant_List
        ),

    Record_To_nList =
        Table.TransformColumns(
            Columns_To_Record,
            {
                "nList",
                each {Record.ToList(_)},
                type list
            }
        ),

    fScenario =
        Table.RenameColumns(
            Table.SelectRows(
                Record_To_nList,
                each [情景] = 1
            ),
            {
                {
                    "选项",
                    "路径"
                },
                {
                    "nList",
                    "五围"
                }
            }
        ),

    oScenario =
        Table.SelectRows(
            Record_To_nList,
            each [情景] ˃ 1
        ),

    Previous_Scenarios =
        Table.AddColumn(
            oScenario,
            "上一情景",
            each [情景] - 1,
            Int64.Type
        ),

    Grouping =
        Table.Group(
            Previous_Scenarios,
            "情景",
            {
                "nTable",
                each _,
                type table
                    [
                        情景 = Int64.Type,
                        选项 = text,
                        nList = list,
                        上一情景 = Int64.Type
                    ]
            }
        ),
    
    Acc_Process =
        List.Accumulate(
            Table.Column(
                Grouping,
                "nTable"
            ),
            fScenario,
            (x, y)=˃
                let
                    InnerJoin =
                        Table.NestedJoin(
                            y,
                            "上一情景",
                            x,
                            "情景",
                            "nTable",
                            JoinKind.Inner
                        ),
                    
                    Expansion =
                        Table.ExpandTableColumn(
                            InnerJoin,
                            "nTable",
                            {
                                "路径",
                                "五围"
                            },
                            {
                                "上一路径",
                                "上一五围"
                            }
                        ),

                    Add_Path =
                        Table.AddColumn(
                            Expansion,
                            "路径",
                            each
                                Text.Combine(
                                    {
                                        [上一路径],
                                        [选项]
                                    },
                                    "|"
                                ),
                            type text
                        ),

                    Add_Summation =
                        Table.AddColumn(
                            Add_Path,
                            "五围",
                            each
                                List.Combine(
                                    {
                                        [上一五围],
                                        [nList]
                                    }
                                ),
                            type list
                        ),

                    RemoveCols =
                        Table.SelectColumns(
                            Add_Summation,
                            {
                                "情景",
                                "路径",
                                "五围"
                            }
                        )
                in
                    RemoveCols
        ),

    TransCol =
        Table.TransformColumns(
            Acc_Process,
            {
                "五围",
                (x)=˃
                    Record.FromList(
                        List.Transform(
                            List.Zip(
                                x
                            ),
                            (y)=˃ List.Sum(y)
                        ),
                        Constant_List
                    ),
                type record
            }
        ),

    Expand_Records =
        Table.ExpandRecordColumn(
            TransCol,
            "五围",
            Constant_List
        ),

    RemoveCol =
        Table.RemoveColumns(
            Expand_Records,
            "情景"
        ),

    DataType =
        Table.TransformColumnTypes(
            RemoveCol,
            List.Zip(
                {
                    Constant_List,
                    List.Repeat(
                        {Int64.Type},
                        List.Count(Constant_List)
                    )
                }
            )
        )
in
    DataType

玩到一半我发现攻略里提到如果想让角色得到完美的培养,最后五个选项必须为2,2,1,1,1,并且武力和运气要大于等于50,而统率要大于等于40。对计算出的结果进行筛选,发现要实现完美培养只有一种组合根本没有容错的空间,所以只能开新档重玩了

附件

2 Replies to “角色培养问题”

  1. 歪楼问个很基础的问题 合并excel文档查询怎么添加一列 让这一列显示的是这个excel文件的名称呢?(举个例子下载了三个产品的数据指标,每个产品对应的excel文件只能通过文件名判断这是那个产品,但是里面内容没有产品标识,在利用excel的合并查询时,如何添加一列,使得每个产品数据文档前面增加一列作为产品名称,这个产品名称就是产品excel文件的名称)似乎表述的不太清晰

    1. 不知道你需要的是不是这种效果:
      let
      Source = Folder.Files("D:\OneDrive\PQ Fans\Reply\Reply 1\Data Folder"),

      Trans_Col =
      Table.TransformColumns(
      Source,
      {
      {
      "Content",
      (x)=>
      Table.SelectRows(
      Excel.Workbook(
      x,
      true
      ),
      (y)=> y[Name] = "Tbl"
      ){0}[Data]
      },
      {
      "Name",
      each Text.Split(_, "."){0},
      type text
      }
      }
      ),

      Col_Selection =
      Table.SelectColumns(
      Trans_Col,
      {
      "Content",
      "Name"
      }
      ),

      Expansion =
      Table.ExpandTableColumn(
      Col_Selection,
      "Content",
      {
      "No"
      }
      )

      in
      Expansion

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注