public IMemberContainer CopyGenotype() { List<TileNode> newGraph = new List<TileNode>(); Dictionary<TileNode, TileNode> oldToNewMapping = new Dictionary<TileNode, TileNode>(); foreach (TileNode o in graph.nodes) { TileNode n = TileNode.Copy(o); oldToNewMapping.Add(o, n); newGraph.Add(n); } foreach (TileNode o in graph.nodes) { foreach (TileNode c in o.connectedNodes) { oldToNewMapping[o].AddConnectedNode(oldToNewMapping[c]); } } MemberTilePCG ret = new MemberTilePCG(); ret.graph = new TileGraph(newGraph); return ret; }
private static void ConnectCandidates(MemberTilePCG firstParent, List<TileNode> firstCandidates, MemberTilePCG secondParent, List<TileNode> secondCandidates, Dictionary<TileNode, TileNode> oldToNewMapping) { foreach (TileNode fc in firstCandidates) { float minDistance = -1; TileNode candidate = null; foreach (TileNode sc in secondCandidates) { if (oldToNewMapping[sc].connectedNodes.Count < oldToNewMapping[sc].type.doorLocs.Length) { float dist = (secondParent.renderedTiles[sc].location - firstParent.renderedTiles[fc].location).magnitude; if (minDistance == -1 || dist < minDistance) { minDistance = dist; candidate = oldToNewMapping[sc]; } } } if (candidate != null) oldToNewMapping[fc].AddConnectedNode(candidate); } }
private static List<TileNode>[] CreateHalvesAndCandidates(Vector3 lineCheck, MemberTilePCG m) { List<TileNode> firstHalf = new List<TileNode>(); List<TileNode> secondHalf = new List<TileNode>(); foreach (KeyValuePair<TileNode, RenderedTileInfo> renderedTile in m.renderedTiles) { if (Vector3.Cross(lineCheck, renderedTile.Value.location).y < 0) { firstHalf.Add(renderedTile.Key); } else { secondHalf.Add(renderedTile.Key); } } // find candidate doors List<TileNode> firstHalfCandidates = new List<TileNode>(); List<TileNode> secondHalfCandidates = new List<TileNode>(); foreach (TileNode t in firstHalf) { foreach (TileNode c in t.connectedNodes) { if (secondHalf.Contains(c)) { firstHalfCandidates.Add(t); if (!secondHalfCandidates.Contains(c)) secondHalfCandidates.Add(c); } } } return new List<TileNode>[]{ firstHalf, secondHalf, firstHalfCandidates, secondHalfCandidates }; }
public IMemberContainer[] Crossover(IMemberContainer otherParent) { // This is difficult. // First (and bad) attempt: // 1. draw the same line through the origin in both graphs, splitting them. // 2. for each child, pick two nodes in the two halves as close to the origin as possible that have doors that used to be connected. // 3. connect the nodes on each half via the single door. // NOTE: THIS IS PRONE TO FAIL CATASTROPHICALLY. If the one new connection cannot be made, the entire crossover will fail. float angle = Random.Range(0, 180); // turn angle into vector Vector3 lineCheck = Quaternion.AngleAxis(angle, Vector3.up) * Vector3.forward; List<TileNode>[] mySplit = CreateHalvesAndCandidates(lineCheck, this); List<TileNode>[] otherSplit = CreateHalvesAndCandidates(lineCheck, (MemberTilePCG)otherParent); // Child 1 List<TileNode> firstChild = new List<TileNode>(); Dictionary<TileNode, TileNode> firstOldToNewMapping = new Dictionary<TileNode, TileNode>(); // First Half Copy foreach (TileNode t in mySplit[0]) { TileNode newTile = TileNode.Copy(t); firstOldToNewMapping[t] = newTile; firstChild.Add(newTile); foreach (TileNode c in t.connectedNodes) { if (firstOldToNewMapping.ContainsKey(c)) { newTile.AddConnectedNode(firstOldToNewMapping[c]); firstOldToNewMapping[c].AddConnectedNode(newTile); } } } // Second Half Copy foreach (TileNode t in otherSplit[1]) { TileNode newTile = TileNode.Copy(t); firstOldToNewMapping[t] = newTile; firstChild.Add(newTile); foreach (TileNode c in t.connectedNodes) { if (firstOldToNewMapping.ContainsKey(c)) { newTile.AddConnectedNode(firstOldToNewMapping[c]); firstOldToNewMapping[c].AddConnectedNode(newTile); } } } // Child 2 List<TileNode> secondChild = new List<TileNode>(); Dictionary<TileNode, TileNode> secondOldToNewMapping = new Dictionary<TileNode, TileNode>(); // First Half Copy foreach (TileNode t in mySplit[1]) { TileNode newTile = TileNode.Copy(t); secondOldToNewMapping[t] = newTile; secondChild.Add(newTile); foreach (TileNode c in t.connectedNodes) { if (secondOldToNewMapping.ContainsKey(c)) { newTile.AddConnectedNode(secondOldToNewMapping[c]); secondOldToNewMapping[c].AddConnectedNode(newTile); } } } // Second Half Copy foreach (TileNode t in otherSplit[0]) { TileNode newTile = TileNode.Copy(t); secondOldToNewMapping[t] = newTile; secondChild.Add(newTile); foreach (TileNode c in t.connectedNodes) { if (secondOldToNewMapping.ContainsKey(c)) { newTile.AddConnectedNode(secondOldToNewMapping[c]); secondOldToNewMapping[c].AddConnectedNode(newTile); } } } ConnectCandidates(this, mySplit[2], (MemberTilePCG)otherParent, otherSplit[3], firstOldToNewMapping); ConnectCandidates(this, mySplit[3], (MemberTilePCG)otherParent, otherSplit[2], secondOldToNewMapping); MemberTilePCG[] containers = new MemberTilePCG[2]; containers[0] = new MemberTilePCG(); containers[0].graph = new TileGraph(firstChild); containers[1] = new MemberTilePCG(); containers[1].graph = new TileGraph(secondChild); return containers; }