结合两个项目(类似食谱)
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 的项目(item1
、item2
、...)。
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
.
我希望用户能够组合两个项目,如果兼容,将产生一个新项目。在此示例中,项目 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 的项目(item1
、item2
、...)。
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
.