【问题标题】:Recursion pattern to find root items递归模式查找根项目
【发布时间】:2018-02-24 19:41:21
【问题描述】:

我正在尝试找出一种方法来查找根项及其相关性。

就我而言,我有一个游戏的“可制作物品”列表。

例如:

  • 原木
  • 木板
  • 木墙

所有这些项目都有所谓的parentschildren。 这些是包含itemID 的简单元组数组(我可以将其转换为实际的Item 对象和amount 值。

例如:

typealias ParentTuple = (id: Int, amount: Float)
typealias ChildrenTuple = (id: Int, amount: Float)

var woodLog = Item(id: 1,
                   name: "Wood Log",
                   parents: [],
                   children: [ChildrenTuple(id: 2, amount: 2)]
                   )

var woodPlank = Item(id: 2,
                     name: "Wood Plank",
                     parents: [ParentTuple(id: 1, amount: 0.5)],
                     children: [ChildrenTuple(id: 3, amount: 4)]
                     )

var woodStick = Item(id: 3,
                     name: "Wood Stick",
                     parents: [ParentTuple(id: 2, amount: 0.25)],
                     children: []
                     )

如您所见,一根原木可以制作 2 个木板,而您需要 0.5 个原木才能制作 1 个木板。 (当然,稍后我会将每个值限制为下一个完整整数)。

因此,按照 1 个原木的逻辑,您应该能够制作 8 个木棍。

  • 1x 原木 ->
  • 2x 木板 ->
  • 8x 木棒

现在我需要知道的是,如果我想以制作 32 根木棒为例,我需要多少原木?

我设法递归地返回了一个项目的所有rootItems(没有任何parents的项目)的列表,如下所示:

func rootItems() -> [ParentTuple] {
    guard self.isCraftable else { return [ParentTuple(self.id, amount: 1)] }

    var rootItems = [ParentTuple]()

    for (_, parentTuple) in self.parentIDs.enumerated() {
        guard let parentItem = Item.item(forID: parentTuple.id) else {
            assertionFailure()
            return [ParentTuple(self.id, amount: 1)]
        }
        if parentItem.isRootItem {
            rootItems.append(ParentTuple(id: parentTuple.id, amount: parentTuple.amount))
        } else {
            rootItems.append(contentsOf: parentItem.rootItems())
        }
    }

    return rootItems
}

这很好用。我只是坚持如何让amount 工作。 理论上,对于每个递归调用,我只需要将当前的 parentTuple.amount 与下一个相乘(在我们的示例中:0.25 * 0.5 = 0.125 --> 1/8 Wood Log for 1 Wood Branch)

我的模型可能不适合该任务吗,我是否遗漏了什么?

【问题讨论】:

    标签: swift recursion computer-science


    【解决方案1】:

    我会以不同的方式处理这个问题。这是伪代码来说明

    class Item {
        id : int?
        name : String?
        tier : Int?
        material : String?
    }
    

    然后,当您定义 WoodLogWoodPlankWoodStick 时,您可以分配 IDtiermaterial,然后您可以从 tier 级别处理计算。添加material 还可以让您以最少的工作拥有更多相同materialtier 的项目,并轻松与其他项目进行比较,以确保您可以使用它们进行拆卸或创建。

    func calcDismantleEfficiency(_ itemToMake: Item, _ itemToDismantle: Item) -> Int? {
        // array to get result based on tiers
        // the indices of tierArray are the itemToDismantle.tier
        // the subindices are the itemToMake.tier
        let tierArray = [[0,1,2,8,32...],
                         [0,0,1,4,16]...]
        if itemToDismantle.material == itemToMake.material {
             return tierArray[itemToDismantle.tier][itemToMake.tier] as! Int
        } else { return nil }
    
    }
    

    因此,如果您调用 calcDismantleEfficiency(WoodStick,WoodLog),它将返回 8。

    func calculateCost(_ itemToMake: Item, _ itemToDismantle: Item, _ countToMake: Int ) -> Int? {
        if let efficiency = calcDismantleEfficiency(iteToMake, itemToDismantle) {
            if countToMake % efficiency == 0 {
                return countToMake / efficiency
            } else { return (countToMake / efficiency) + 1
        } else { return nil }
    }
    

    所以如果你调用 calculateCost(WoodStick, WoodLog, 64) 它应该返回 8

    顺便说一句,我没有编译或测试任何这些。这都是伪代码

    编辑:在 cmets 中回答有关多种材料项目的问题。

    class Item: NSObject {
        var name : String?
        var id : Int?
        var tier : Int?
        var material : String?
    
        init(_ name : String?,_ id : Int?,_ tier : Int?,_ material : String?) {
            self.name = name
            self.id = id
            self.tier = tier
            self.material = material
        }
    
    }
    
    class Equipment : Item {
        var components : [[Item : Int]]?
    
        override init(_ name : String?,_ id : Int?,_ tier : Int?,_ material : String?) {
            super.init(name, id, tier, material)
        }
    
        init(_ name : String?,_ id : Int?,_ tier : Int?,_ material : String?,_ components : [[Item : Int]]?) {
            super.init(name, id, tier, material)
            self.components = components
        }
    }
    

    如何进行的基本示例

       override func viewDidLoad() {
            super.viewDidLoad()
    
            let item = Item(nil, nil, nil , "wood")
            let item2 = Item(nil,nil,nil,"metal")
            let equipment = Equipment(nil, nil, nil, nil, [[item : 1],[item2 : 5]])
    
            checkType(object: item2)
            checkType(object: equipment)
        }
    
    
        func checkType(object: NSObject) {
            if let obj = object as? Equipment {
                print("Equipment")
                // do work here
            } else if let obj = object as? Item {
                print("Item")
                // do work here
            }
        }
    

    【讨论】:

    • 这对我来说看起来不错。但这不会限制我在层级中拥有不同的金额吗?例如,如果我有其他物品,而不是 4 个子物品制作 8,而那些只制作 1 而不是 4,这样的事情仍然可能吗?
    • 您可以为每种材质创建一个预设的tier 对象并设置哪些值在哪里。或者您可以创建一个数组并使其更基本。您的来电。
    • 例如 TierArray.wood = [[0,1,2,8,32,128],[0,0,1,4,16,64]...]TierArray.metal 可以完全等同于其他东西。
    • 现在如果有需要元和木材的物品我该怎么办?
    • 'components' 接受一个字典数组,其中键是组成它的项目,值是制作它所需的项目数量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-09
    • 2017-08-02
    相关资源
    最近更新 更多