public void MSTest_disconnect_not_connected_nodes() { Node node1 = new Node(); Node node2 = new Node(); node1.disconnect(node2); }
public void MSTest_disconnect_nodes() { Node baseNode = new Node(); Node nbNode = new Node(); baseNode.neighbors.Add(nbNode); baseNode.neighbors.Add(baseNode); baseNode.disconnect(nbNode); Assert.IsFalse(baseNode.neighbors.Contains(nbNode)); Assert.IsFalse(nbNode.neighbors.Contains(baseNode)); }
/*Tuple contains the remaining connections from the bridge, * the amount of nodes, and the total amount of connections.*/ private Tuple <int, int, int> makeSection(Node start, int startc, ref int level) { Bridge b = new Bridge(level.ToString()); Bridge bstart = start as Bridge; if (startc == 1) //can only be directly connected to a bridge { level++; b.connectToNodeOfSameZone(start); if (bstart != null) { bstart.connectToNodeOfNextZone(b); bstart.disconnect(b); } if (level > difficultyLevel + 1) { exitNode = new Node(b); } else { bridges[level - 2] = b; } return(Tuple.Create(rng.Next(1, 4), 1, 1)); } HashSet <int> open = new HashSet <int>(); List <Node> nodes = new List <Node>(); List <int> conns = new List <int>(); int totalConns = 0; open.Add(0); nodes.Add(start); conns.Add(startc); int index; while (open.Count > 1 || open.Contains(0)) { Node n = new Node(); index = nodes.Count; open.Add(index); nodes.Add(n); conns.Add(rng.Next(1, 5)); for (int i = 0; i < index; i++) { if (open.Contains(i) && conns.Sum() > open.Count) { totalConns++; nodes[i].connect(n); conns[i]--; if (conns[i] == 0) { open.Remove(i); } conns[index]--; if (conns[index] == 0) { open.Remove(index); break; } } } } if (bstart != null) { bstart.toNodes = bstart.neighbors.Except(bstart.fromNodes).ToList(); } index = open.Single(); foreach (Node nd in shortestpath(start, nodes[index]) .Where(m => m == nodes[index] || p.isBridge(start, nodes[index], m))) { level++; if (level > difficultyLevel + 1) { exitNode = nd; exitNode.id = "exit"; break; } else { var nb = nd.neighbors; while (nb.Count > 0) { Node m = nb[0]; m.disconnect(nd); if (p.isReachable(start, m)) { b.connectToNodeOfSameZone(m); } else { b.connectToNodeOfNextZone(m); } } bridges[level - 2] = b; b = new Bridge(level.ToString()); } } return(Tuple.Create(conns[index], nodes.Count - 1, totalConns)); }
/* To create a new dungeon with the specified difficult level and capacity multiplier */ //TO-DO: check average connectivity predicate //TO-DO: improve the algorithm for building connections between nodes in the same zone public Dungeon(uint level, uint nodeCapacityMultiplier, Random random) { Logger.log("Creating a dungeon of difficulty level " + level + ", node capacity multiplier " + nodeCapacityMultiplier + "."); difficultyLevel = level; //assign dungeon difficulty level bridges = new List <Bridge>(); //List of bridges initialized predicates = new Predicates(); zones = new List <Zone>(); //initialize the zones M = nodeCapacityMultiplier; //initialize node capacity multiğlier int numberOfNodesInZone = 0; int connected = 0; //every node is named with its zone number followed by its number in a zone (nodeId = preId+lastId) string preId, lastId, nodeId = ""; startNode = new Node("" + 10, 1); //start node id is set Logger.log("Set startNode Id: 10"); for (int i = 1; i < level + 1; i++) //i signifies zone level, for each zone { Zone newZone = new Zone(i, nodeCapacityMultiplier); //create a new zone zones.Add(newZone); //add it in dungeon.zones list Logger.log("Creating level " + i); preId = "" + i; // preId is zone level numberOfNodesInZone = random.Next(2, 5); //randomly decide between 2-4 nodes in a zone //if you change number of nodes can be in a zone, be careful with the dependent statements below Logger.log("Number of nodes in zone " + i + " is " + numberOfNodesInZone); for (int j = 1; j <= numberOfNodesInZone; j++) //for each node in a zone { //create and add nodes to the list nodesInZone lastId = "" + j; nodeId = preId + lastId; //merge preId and lastId to create nodeId Node newNode = new Node(nodeId, i); //create node Logger.log("Created node with id " + nodeId); newZone.nodesInZone.Add(newNode); //add node to the list } //zone's nodesInZone list stores every node in this zone int numberOfNodesToConnect; // temp variable to decide how many nodes to connect for startNode or for bridges Node zoneFirstNode; //holds start node or starting bridge for the zone //(starting bridge for a zone is the bridge which is connecting it to the previous zone) if (i == 1) //for the first level { // connect start node to some nodes in the zone zoneFirstNode = startNode; numberOfNodesToConnect = random.Next(1, numberOfNodesInZone + 1); //randomly decide btw 1-4 nodes //rnd operation is exclusive for the max number, numberofNodesInZone can be 4 at most, thus it is safe this way Logger.log("Connecting startNode to " + numberOfNodesToConnect + " nodes in the zone "); for (int j = 0; j < numberOfNodesToConnect; j++) //for each nodes to connect { //connect them with the start node int nodeIndex = random.Next(0, numberOfNodesInZone); //randomly get node index to connect while (startNode.alreadyConnected(newZone.nodesInZone.ElementAt(nodeIndex))) { //if the chosen node is already connected nodeIndex = random.Next(0, numberOfNodesInZone); //choose a new one } startNode.connect(newZone.nodesInZone.ElementAt(nodeIndex)); //connect start node with that node Logger.log("Connected to node " + newZone.nodesInZone.ElementAt(j).id); } } else { //connect bridge to some nodes in the next zone Bridge startBridge = bridges.ElementAt(i - 2); //bridge is already created in previous loop zoneFirstNode = (Node)startBridge; int maxConnect = 4 - startBridge.neighbors.Count; //maximum number of connections that bridge can make if (numberOfNodesInZone < maxConnect) //maximum number of connections are constrained by { maxConnect = numberOfNodesInZone; //number of zones in the zone } numberOfNodesToConnect = random.Next(1, maxConnect + 1); //Decide how many connections it should make Logger.log("Connecting bridge " + startBridge.id + " to " + numberOfNodesToConnect + " nodes in the next zone "); for (int j = 0; j < numberOfNodesToConnect; j++) { //connect them with the bridge node int nodeIndex = random.Next(0, numberOfNodesInZone); //randomly decide the node index while (startBridge.alreadyConnected(newZone.nodesInZone.ElementAt(nodeIndex))) { nodeIndex = random.Next(0, numberOfNodesInZone); } startBridge.connectToNodeOfNextZone(newZone.nodesInZone.ElementAt(nodeIndex)); //connect bridge with the next zone Logger.log("Connected to node " + newZone.nodesInZone.ElementAt(j).id); } } Logger.log("Connecting nodes in the same zone"); //connect nodes in the same zone //TO-DO improve the algorithm //Currently it exits the algorithm once every node is accessible from the starting node of the zone while (!allReachable(newZone.nodesInZone, zoneFirstNode)) //while there exists not reachable nodes { Node n1 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); //randomly choose node1 while (n1.isFullyConnected()) //if it is fully connected node { n1 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); //choose another one } Node n2 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); //randomly select node2 while (n2.isFullyConnected() || n2.id == n1.id || n2.alreadyConnected(n1)) //make sure it is not fully connected, not same as node1, not already connected with node1 { n2 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); } n1.connect(n2); Logger.log("Nodes " + n1.id + " " + n2.id + " are connected"); } List <Node> listOfNotFullNodes = new List <Node>(); //get list of not fully connected nodes in the zone to consider connections for (int j = 0; j < newZone.nodesInZone.Count; j++) { Node nd = newZone.nodesInZone.ElementAt(j); if (!nd.isFullyConnected()) { listOfNotFullNodes.Add(nd); } } Logger.log("Creating list of not full nodes, number of not full nodes " + listOfNotFullNodes.Count); //Connect last node to the zone, either a bridge or the exit node int min = 1; int max; if (i == level) { // last zone //connect exit node lastId = "" + (numberOfNodesInZone + 1); nodeId = preId + lastId; //create id of the exit node exitNode = new Node(nodeId, i); //create exit node Logger.log("Last zone is finished, exit node id is set to " + nodeId); max = 4; //max number of connections that node can have if (listOfNotFullNodes.Count < 4) { max = listOfNotFullNodes.Count; //can make at most listOfNotFullNodes.Count number of connections } numberOfNodesToConnect = random.Next(min, max + 1); //randomly decide number of nodes to connect for (int j = 0; j < numberOfNodesToConnect; j++) //connect exit node to that number of nodes { exitNode.connect(listOfNotFullNodes.ElementAt(j)); //can be randomized Logger.log("Connected to node " + listOfNotFullNodes.ElementAt(j).id); } } else { //connect to end bridge //a bridge can be connected to at minimum 1 and at maximum 3 nodes lastId = "" + (numberOfNodesInZone + 1); nodeId = preId + lastId; //create bridge id Bridge endBridge = new Bridge(nodeId, i); //create the bridge bridges.Add(endBridge); //add it to bridges list to access it in the next loop iteration Logger.log("A new bridge is created with id " + nodeId); max = 3; //since a bridge should already have at least 1 connection to the other zone //max number of connections it can make can not be more than 3 if (listOfNotFullNodes.Count < 3) { max = listOfNotFullNodes.Count; //can make at most listOfNotFullNodes.Count number of connections } numberOfNodesToConnect = random.Next(min, max + 1); //decide number of nodes to connect for (int j = 0; j < numberOfNodesToConnect; j++) //connect it to that number of nodes { endBridge.connectToNodeOfSameZone(listOfNotFullNodes.ElementAt(j)); //not randomized Logger.log("Connected to node " + listOfNotFullNodes.ElementAt(j).id); } //end bridge is also connected } //Ensure the average connectivity if (i == 1) { Node n1, n2; connected = startNode.neighbors.Count; for (int j = 0; j < numberOfNodesInZone; j++) { connected += newZone.nodesInZone.ElementAt(j).neighbors.Count; } while (Convert.ToDouble(connected / (numberOfNodesInZone + 1)) > 3) { n1 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); while (n1.neighbors.Count <= 1) { n1 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); } n2 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); while (n2.neighbors.Count <= 1 || n2.id == n1.id || !n2.alreadyConnected(n1)) { n2 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); } n1.disconnect(n2); Logger.log("Nodes " + n1.id + " " + n2.id + " are disconnected"); connected -= 2; } } else if (i == level) { Node n1, n2; connected = exitNode.neighbors.Count; connected += bridges.ElementAt(i - 2).neighbors.Count; for (int j = 0; j < numberOfNodesInZone; j++) { connected += newZone.nodesInZone.ElementAt(j).neighbors.Count; } while (Convert.ToDouble(connected / (numberOfNodesInZone + 2)) > 3) { n1 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); while (n1.neighbors.Count <= 1) { n1 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); } n2 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); while (n2.neighbors.Count <= 1 || n2.id == n1.id || !n2.alreadyConnected(n1)) { n2 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); } n1.disconnect(n2); Logger.log("Nodes " + n1.id + " " + n2.id + " are disconnected"); connected -= 2; } } else { Node n1, n2; connected = bridges.ElementAt(i - 2).neighbors.Count; for (int j = 0; j < numberOfNodesInZone; j++) { connected += newZone.nodesInZone.ElementAt(j).neighbors.Count; } while (Convert.ToDouble(connected / (numberOfNodesInZone + 1)) > 3) { n1 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); while (n1.neighbors.Count <= 1) { n1 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); } n2 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); while (n2.neighbors.Count <= 1 || n2.id == n1.id || !n2.alreadyConnected(n1)) { n2 = newZone.nodesInZone.ElementAt(random.Next(0, numberOfNodesInZone)); } n1.disconnect(n2); Logger.log("Nodes " + n1.id + " " + n2.id + " are disconnected"); connected -= 2; } } //pass to next zone Logger.log("Passing to next zone"); } //Add startnode, bridges and endnode foreach (Zone z in zones) { if (z.id == 1) //first zone, add start node { z.nodesInZone.Add(startNode); } else if (z.id == level) //last zone, add end node { z.nodesInZone.Add(exitNode); } if (z.id != level) //in middle zones, add their bridges { z.nodesInZone.Add(bridges.ElementAt(z.id - 1)); } } }
/* Generates Random graph for dungeon class, uses const max_size, magicshuffle_number and regular dungeon options. */ public void genGraph() { int cnt = 0; //Generate all zones: for (int i = 0; i < (difficultyLevel + 1); i++) { int rSize = RandomGenerator.rnd.Next(2, max_size); //random size for current zone Node tmpStart = new Node(); //startpoint of current zone (exitpoint of last zone) Node tmpExit = new Node(); //exitpoint of current zone, bridge or exitnode. if (i == 0) //first zone. { startNode = new Node("0"); startNode.visited = true; graph.Add(startNode); tmpStart = startNode; Bridge b = new Bridge("" + (rSize - 1)); graph.Add(b); bridges[i] = b; tmpExit = b; } else if (i < difficultyLevel) //not first not last zone. { tmpStart = bridges[i - 1]; Bridge b = new Bridge("" + (rSize + cnt - 1)); graph.Add(b); tmpExit = b; bridges[i] = b; } else if (i == difficultyLevel) //last zone. { tmpStart = bridges[i - 1]; exitNode = new Node("" + (rSize + cnt - 1)); graph.Add(exitNode); tmpExit = exitNode; } Node[] nodeArray = new Node[rSize]; nodeArray[0] = tmpStart; nodeArray[rSize - 1] = tmpExit; for (int j = 1; j < (rSize - 1); j++) //we now know how big and what the tmp start/exit is. { Node n = new Node("" + (cnt + j)); //build nodes graph.Add(n); nodeArray[j] = n; } bool once = false; int shuffle = 0; //TODO remove node array only use shuffle array. Node[] shuffleArray = new Node[rSize - 2]; //nodes we want to shuffle Array.Copy(nodeArray, 1, shuffleArray, 0, rSize - 2); //Build zone until correct while ((Predicates.countNumberOfBridges(tmpStart, tmpExit) != 0) || !once) { //connect and shuffle the nodes random: shuffle_connect(shuffleArray, (rSize - 2), magic_shuffle_number); //MSN should be 1. but incase somebody want to change it.. tmpExit.neighbors.Clear(); if (i > 0) { foreach (Node x in bridges[i - 1].toNodes.ToList()) { tmpStart.disconnect(x); tmpStart.neighbors.Remove(x); } bridges[i - 1].toNodes.Clear(); } else { tmpStart.neighbors.Clear(); } int a = Utils.RandomGenerator.rnd.Next(1, rSize); int b = a; if (rSize != 2) { while (b == a) { b = Utils.RandomGenerator.rnd.Next(1, rSize); } } tmpStart.connect(nodeArray[a]); nodeArray[a].connect(tmpStart); tmpStart.connect(nodeArray[b]); nodeArray[b].connect(tmpStart); if (i > 0) { bridges[i - 1].connectToNodeOfNextZone(nodeArray[a]); bridges[i - 1].connectToNodeOfNextZone(nodeArray[b]); } if (nodeArray[a].id == tmpExit.id || nodeArray[b].id == tmpExit.id) { a = Utils.RandomGenerator.rnd.Next(1, rSize - 1); if (i < difficultyLevel) { bridges[i].connectToNodeOfSameZone(nodeArray[a]); } tmpExit.connect(nodeArray[a]); nodeArray[a].connect(tmpExit); } else { a = Utils.RandomGenerator.rnd.Next(1, rSize - 1); b = a; while (b == a) { b = Utils.RandomGenerator.rnd.Next(1, rSize - 1); } if (i < difficultyLevel) { bridges[i].connectToNodeOfSameZone(nodeArray[a]); bridges[i].connectToNodeOfSameZone(nodeArray[b]); } tmpExit.connect(nodeArray[a]); nodeArray[a].connect(tmpExit); tmpExit.connect(nodeArray[b]); nodeArray[b].connect(tmpExit); } once = true; //Console.WriteLine("shuffle: " + shuffle); shuffle++; } // if (i == 0) cnt++; double t = 0; double avg = 0; for (int h = 0; h < rSize; h++) { double n = (double)nodeArray[h].neighbors.Count; t = t + n; } avg = avg + ((double)t / (double)rSize); Logger.log("zone " + i + " avg: " + avg); cnt = cnt + (rSize - 1); } }