// Builds a graph from an adjacency matrix. // Only the lower left half is checked. SearchGraph SearchGraphFromData(bool[,] adjacencyMatrix) { int n = adjacencyMatrix.GetUpperBound(0) + 1; // Don't screw this up. Assert.IsTrue(n == adjacencyMatrix.GetUpperBound(1) + 1); List<SkillNode> nodes = new List<SkillNode>(); for (int i = 0; i < n; i++) { SkillNode node = new SkillNode(); node.Id = (ushort)i; nodes.Add(node); } for (int i = 0; i < n; i++) { nodes[i].Neighbor = new List<SkillNode>(); for (int j = 0; j < i; j++) { if (adjacencyMatrix[i, j]) { nodes[i].Neighbor.Add(nodes[j]); // No directed edges atm. nodes[j].Neighbor.Add(nodes[i]); } } } SearchGraph graph = new SearchGraph(); foreach (SkillNode node in nodes) { graph.AddNode(node); } return graph; }
// Builds a graph from an adjacency matrix. // Only the lower left half is checked. private static SearchGraph SearchGraphFromData(bool[,] adjacencyMatrix) { int n = adjacencyMatrix.GetUpperBound(0) + 1; // Don't screw this up. Assert.IsTrue(n == adjacencyMatrix.GetUpperBound(1) + 1); List <PassiveNodeViewModel> nodes = new List <PassiveNodeViewModel>(); for (ushort i = 0; i < n; i++) { var node = new PassiveNodeViewModel(i); nodes.Add(node); } for (int i = 0; i < n; i++) { for (int j = 0; j < i; j++) { if (adjacencyMatrix[i, j]) { nodes[i].NeighborPassiveNodes[nodes[j].Id] = nodes[j]; // No directed edges atm. nodes[j].NeighborPassiveNodes[nodes[i].Id] = nodes[i]; } } } SearchGraph graph = new SearchGraph(); foreach (PassiveNodeViewModel node in nodes) { graph.AddNode(node); } return(graph); }
/// <summary> /// Initializes the search graph by going through all node groups /// of the skill tree and including those that could be part of the solution. /// </summary> private void CreateSearchGraph(SearchGraph searchGraph) { foreach (var ng in SkillTree.NodeGroups) { var mustInclude = false; SkillNode firstNeighbor = null; // Find out if this node group can be omitted. foreach (var node in ng.Nodes) { // If the group contains a skilled node or a target node, // it can't be omitted. if (searchGraph.NodeDict.ContainsKey(node) || MustIncludeNodeGroup(node)) { mustInclude = true; break; } // If the group is adjacent to more than one node, it must // also be fully included (since it's not isolated and could // be part of a path to other nodes). var ng1 = ng; foreach (var neighbor in node.Neighbor.Where(neighbor => neighbor.SkillNodeGroup != ng1)) { if (firstNeighbor == null) { firstNeighbor = neighbor; } // Does the group have more than one neighbor? if (neighbor != firstNeighbor) { mustInclude = true; break; } } if (mustInclude) { break; } } if (mustInclude) { // Add the group's nodes individually foreach (var node in ng.Nodes) { // Can't path through class starts. if (node.IsRootNode // Don't add nodes that are already in the graph (as // target or start nodes). || searchGraph.NodeDict.ContainsKey(node) // Don't add nodes that should not be skilled. || Settings.Crossed.Contains(node) // Mastery nodes are obviously not useful. || node.Type == PassiveNodeType.Mastery // Ignore ascendancies for now || node.ascendancyName != null) { continue; } if (IncludeNodeInSearchGraph(node)) { searchGraph.AddNode(node); } } } } }