private static void CheckPrerequisites() { // check prerequisites var nodes = new Queue <ResearchNode>(Nodes.OfType <ResearchNode>()); // remove redundant prerequisites while (nodes.Count > 0) { var node = nodes.Dequeue(); if (node.Research.prerequisites.NullOrEmpty()) { continue; } var ancestors = node.Research.prerequisites?.SelectMany(r => r.Ancestors()).ToList(); var redundant = ancestors.Intersect(node.Research.prerequisites); if (redundant.Any()) { ResearchLog.Warning("\tredundant prerequisites for {0}: {1}", node.Research.LabelCap, string.Join(", ", redundant.Select(r => r.LabelCap).ToArray()) + ", fixing, please save"); foreach (var redundantPrerequisite in redundant) { ProfileManager.AddCommand("".Find(node.Research).Get(new { node.Research.prerequisites }).Remove().Find(redundantPrerequisite)); node.Research.prerequisites.Remove(redundantPrerequisite); } } } // fix bad techlevels nodes = new Queue <ResearchNode>(Nodes.OfType <ResearchNode>()); while (nodes.Count > 0) { var node = nodes.Dequeue(); if (!node.Research.prerequisites.NullOrEmpty()) { // warn and fix badly configured techlevels if (node.Research.prerequisites.Any(r => r.techLevel > node.Research.techLevel)) { ResearchLog.Warning("\t{0} has a lower techlevel than (one of) it's prerequisites, fixing, please save", node.Research.defName); TechLevel maxTech = node.Research.prerequisites.Max(r => r.techLevel); ProfileManager.AddCommand("".Find(node.Research).Set(new { node.Research.techLevel }).Find(maxTech)); node.Research.techLevel = maxTech; // re-enqeue all descendants foreach (var descendant in node.Descendants.OfType <ResearchNode>()) { nodes.Enqueue(descendant); } } } } }
private static void EdgeLengthSweep_Local_Layer(int l, bool @in) { // The objective here is to; // (1) move and/or swap nodes to reduce local edge length // (2) not increase the number of crossings var x = @in ? l - 1 : l + 1; var crossings = Crossings(x); var layer = Layer(l, true); foreach (var node in layer) { foreach (var edge in @in ? node.InEdges : node.OutEdges) { // current length var length = edge.Length; var neighbour = @in ? edge.In : edge.Out; if (neighbour.X != x) { ResearchLog.Warning("{0} is not at layer {1}", neighbour, x); } // we only need to loop over positions that might be better for this node. // min = minimum of current position, node position var min = Mathf.Min(node.Y, neighbour.Y); var max = Mathf.Max(node.Y, neighbour.Y); // already at only possible position if (min == max && min == node.Y) { continue; } for (var y = min; y <= max; y++) { if (y == neighbour.Y) { continue; } // is this spot occupied? var otherNode = NodeAt(x, y); // occupied, try swapping if (otherNode != null) { Swap(neighbour, otherNode); var candidateCrossings = Crossings(x); if (candidateCrossings > crossings) { // abort Swap(otherNode, neighbour); } else { var candidateLength = edge.Length; if (length - candidateLength < Epsilon) { // abort Swap(otherNode, neighbour); } else { length = candidateLength; } } } // not occupied, try moving else { var oldY = neighbour.Y; neighbour.Y = y; var candidateCrossings = Crossings(x); if (candidateCrossings > crossings) { // abort neighbour.Y = oldY; } else { var candidateLength = edge.Length; if (length - candidateLength < Epsilon) { // abort neighbour.Y = oldY; } else { length = candidateLength; } } } } } } }