public void MSTest_shortestpath() { Node node1 = new Node("1_1"); Node node2 = new Node("1_2"); Node node3 = new Node("1_3"); Node node4 = new Node("1_4"); Node node5 = new Node("1_5"); node2.connect(node1); node2.connect(node3); node4.connect(node1); node4.connect(node5); node5.connect(node3); Dungeon d = new Dungeon(); d.zone = new Dictionary <int, List <Node> >(); d.zone[1] = new List <Node>(); d.zone[1].Add(node1); d.zone[1].Add(node2); d.zone[1].Add(node3); d.zone[1].Add(node4); d.zone[1].Add(node5); List <Node> sp = d.shortestpath(node1, node3); List <Node> expectedSp = new List <Node>(); expectedSp.Add(node2); expectedSp.Add(node3); Assert.IsTrue(sp.Count == 2); Assert.IsTrue(sp[0] == expectedSp[0]); Assert.IsTrue(sp[1] == expectedSp[1]); }
public void NTest_check_fullyConnected_notConnected() { Node n1 = new Node("" + 0, 1); Node n2 = new Node("" + 1, 1); Node n3 = new Node("" + 2, 1); Node n4 = new Node("" + 3, 1); Node n5 = new Node("" + 4, 1); n1.connect(n2); n1.connect(n3); n1.connect(n4); n1.connect(n5); Assert.IsTrue(n1.isFullyConnected()); }
public void randomConnection(Node thisNode, Node[] toNodes) { int l = toNodes.Length; if (l == 0) { return; // no nodes to connect to (this is a valid situation) } if (thisNode.neighbors.Count >= maxConnectivity) { return; // thisNode is not allowed to have more neigbours } int index = 0; index = r.Next(l - 1); if (toNodes[index] == thisNode) { return; } if (toNodes[index].neighbors.Count >= maxConnectivity) { return; } if (!thisNode.neighbors.Contains(toNodes[index])) { thisNode.connect(toNodes[index]); } }
public void MSTest_combat_pack_not_flees_does_attack_dies() { Game game = new Game(); game.dungeon = new Dungeon(); Utils.RandomGenerator.initializeWithSeed(0); Random r = Utils.RandomGenerator.rnd; game.player = new Player(); Pack pack = new Pack("pack", 1); pack.members[0].HP = 7; pack.startingHP = 7; Node fightNode = new Node(0); Node retreatNode = new Node(0); game.player.location = fightNode; game.player.dungeon = game.dungeon; game.dungeon.zone.Add(1, new List <Node>()); pack.location = game.player.location; game.dungeon.zone[1].Add(fightNode); game.dungeon.zone[1].Add(retreatNode); game.player.zone = 1; fightNode.packs.Add(pack); fightNode.connect(retreatNode); while (fightNode.contested(game.player)) { game.update(new AttackCommand(pack.members[0].id)); } Assert.IsTrue(!fightNode.contested(game.player)); Assert.IsTrue(fightNode.packs.Count == 0); Assert.IsTrue(game.player.KillPoint == 1); }
/* To disconnect a bridge from the rest of the zone the bridge is in. */ public void disconnect(Bridge b) { Logger.log("Disconnecting the bridge " + b.id + " from its zone."); Node newStart = new Node(b.id); newStart.neighbors = b.neighbors; newStart.nodeLevel = b.nodeLevel; Node[] allNodes = new Node[b.neighbors.Count]; b.neighbors.CopyTo(allNodes); foreach (Node n in allNodes.ToList()) { if (b.toNodes.Contains(n)) { newStart.connect(n); } n.disconnect(b); } startNode = newStart; }
public void NTest_shortestpath() { List <Node> nodes = new List <Node>(); Node n1, n2; Node startNode = new Node("" + 0, 1); nodes.Add(startNode); for (int i = 1; i <= 10; i++) { Node newNode = new Node("" + (i), 1); nodes.Add(newNode); } for (int i = 1; i <= 3; i++) { startNode.connect(nodes.ElementAt(i)); } for (int i = 3; i < 9; i++) { n1 = nodes.ElementAt(i + 1); n2 = nodes.ElementAt(i + 2); nodes.ElementAt(i).connect(n1); nodes.ElementAt(i).connect(n2); } List <Node> listToCheck = new List <Node>(); List <Node> pathToCheck = new List <Node>(); pathToCheck.Add(nodes.ElementAt(3)); listToCheck.Add(nodes.ElementAt(3)); for (int i = 4; i <= 10; i++) { listToCheck.Add(nodes.ElementAt(i)); i++; } Assert.AreSame(listToCheck, dungeon.shortestpath(nodes.ElementAt(3), nodes.ElementAt(10))); }
public void NTest_check_allReachable() { List <Node> nodes = new List <Node>(); Node n1, n2; Node startNode = new Node("" + 10, 1); nodes.Add(startNode); for (int i = 1; i <= 10; i++) { Node newNode = new Node("" + (10 + i), 1); nodes.Add(newNode); } for (int i = 1; i <= 3; i++) { startNode.connect(nodes.ElementAt(i)); } for (int i = 3; i < 9; i++) { n1 = nodes.ElementAt(i + 1); n2 = nodes.ElementAt(i + 2); nodes.ElementAt(i).connect(n1); nodes.ElementAt(i).connect(n2); } Assert.IsTrue(dungeon.allReachable(nodes, startNode)); }
public void DungeonIsValidTest_2() { Dungeon a = new Dungeon(1, 1); a.dungeon_size = a.graph.Count; a.graph.Clear(); Node u = new Node(); a.graph.Add(u); Assert.AreEqual(false, a.dungeon_is_ok()); Node v = new Node(); Node w = new Node(); Node x = new Node(); u.id = ("" + 0); v.id = ("" + 1); w.id = ("" + 2); x.id = ("" + 3); a.graph.Add(v); a.graph.Add(w); a.graph.Add(x); u.connect(v); v.connect(w); w.connect(x); a.startNode = u; a.exitNode = x; a.dungeon_size = a.graph.Count; Assert.AreEqual(false, a.dungeon_is_ok()); }
public Node[] genSubPath(int n, Node entryNode, Node endNode, int idMod, int lvl) { Node[] path = new Node[n]; path[0] = new Node(lvl + "_" + idMod); for (int i = 1; i < n; i++) { path[i] = new Node(lvl + "_" + (2 * (i) + idMod)); path[i].connect(path[i - 1]); } if (entryNode.GetType() == typeof(Bridge)) { connectBridge((entryNode as Bridge), path[0], false); } else { entryNode.connect(path[0]); } if (endNode.GetType() == typeof(Bridge)) { connectBridge((endNode as Bridge), path[n - 1], true); } else { endNode.connect(path[n - 1]); } return(path); }
public void MSTest_connect_nodes() { Node baseNode = new Node("baseNode"); Node nbNode = new Node("nbNode"); baseNode.connect(nbNode); Assert.IsTrue(baseNode.neighbors.Contains(nbNode)); Assert.IsTrue(nbNode.neighbors.Contains(baseNode)); }
// To create a consistent dummy dungeon to test Pack movement on public Dungeon(uint M) { this.M = M; Node N0 = new Node("1_0"); Node N1 = new Node("1_1"); Node N2 = new Node("1_2"); Node N3 = new Node("1_3"); N0.connect(N1); N0.connect(N2); N1.connect(N2); List <Node> nodes = new List <Node>(); nodes.Add(N0); nodes.Add(N1); nodes.Add(N2); nodes.Add(N3); zone = new Dictionary <int, List <Node> >(); zone.Add(1, nodes); }
public void MSTest_RandomConnection_connect_multiple_node_graph() { Node node1 = new Node(); Node node2 = new Node(); Node node3 = new Node(); node2.connect(node1); node2.connect(node3); Node[] graph = new Node[3]; graph[0] = node1; graph[1] = node2; graph[2] = node3; Node testnode = new Node("test"); Dungeon d = new Dungeon(); d.randomConnection(testnode, graph); Assert.IsTrue(testnode.neighbors.Count == 1); Node result = testnode.neighbors[0]; Assert.IsTrue(result.neighbors.Contains(testnode)); }
public void Crystal_Use_OnNode() { Node N0 = new Node("N0"); Node N1 = new Node("N1"); Node N2 = new Node("N2"); Node N3 = new Node("N3"); N1.connect(N0); N1.connect(N2); N1.connect(N3); N3.connect(N2); Predicates utils = new Predicates(); List <Node> mockDungeon = utils.reachableNodes(N1); player.dungeon = new Dungeon(1, 1); player.location = N1; Crystal crystal = new Crystal("crystal1"); player.bag.Add(crystal); player.use(crystal); Assert.IsTrue(crystal.used); Assert.IsFalse(player.bag.Contains(crystal)); Assert.IsTrue(player.accelerated); Assert.IsTrue(mockDungeon.Contains(N0)); Assert.IsNull(player.name); Assert.AreEqual(0, player.HP); Assert.AreEqual(5u, player.AttackRating); Assert.AreEqual(100, player.HPbase); Assert.AreEqual(0u, player.KillPoint); foreach (Node node in mockDungeon) { Console.WriteLine(node.id); } }
public void MSTest_pack_moveTowards() { Pack pack = new Pack("Highlander", 1); Dungeon dungeon = new Dungeon(2, 2); Node node = new Node("node1"); Node node2 = new Node("node2"); Node node3 = new Node("node3"); Node node4 = new Node("node4"); Node node5 = new Node("node5"); Node node6 = new Node("node6"); node.connect(node2); node2.connect(node3); node3.connect(node4); node.connect(node5); node5.connect(node2); node6.connect(node); pack.location = node; pack.dungeon = dungeon; node.packs.Add(pack); pack.moveTowards(node4); Assert.AreEqual(pack.location, node2); }
public void MSTest_RandomConnection_thisnode_max_neighbors() { Node maxConnectionNode = new Node("maxConnectionNode"); Node[] graph = new Node[5]; Node graphnode = new Node(); graph[4] = graphnode; for (int i = 0; i < 4; i++) { Node neighbor = new Node("neighbor " + i); maxConnectionNode.connect(neighbor); } Dungeon d = new Dungeon(); d.randomConnection(maxConnectionNode, graph); Assert.IsTrue(maxConnectionNode.neighbors.Count == 4); }
public void MSTest_MoveCommand() { Node n1 = new Node("n1"); Node n2 = new Node("n2"); Item item = new Item("test"); n2.items.Add(item); n1.connect(n2); Command moveCom = new MoveCommand(0); //Assert.IsTrue(moveCom.ToString() == "move to " + n2.id); Player player = new Player(); player.location = n1; moveCom.ExecuteCommand(player); Assert.IsTrue(player.location == n2); Assert.IsTrue(player.bag.Contains(item)); Assert.IsFalse(n2.items.Contains(item)); }
public void MSTest_fight_flee() { Node node = new Node(); Node node2 = new Node(); Player player = new Player(); Pack pack = new Pack("packo", 4); node.connect(node2); player.location = node; node.packs.Add(pack); pack.location = node; player.AddNextCommand(0); //node.fight(player); Assert.AreNotEqual(player.location, node); Assert.AreEqual(player.location, node2); }
public void ShortestPathTest() { Dungeon a = new Dungeon(1, 1); a.graph.Clear(); //Build a dungeon Node u = new Node(); Node v = new Node(); Node w = new Node(); Node x = new Node(); u.id = ("" + 0); v.id = ("" + 1); w.id = ("" + 2); x.id = ("" + 3); // 0 --> 1 --> 2 u.connect(v); v.connect(w); a.graph.Add(u); a.graph.Add(v); a.graph.Add(w); a.graph.Add(x); a.dungeon_size = a.graph.Count; // u --> v = 2 (Min path size) List <Node> result = Predicates.shortestpath(u, v, a.dungeon_size); Assert.AreEqual(Predicates.find_all_paths_extract_shortest(u, v, a.dungeon_size), result.Count); // u --> w = 3 (path size) result = Predicates.shortestpath(u, w, a.dungeon_size); Assert.AreEqual(Predicates.find_all_paths_extract_shortest(u, w, a.dungeon_size), result.Count); // u --> x = 0 (not possible) result = Predicates.shortestpath(u, x, a.dungeon_size); Assert.AreEqual(Predicates.find_all_paths_extract_shortest(u, x, a.dungeon_size), result.Count); }
public void DungeonIsValidTest_1() { Dungeon a = new Dungeon(10, 1); a.graph.Clear(); Node u = new Node(); Node v = new Node(); Node w = new Node(); Node x = new Node(); Node y = new Node(); Node z = new Node(); u.id = ("" + 0); v.id = ("" + 1); w.id = ("" + 2); x.id = ("" + 3); y.id = ("" + 4); z.id = ("" + 5); // 0 --> 1 --> 2 u.connect(v); v.connect(w); a.graph.Add(u); a.graph.Add(v); a.graph.Add(w); a.graph.Add(x); a.graph.Add(y); a.graph.Add(z); a.dungeon_size = a.graph.Count; bool result = a.dungeon_is_ok(); Assert.AreEqual(true, result); a.graph.Add(y); u.connect(w); u.connect(x); u.connect(y); u.connect(z); a.dungeon_size = a.graph.Count; result = a.dungeon_is_ok(); Assert.AreEqual(false, result); //clean a.graph.Clear(); u.neighbors.Clear(); v.neighbors.Clear(); w.neighbors.Clear(); x.neighbors.Clear(); y.neighbors.Clear(); z.neighbors.Clear(); u.connect(v); u.connect(w); u.connect(x); u.connect(y); v.connect(u); v.connect(w); v.connect(x); v.connect(y); w.connect(u); w.connect(v); w.connect(x); w.connect(y); x.connect(u); x.connect(w); x.connect(v); x.connect(y); y.connect(u); y.connect(w); y.connect(x); y.connect(v); a.graph.Add(u); a.graph.Add(v); a.graph.Add(w); a.graph.Add(x); a.graph.Add(y); a.dungeon_size = a.graph.Count; result = a.dungeon_is_ok(); Assert.AreEqual(false, result); }
public void CreateLevel(Node startNode, Node endNode) { // The number of nodes in this level. // There is no specification on the minimum or maximum nodes per level, so a number between 1 and 3 included seems adequate. // Note: that there is a minimum implied number of nodes per level of 1. This is because a dungeon must be at least // 3 nodes long (including the exit and entry node). int numberOfFirstPathNodes = RandomGenerator.rnd.Next(1, 4); int numberOfSecondPathNodes = RandomGenerator.rnd.Next(1, 4); // To ensue that there are no bridges within a level, 2 separate paths are created from entry to exit node. // Note: that these paths are not necessarily of the same length. List <Node> firstPath = new List <Node>(numberOfFirstPathNodes); List <Node> secondPath = new List <Node>(numberOfSecondPathNodes); // Populate the lists with nodes. for (int i = 0; i < Math.Max(numberOfFirstPathNodes, numberOfSecondPathNodes); i++) { // Create first path. if (i < numberOfFirstPathNodes) { Node newNode = new Node("n" + nodeNumber++); allNodes.Add(newNode); newNode.hint = Node.DrawingHint.Top; newNode.drawIndex = i; // Check if a previous node exists. if (i > 0) { // Connect the new node to the previous node to ensure a valid path. newNode.connect(firstPath[i - 1]); } firstPath.Add(newNode); } // Create second path. if (i < numberOfSecondPathNodes) { Node newNode = new Node("n" + nodeNumber++); allNodes.Add(newNode); newNode.hint = Node.DrawingHint.Bottom; newNode.drawIndex = i; // Check if a previous node exists. if (i > 0) { // Connect the new node to the previous node to ensure a valid path. newNode.connect(secondPath[i - 1]); } secondPath.Add(newNode); } } // Connect the start node of the level to first generated node for each path. // If the starting node is a bride then all newly generated nodes are next zone nodes. if (startNode is Bridge) { ((Bridge)(startNode)).connectToNodeOfNextZone(firstPath.First()); ((Bridge)(startNode)).connectToNodeOfNextZone(secondPath.First()); } // If it's not a bridge we can just connect to it. else { startNode.connect(firstPath.First()); startNode.connect(secondPath.First()); } // Connect the end node of the level to last generated node for each path. // If the end node is a bride then all newly generated nodes are same zone nodes. if (endNode is Bridge) { ((Bridge)(endNode)).connectToNodeOfSameZone(firstPath.Last()); ((Bridge)(endNode)).connectToNodeOfSameZone(secondPath.Last()); } // If it's not a bridge we can just connect to it. else { endNode.connect(firstPath.Last()); endNode.connect(secondPath.Last()); } // Total list of nodes, containing the two paths. List <Node> nodes = new List <Node>(); nodes.AddRange(firstPath); nodes.AddRange(secondPath); // Calculate the total number of neighbors. // This is the total amount of neighbors already made. int totalNumberOfNeighbors = startNode.neighbors.Count + endNode.neighbors.Count; nodes.ForEach(node => totalNumberOfNeighbors += node.neighbors.Count); // Calculate the total allowed number of neighbors. // The total allowed number of neighbors is the number of nodes + 2 (because the exit and entry node) times 3 (the avg allowed number of neighbors). int allowedNumberOfNeigbors = 3 * (nodes.Count + 2); // The number of extra connections between nodes. // This is the allowed number of neighbors minus the number of neighbor we already have. // The amount is then divided by 2 because a connection adds 2 neighbors. // Note: that there is a implicit floor() here because we cannot add a fractional amount of connections. int numberOfExtraConnections = (allowedNumberOfNeigbors - totalNumberOfNeighbors) / 2; // Create extra set of connections. for (int i = 0; i < numberOfExtraConnections; i++) { // Pick 2 nodes at random. Node firstNode = nodes[RandomGenerator.rnd.Next(nodes.Count)]; Node secondNode = nodes[RandomGenerator.rnd.Next(nodes.Count)]; // The following conditions must be met to create connection: if (firstNode != secondNode && // Not the same nodes, because we cannot add ourself as neighbor. firstNode.neighbors.Count < 4 && // Node must not already have 4 neighbors. secondNode.neighbors.Count < 4 && // Other node must not already have 4 neighbors. !firstNode.neighbors.Contains(secondNode) && // We may not already be neighbors with other node. !secondNode.neighbors.Contains(firstNode) // Other node may not be already neighbors with us (this is implied, but just for completeness). ) { firstNode.connect(secondNode); } } // Create 0 to 3 death end paths to add some complexity. int numberOfExtraNodes = RandomGenerator.rnd.Next(4); for (int i = 0; i < numberOfExtraNodes; i++) { // Pick a nodes at random. Node node = nodes[RandomGenerator.rnd.Next(nodes.Count)]; // Node must not already have 4 neighbors. // Note: that adding a death end path only creates a single extra connection and thus never exceeds the avg note connection of 3. if (node.neighbors.Count < 4) { Node newNode = new Node("n" + nodeNumber++); allNodes.Add(newNode); newNode.hint = Node.DrawingHint.Dangling; node.connect(newNode); } } }
/* 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); } }
/* 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)); } } }