Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/actionscript-3/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 复杂树数据结构_C#_Algorithm_Data Structures_Tree - Fatal编程技术网

C# 复杂树数据结构

C# 复杂树数据结构,c#,algorithm,data-structures,tree,C#,Algorithm,Data Structures,Tree,我正在为一款游戏设计一个道具系统,我们正在制作一款类似于古老的经典生化危机游戏的道具。目前,我正在实现项目组合,您可以将不同的项目相互组合以获得新的内容。复杂的情况来自于这样一个事实,即存在具有多个转换级别的项目,并且每个级别有多个配偶。请允许我澄清一下,让我们假设我们有一种绿色、红色和蓝色的草药。你不能把红色和蓝色结合起来,但是你可以把G+B结合起来你会得到一个像绿蓝药草一样的东西,或者G+R得到绿红药草,如果你把这两个结果中的任何一个结合到一个蓝色药草上,你会得到一个绿绿药草。正如你在这个例

我正在为一款游戏设计一个道具系统,我们正在制作一款类似于古老的经典生化危机游戏的道具。目前,我正在实现项目组合,您可以将不同的项目相互组合以获得新的内容。复杂的情况来自于这样一个事实,即存在具有多个转换级别的项目,并且每个级别有多个配偶。请允许我澄清一下,让我们假设我们有一种绿色、红色和蓝色的草药。你不能把红色和蓝色结合起来,但是你可以把G+B结合起来你会得到一个像绿蓝药草一样的东西,或者G+R得到绿红药草,如果你把这两个结果中的任何一个结合到一个蓝色药草上,你会得到一个绿绿药草。正如你在这个例子中看到的,绿色药草有两个级别的转化,为了达到第一个级别,有两个可能的配偶(红色|蓝色),从这一点到第二个级别,只有一个配偶(蓝色)

所以我想出了一个有趣的树,涵盖了所有的可能性:<强> nSeals>强,不只是2,树的层次越复杂,看看这个3个层次的例子,你在中间看到的三角形形状代表一个项目,它周围的其他彩色形状表示它可能达到下一个层次:

有很多不同的组合,我可以先把我的物品和蓝色的结合起来,然后是红色的,然后是绿色的,或者是绿色的,然后是红色的,然后是蓝色的,等等,以达到我的最终水平。 我找到了这棵树,代表了所有可能的组合:

(右边的数字是#级别,左边是每个级别的#节点),但正如您所看到的,它是多余的。如果您查看结束节点,它们应该都是一个,因为它们都会导致相同的最终结果,即G+R+B。实际上,这种情况下总共有7种可能的状态,下面是正确的树:

这很有意义,注意节点数量上的巨大差异

现在我的问题是,什么是适合这个的数据结构我很确定这个没有内置的,所以我要做我自己的定制的,我确实做了,并设法让它工作,但有一个问题。(值得一提的是,我从一个XML文件中获取节点信息,我所说的信息是指达到一个节点/级别所需的项,以及在该节点上我的项的名称,例如:绿色药草要达到RedGreenHerb状态,它“需要”一个RedHerb,当如果发生初始化,名称“GreenHerb”将更改为“RedGreenHerb”,如果您想知道RedHerb会发生什么,它就会消失,我不再需要它),以下是我的数据结构:

public struct TransData
{
    public TransData(string transItemName, string itemRequired)
    {
        this.transItemName = transItemName;
        this.itemRequired = itemRequired;
    }
    public string transItemName;
    public string itemRequired;
}

public class TransNode
{
    public List<TransNode> nodes = new List<TransNode>();
    public TransData data;
    public TransNode(TransNode node): this(node.data.transItemName, node.data.itemRequired) { }
    public TransNode(string itemName, string itemRequired)
    {
       data = new TransData(itemName, itemRequired);
    }
}

public class TransLevel
{
    public List<TransNode> nodes = new List<TransNode>();
    public TransNode NextNode { get { return nodes[cnt++ % nodes.Count]; } }
    int cnt;
}

public class TransTree
{    
    public TransTree(string itemName)
    {
        this.itemName = itemName;
    }
    public string itemName;
    public TransNode[] nodes;
    public List <TransLevel> levels = new List<TransLevel>();
    // other stuff...
}
}

下面是一个XML示例,可以让一切变得清晰: ItemName->Level->Path(只不过是一个节点)->路径数据

<IOUTransformableItemsDatabaseManager>
  <GreenHerb>
    <Level_0>
      <Path_0>
        <NewName>RedGreenHerb</NewName>
        <ItemRequired>RedHerb</ItemRequired>
      </Path_0>
      <Path_1>
        <NewName>BlueGreenHerb</NewName>
        <ItemRequired>BlueHerb</ItemRequired>
      </Path_1>
    </Level_0>
    <Level_1>
      <Path_0>
        <NewName>GreyHerb</NewName>
        <ItemRequired>BlueHerb</ItemRequired>
      </Path_0>
    </Level_1>
  </GreenHerb>
</IOUTransformableItemsDatabaseManager>
我首先连接节点,然后删除标高?为什么,因为如果我没有,那么每个节点都有两个对它的引用,一个来自其父节点,另一个来自当前级别。 现在,
ConnectNode
实际上是针对我显示的长树,而不是针对具有7种状态的优化树:

    // this is an overloaded version I use inside a for loop in ConnectNodes()
    private void ConnectNodes(int level1, int level2)
    {
        int level1_nNodes = levels[level1].nodes.Count;
        int level2_nNodes = levels[level2].nodes.Count;

        // the result of the division gives us the number of nodes in level2,
        // that should connect to each node in level1. 12/4 = 3, means that each
        // node from level1 will connect to 3 nodes from level2;
        int nNdsToAtch = level2_nNodes / level1_nNodes;
        for (int i = 0, j = 0; i < level2_nNodes; j++)
        {
            var level1_nextNode = levels[level1].nodes[j];
            for (int cnt = 0; cnt < nNdsToAtch; cnt++, i++)
            {
                var level2_nextNode = levels[level2].nodes[i];
                level1_nextNode.nodes.Add(new TransNode(level2_nextNode));
            }
        }
   }
每个“1”表示一个实际项目,“0”表示为空。在我的树上,'001'=蓝色,'010'=绿色,'100'=红色,'011'表示绿色+蓝色,'111'=灰色(最终等级)

所以现在我解释了一切,首先:我的方法正确吗?如果不是,那是什么? 如果是,那么我可以使用/制作什么样的数据结构来实现这一点?如果我提出的数据结构在它们的位置上,我如何将XML文件中的数据存储到我的数据结构中,从而将节点连接在一起,这样每当我取出一个节点时,它就会取出它的子节点

非常感谢您的帮助和耐心:)

编辑:有趣的是,整个系统只针对在整个游戏中只出现一次的项目(拾取一次)。这就是为什么每当我选择一条路径时,我会将其从memeory中删除,每当我选择一个项目时,我会将其条目从数据库中删除,因为我不会再遇到它


编辑:请注意,我不仅仅通过字符串来表示我的项目,它们还有很多其他属性。但在这种情况下,我只关心它们的名称,这就是我处理字符串的原因。

我不喜欢这个解决方案的原因:

  • 简单的解决方案是最好的解决方案
  • 很难维护,因为xml是基于图形的
  • 不要真的利用OOP
  • 漏洞的来源
  • 可能使用
    反射
    解决小问题(我说小是因为如果你玩这样的游戏,你将面临更多的困难和问题;)。这意味着不必要的复杂性
我喜欢这个解决方案:

  • 你刚刚完全理解了这个问题。每个项都有一个与其他一些对象的转换列表。现在的问题是如何表示它(而不是存储它)
我要做的是(juste IMHO,你的解决方案也很好):从仅节点的角度使用OOP。因此,如果要将树附加到数据结构,则树将成为一个状态机(正如您所说的路径;)

public class InventoryObject
{
    protected Dictionnary<Type, InventoryObject> _combinations = new Dictionnary<Type, InventoryObject>();

    public InventoryObject() {}       

    public InventoryObject Combine(InventoryObject o)
    {
       foreach (var c in _combinations)
          if (typeof(o) == c.Key)
            return c.Value

       throw new Exception("These objects aren't combinable");
    }
}

public class BlueHerb : InventoryObject
{
    public Herb()
    {
       _combinations.Add(RedHerb, new BlueRedHerb());
       _combinations.Add(GreenHerb, new BlueGreenHerb());
    }
}

public class BlueRedHerb: InventoryObject
{
    public BlueRedHerb()
    {
       _combinations.Add(GreenHerb, new GreyHerb());
    }
}
公共类InventoryObject
{
受保护的词典_组合=新词典();
公共InventoryObject(){}
公共库存对象组合(库存对象o)
{
foreach(组合中的var c)
if(类型(o)==c.键)
返回c.值
抛出新异常(“这些对象不可组合”);
}
}
公共类BlueHerb:InventoryObject
{
公共药草()
{
_添加(RedHerb,newblueredherb());
_添加(青草,新青草());
}
}
公共类BlueRedHerb:InventoryObject
{
紫草
    // this is an overloaded version I use inside a for loop in ConnectNodes()
    private void ConnectNodes(int level1, int level2)
    {
        int level1_nNodes = levels[level1].nodes.Count;
        int level2_nNodes = levels[level2].nodes.Count;

        // the result of the division gives us the number of nodes in level2,
        // that should connect to each node in level1. 12/4 = 3, means that each
        // node from level1 will connect to 3 nodes from level2;
        int nNdsToAtch = level2_nNodes / level1_nNodes;
        for (int i = 0, j = 0; i < level2_nNodes; j++)
        {
            var level1_nextNode = levels[level1].nodes[j];
            for (int cnt = 0; cnt < nNdsToAtch; cnt++, i++)
            {
                var level2_nextNode = levels[level2].nodes[i];
                level1_nextNode.nodes.Add(new TransNode(level2_nextNode));
            }
        }
   }
001
010
100
011
101
110
111
public class InventoryObject
{
    protected Dictionnary<Type, InventoryObject> _combinations = new Dictionnary<Type, InventoryObject>();

    public InventoryObject() {}       

    public InventoryObject Combine(InventoryObject o)
    {
       foreach (var c in _combinations)
          if (typeof(o) == c.Key)
            return c.Value

       throw new Exception("These objects aren't combinable");
    }
}

public class BlueHerb : InventoryObject
{
    public Herb()
    {
       _combinations.Add(RedHerb, new BlueRedHerb());
       _combinations.Add(GreenHerb, new BlueGreenHerb());
    }
}

public class BlueRedHerb: InventoryObject
{
    public BlueRedHerb()
    {
       _combinations.Add(GreenHerb, new GreyHerb());
    }
}
public struct TransData
{
    public TransData(string itemName, List <string> itemsRequired)
    {
        this.itemName = itemName;
        this.itemsRequired = itemsRequired;
    }
    public string itemName;
    public List <string> itemsRequired;
}
public TransNode(string itemName, List <string> itemsRequired)
{
    data = new TransData(itemName, itemsRequired);
}
Necklace L.1_A: Requires BlueGem
Necklace L.1_B: Requires GreenGem
Necklace L.1_C: Requires RedGem
Necklace L.2_A: Requires BlueGem AND GreenGem
Necklace L.2_B: Requires GreenGem AND RedGem
Necklace L.2_C: Requires RedGem AND BlueGem
Necklace L.3_A: Requires RedGem AND BlueGem AND GreenGem
<IOUTransformableItemsDatabaseManager>
    <Necklace>
        <Level_0>
            <Path_0>
                <NewName>RedNecklace</NewName>
                <ItemsRequired>
                    <Item_0>Red</Item_0>
                </ItemsRequired>
            </Path_0>
            <Path_1>
                        .......
            </Level_0>
        <Level_1>
            <Path_0>
                <NewName>RedGreenNecklace</NewName>
                <ItemsRequired>
                    <Item_0>Red</Item_0>
                    <Item_1>Green</Item_1>
                </ItemsRequired>
            </Path_0>
            <Path_1>
                  .....
        </Level_1>
        <Level_2>
            <Path_0>
                <NewName>RedGreenBlueNecklace</NewName>
                <ItemsRequired>
                    <Item_0>Red</Item_0>
                    <Item_1>Green</Item_1>
                    <Item_2>Blue</Item_2>
                </ItemsRequired>
            </Path_0>
        </Level_2>
    </Necklace>
</IOUTransformableItemsDatabaseManager>
public class TransTree
{
    //public string itemName;
    //public List <TransNode> nodes;
    public List <TransLevel> levels = new List<TransLevel>();
    public TransNode root { private set; get; }
    public TransTree(string itemName)
    {
    //  this.itemName = itemName;
        root = new TransNode(itemName, null);
    }
}
public void ConnectNodes()
{
   for (int i = 0; i < levels.Count - 1; i++)
       ConnectNodes(i, i + 1);
   ConnectRoot();
}
private void ConnectNodes(int level1, int level2)
{
    int level1_nNodes = levels[level1].nodes.Count;
    int level2_nNodes = levels[level2].nodes.Count;
    for (int i = 0; i < level1_nNodes; i++)
    {
        var node1 = levels[level1].nodes[i];
        for (int j = 0; j < level2_nNodes; j++)
        {
            var node2 = levels[level2].nodes[j];
            foreach (var itemReq in node1.data.itemsRequired)
            {
                if (node2.data.itemsRequired.Contains(itemReq))
                {
                    node1.nodes.Add(node2);
                    break;
                }
            }
        }
     }
}
ConnectRoot();

public void ConnectRoot()
{
    foreach (var node in levels[0].nodes)
       root.nodes.Add(node);
}
// fetching the data from the xml file
    tree.ConnectNodes();
    tree.RemoveLevels();
tree.SetRoot(nodeTakenToTransform);
public void Notify_ItemTransformed(TransTree itemTree, TransNode nodeTaken)
{
   var key = new Tuple<string, string>(itemTree.root.data.itemName, nodeTaken.data.itemsRequired[0]);
   itemTree.SetRoot(nodeTaken);
   itemTree.UpdateNodesRequirements(itemTree.root); // take note here
   RemoveKey(key);
   RegisterItem(itemTree);
}
tree.SetRoot(nodeTaken);
tree.UpdateNodesRequirements(tree.root);
public void UpdateNodesRequirements(TransNode node)
{
    foreach (var n in node.nodes)
    {
        if (n.data.itemsRequired.Contains(root.data.itemsRequired[0]))
            n.data.itemsRequired.Remove(root.data.itemsRequired[0]);
        if (n.nodes != null && n.nodes.Count > 0)
            UpdateNodesRequirements(n);
    }
}