结合两个项目(类似食谱)

Combining two items (recipe-like)

我希望用户能够组合两个项目,如果兼容,将产生一个新项目。在此示例中,项目 ID 将保存为字符串。

我想知道执行此操作的最有效方法是什么,同时确保交换的订单将始终产生相同的结果,以便用户可以输入订单:

item X + item Y = item Z
item Y + item X = item Z

我试过使用字典和对象,但我就是无法使用任何东西。我还尝试了一些包含 HashMap/HashSet 的各种库,但没有任何效果。这是一些伪代码:

itemRecipe1:HashSet = new HashSet();
itemRecipe1.add("2");//Add item with ID of 2
itemRecipe1.add("3");//Add item with ID of 3

inputRecipe:HashSet = new HashSet();
inputRecipe.add("3");//Add item with ID of 3 (swapped)
inputRecipe.add("2");//Add item with ID of 2 (swapped)

recipeList:HashMap = new HashMap();
receipeList.put(itemRecipe1, "11");//Recipe has been added, the result of the recipe should be item 11

//This should output as TRUE since the composition of itemRecipe1 and inputRecipe are the same, despite a different input order.
trace(receipeList.containsKey(inputRecipe));

如果有人对此问题有解决方案,请告诉我,因为我愿意实施我可以开始工作的任何设计。我只是不明白字典如何工作,因为键顺序很重要。

so the user could input the order

第一步是限制可能的输入。如果您允许任何类型的输入,则必须解析该输入,事情很快就会变得复杂。

创建一个只允许用户将两个项目放在一起的输入法,例如通过将项目拖放到仅 2 个插槽。

I just don't see how a Dictionary could work as the key order matters.

重要的是把按键设计好。

正如评论中 @George Profenza 指出的那样,您可以将您的 ID 更改为不同的格式。您可以使用 1, 2, 4, ... 2^n 而不是 1, 2, 3, ... n。优点是您可以通过按位 运算符 (|) 唯一地组合任意两个 ID。在以下示例中,组合了两个这样的 ID(二进制表示法):

  00001
| 10000
--------
  10001 

如您所见,每个ID在二进制中都占据一个单独的位置:第1位和第5位。通过 运算符组合两者意味着现在第 1 位和第 5 位均为 1。顺序无关紧要。如果您以 2 的幂的形式使用此类 ID,则可以将它们组合起来,而无需考虑形成对的顺序,然后可以将其用作字典的键。


另一个解决方案是简单地对 ID 对进行排序。

组合 3-2 变为 2-3,组合 2-3 保持 2-3。 2-3 和 3-2 结果相同。

然后您可以相应地构建您的数据结构,即:外部数据结构用于较小的 ID 号,嵌套的内部数据结构用于较大的 ID 号。这是一些带有通用对象的伪代码:

var map:Object = {};
map["2"] = {"3":"combination 2-3"};

要访问它,您需要执行以下操作:

trace(map[Math.min(ID1, ID2)][Math.max(ID1, ID2)])

还有一种蛮力方法,可以将两种可能的组合存储在数据结构中。其代码大致如下所示:

var map:Object = {};
map["2"] = {"3":"combination 2-3"};
map["3"] = {"2":"combination 2-3"};

现在都

trace(map[ID1][ID2]);

trace(map[ID2][ID1]);

应该会产生相同的结果。

所以您正在尝试将两个或多个对象相互关联。您首先需要的是一些可用于唯一地表示每个项目的原始数据,通常是 ID。这应该为您提供以下内容:

class Item {
    public var _id:int;

    public function Item(id:int) {
        _id = id;
    }

    public function get id():int { return _id; }
}

现在您需要一些数据来使用此 ID 在多个项目之间建立关系。这可以像下面一样简单,添加一些额外的功能来查看这些 ID 的输入列表是否与关系匹配:

class ItemRelationship {
    private var _items:Vector.<Item>;

    public function ItemRelationship(items:Vector.<Item>) {
        _items = items;
    }

    public function matches(ids:Vector.<int>):Boolean {
        if (_items.length !== ids.length) {
            return false;
        }

        for each (var item:Item in _items) {
            var found:Boolean = false;

            for each (var id:int in ids) {
                if (item.id === id) {
                    found = true;
                    break;
                }
            }

            if (!found) return false;
        }

        return true;
    }

    public function get items():Vector.<Item> { return _items; }
}

这让我们可以做这样的事情,假设我们有一堆带有 ID 的项目(item1item2、...)。

var rel:ItemRelationship = new ItemRelationship(new <Item>[item1, item2]);

然后:

trace(rel.matches(new <int>[1,2])); // true
trace(rel.matches(new <int>[2,1])); // true
trace(rel.matches(new <int>[3,4])); // false

现在我们需要的是存储所有这些关系的东西,并让我们根据输入 ID 列表获取一个:

class RelationshipCollection {
    private var _relationships:Vector.<ItemRelationship>;

    public function RelationshipCollection(relationships:Vector.<ItemRelationship>) {
        _relationships = relationships;
    }

    public function find(ids:Vector.<int>):ItemRelationship {
        for each(var relationship:ItemRelationship in _relationships) {
            if (relationship.matches(ids)) return relationship;
        }

        return null;
    }
}

在其中放置大量关系:

var collection:RelationshipCollection = new RelationshipCollection(new <ItemRelationship>[
    new ItemRelationship(new <Item>[item1, item4]),
    new ItemRelationship(new <Item>[item2, item3])
]);

试一试:

trace(collection.find(new <int>[1, 3])); // null (no match)
trace(collection.find(new <int>[1, 4])); // works
trace(collection.find(new <int>[3, 2])); // works
trace(collection.find(new <int>[2, 3])); // works

当然,为了可读性,您可以将每个 class 重命名为更适合其应用的名称,例如Item => Potion, ItemRelationship => Recipe, RelationshipCollection => RecipeBook.