Exemple #1
0
        /* 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));
                }
            }
        }