public void removeConnection(Direction dir)
    {
        switch (dir)
        {
        case Direction.Right:
            rightConnection = null;
            break;

        case Direction.Left:
            leftConnection = null;
            break;

        case Direction.Up:
            upConnection = null;
            break;

        case Direction.Down:
            downConnection = null;
            break;
        }
    }
    public void setConnection(Direction dir, AlphabetNode node)
    {
        switch (dir)
        {
        case Direction.Right:
            rightConnection = node;
            break;

        case Direction.Left:
            leftConnection = node;
            break;

        case Direction.Up:
            upConnection = node;
            break;

        case Direction.Down:
            downConnection = node;
            break;
        }
    }
    private void TransformGraphIntoDungeon()
    {
        // Calculate dungeon dimensions
        int dungeonHeight = graph.getNumberNodes() * roomMaxTilesHeight * maxCorridorLengthWhenVertical;
        int dungeonWidth  = graph.getNumberNodes() * roomMaxTilesWidth * maxCorridorLengthWhenHorizontal;

        // Create dungeon grid
        dungeon = new Dungeon(dungeonHeight, dungeonWidth);
        dungeon.createDungeonGrid(dungeonTopLeftCellPosition, floorTileDimensions);
        // Place rooms in dungeon starting from the entrance (root node of the graph), given the productions rules, there can only be one level of rooms above the entrance and no rooms can be at its left
        int entranceTopLeftTileRow    = roomMaxTilesHeight + maxCorridorLengthWhenVertical;
        int entranceTopLeftTileColumn = 0;
        int entranceRandomRoomHeight  = Random.Range(roomMinTilesHeight, roomMaxTilesHeight);
        int entrnaceRandomRoomWidth   = Random.Range(roomMinTilesWidth, roomMaxTilesWidth);

        dungeon.getDungeonRooms().Add(new Room(dungeon, entranceTopLeftTileRow, entranceTopLeftTileColumn, entranceRandomRoomHeight, entrnaceRandomRoomWidth, floorTileDimensions, floorMaterial, wallHeight, wallMaterial));
        // Create a list with the nodes which room has already been placed
        Dictionary <AlphabetNode, Room> nodesWithRoom = new Dictionary <AlphabetNode, Room>();

        nodesWithRoom.Add(graph.getRootNode(), dungeon.getDungeonRooms()[0]);
        // Create a list with the far task nodes connected
        List <AlphabetNode> farTaskNodesConnected = new List <AlphabetNode>();
        // Create a list with the nodes that need to be visited
        List <AlphabetNode> nodesToVisit = new List <AlphabetNode>();

        nodesToVisit.Add(graph.getRootNode());
        // Create a room for each node and connect the rooms
        while (nodesToVisit.Count > 0)
        {
            AlphabetNode currentNode = nodesToVisit[0];
            bool         checkUp     = true;
            bool         checkDown   = true;
            // When the node is a far task node, a room is not created, only the connection
            if (currentNode is FarTaskNode && !farTaskNodesConnected.Contains(currentNode))
            {
                // Find in which direction is the other far task node connected to this one, given the production rules, far task nodes are only connected down or up
                if (currentNode.getConnection(Direction.Up) is FarTaskNode && nodesWithRoom.ContainsKey(currentNode.getConnection(Direction.Up)))
                {
                    ConnectFarTaskNodesRooms(nodesWithRoom[currentNode.getConnection(Direction.Up)], nodesWithRoom[currentNode]);
                    farTaskNodesConnected.Add(currentNode);
                    farTaskNodesConnected.Add(currentNode.getConnection(Direction.Up));
                    checkUp = false;
                }
                else if (currentNode.getConnection(Direction.Down) is FarTaskNode && nodesWithRoom.ContainsKey(currentNode.getConnection(Direction.Down)))
                {
                    ConnectFarTaskNodesRooms(nodesWithRoom[currentNode], nodesWithRoom[currentNode.getConnection(Direction.Down)]);
                    farTaskNodesConnected.Add(currentNode);
                    farTaskNodesConnected.Add(currentNode.getConnection(Direction.Down));
                    checkDown = false;
                }
            }
            // Check right connection
            if (currentNode.getConnection(Direction.Right) != null && !nodesWithRoom.ContainsKey(currentNode.getConnection(Direction.Right)))
            {
                CreateRoomAndConnectNodes(nodesWithRoom, nodesToVisit, currentNode, Direction.Right);
            }
            // Check left connection
            if (nodesToVisit[0].getConnection(Direction.Left) != null && !nodesWithRoom.ContainsKey(nodesToVisit[0].getConnection(Direction.Left)))
            {
                CreateRoomAndConnectNodes(nodesWithRoom, nodesToVisit, currentNode, Direction.Left);
            }
            // Check up connection
            if (checkUp && nodesToVisit[0].getConnection(Direction.Up) != null && !nodesWithRoom.ContainsKey(nodesToVisit[0].getConnection(Direction.Up)))
            {
                CreateRoomAndConnectNodes(nodesWithRoom, nodesToVisit, currentNode, Direction.Up);
            }
            // Check down connection
            if (checkDown && nodesToVisit[0].getConnection(Direction.Down) != null && !nodesWithRoom.ContainsKey(nodesToVisit[0].getConnection(Direction.Down)))
            {
                CreateRoomAndConnectNodes(nodesWithRoom, nodesToVisit, currentNode, Direction.Down);
            }
            // Remove first node in the list
            nodesToVisit.RemoveAt(0);
            // When the current node is the goal node, find the index of its room in the dungeon rooms list
            if (currentNode is GoalNode)
            {
                exitRoomIndex = dungeon.getDungeonRooms().IndexOf(nodesWithRoom[currentNode]);
            }
        }
    }
    private void CreateRoomAndConnectNodes(Dictionary <AlphabetNode, Room> nodesWithRoom, List <AlphabetNode> nodesToVisit, AlphabetNode currentNode, Direction dir)
    {
        // Choose random corridor length to separate the rooms by that distance
        int randomCorridorLength = 1;

        if (dir == Direction.Right || dir == Direction.Left)
        {
            randomCorridorLength = Random.Range(minCorridorLengthWhenHorizontal, maxCorridorLengthWhenHorizontal);
        }
        else
        {
            randomCorridorLength = Random.Range(minCorridorLengthWhenVertical, maxCorridorLengthWhenVertical);
        }
        // Choose random room width
        int randomRoomWidth = Random.Range(roomMinTilesWidth, roomMaxTilesWidth);
        // Choose random room height
        int randomRoomHeight = Random.Range(roomMinTilesHeight, roomMaxTilesHeight);
        // Calculate top left corner column and row based on the direction and the middle cell of corresponding external side to align the rooms as much as possible
        int topLeftCornerColumn = 0;
        int topLeftCornerRow    = 0;

        switch (dir)
        {
        case Direction.Right:
            int         rigthColumnTilesNumber = nodesWithRoom[nodesToVisit[0]].getTilesRightColumn().Count;
            DungeonCell rightColumnMiddleCell  = nodesWithRoom[nodesToVisit[0]].getTilesRightColumn()[rigthColumnTilesNumber / 2].getCorrespondingDungeonCell();
            topLeftCornerColumn = rightColumnMiddleCell.getCellColumnPositionInGrid() + randomCorridorLength + 1;
            topLeftCornerRow    = rightColumnMiddleCell.getCellRowPositionInGrid() - (randomRoomHeight / 2);
            break;

        case Direction.Left:
            int         leftColumnTilesNumber = nodesWithRoom[nodesToVisit[0]].getTilesLeftColumn().Count;
            DungeonCell leftColumnMiddleCell  = nodesWithRoom[nodesToVisit[0]].getTilesLeftColumn()[leftColumnTilesNumber / 2].getCorrespondingDungeonCell();
            topLeftCornerColumn = leftColumnMiddleCell.getCellColumnPositionInGrid() - randomCorridorLength - randomRoomWidth;
            topLeftCornerRow    = leftColumnMiddleCell.getCellRowPositionInGrid() - (randomRoomHeight / 2);
            break;

        case Direction.Up:
            int         upRowTilesNumber = nodesWithRoom[nodesToVisit[0]].getTilesUpRow().Count;
            DungeonCell upRowMiddleCell  = nodesWithRoom[nodesToVisit[0]].getTilesUpRow()[upRowTilesNumber / 2].getCorrespondingDungeonCell();
            topLeftCornerColumn = upRowMiddleCell.getCellColumnPositionInGrid() - (randomRoomWidth / 2);
            topLeftCornerRow    = upRowMiddleCell.getCellRowPositionInGrid() - randomCorridorLength - randomRoomHeight;
            break;

        case Direction.Down:
            int         downRowTilesNumber = nodesWithRoom[nodesToVisit[0]].getTilesDownRow().Count;
            DungeonCell downRowMiddleCell  = nodesWithRoom[nodesToVisit[0]].getTilesDownRow()[downRowTilesNumber / 2].getCorrespondingDungeonCell();
            topLeftCornerColumn = downRowMiddleCell.getCellColumnPositionInGrid() - (randomRoomWidth / 2);
            topLeftCornerRow    = downRowMiddleCell.getCellRowPositionInGrid() + randomCorridorLength + 1;
            break;
        }
        // Create room
        dungeon.getDungeonRooms().Add(new Room(dungeon, topLeftCornerRow, topLeftCornerColumn, randomRoomHeight, randomRoomWidth, floorTileDimensions, floorMaterial, wallHeight, wallMaterial));
        // Add node to lists
        nodesWithRoom.Add(currentNode.getConnection(dir), dungeon.getDungeonRooms()[dungeon.getDungeonRooms().Count - 1]);
        nodesToVisit.Add(currentNode.getConnection(dir));
        // Connect rooms
        dungeon.getDungeonCorridors().Add(new Corridor(dungeon, nodesWithRoom[currentNode], nodesWithRoom[currentNode.getConnection(dir)], floorTileDimensions, floorMaterial, wallHeight, wallMaterial));
    }
Exemple #5
0
    private int totalNodes;             // Number of nodes in the graph

    public Graph(StartNode startNode)
    {
        rootNode = startNode;
    }
Exemple #6
0
    // Method that will create the different nodes in the graphs and will organize them using the production rules
    public void GenerateMission(int minTaskNumber, int maxTaskNumber, int minOrganizeTaskTries, int maxOrganizeTaskTries, float probabiltyApplyOrganizationRule)
    {
        // Randomly choose the number task nodes
        int numberTaskNodes = Random.Range(minTaskNumber, maxTaskNumber);

        // Set the number of total nodes in the graph based on the number of task nodes plus the entance and goal nodes
        totalNodes = numberTaskNodes + 2;
        // Randomly choose the number of times the algorithm will try to apply the reorganize tasks production rules
        int numberOrganizeTaskTries = Random.Range(minOrganizeTaskTries, maxOrganizeTaskTries);

        // The graph always start with the start mission production rule
        ProductionRules.StartMission((StartNode)rootNode, this);
        // The first node to the right of the root of the graph is going to be always a task node
        TaskNode currentTaskNode = (TaskNode)rootNode.getConnection(Direction.Right);
        // The node to the right of the first task node is going to be always the goal node
        GoalNode goalNode = (GoalNode)currentTaskNode.getConnection(Direction.Right);

        // The first step to create the mission is to add all the tasks one by one
        for (int i = 0; i < numberTaskNodes; i++)
        {
            ProductionRules.AddTask(currentTaskNode, goalNode);
            currentTaskNode = (TaskNode)goalNode.getConnection(Direction.Left);
        }
        // The next and final step is to reorganize the tasks position starting from the right of the root node, at this stage the root is always going to be an entrance node and no rules can be applied to it
        AlphabetNode currentNode = rootNode.getConnection(Direction.Right);

        while (numberOrganizeTaskTries > 0)
        {
            // Decide whether to try apply rule from current node or go to the next one
            if (currentNode is TaskNode && !currentNode.isTerminal() && Random.Range(0.0f, 1.0f) < probabiltyApplyOrganizationRule)
            {
                // Get number of nodes from the current that are also non terminal task nodes towards the right
                AlphabetNode        nextRightNode = currentNode.getConnection(Direction.Right);
                List <AlphabetNode> connections   = new List <AlphabetNode>();
                // The biggest number of task nodes taken by a production rule is six
                for (int i = 0; i < 6; i++)
                {
                    if (nextRightNode != null && nextRightNode is TaskNode && !nextRightNode.isTerminal())
                    {
                        connections.Add(nextRightNode);
                        nextRightNode = nextRightNode.getConnection(Direction.Right);
                    }
                }
                // Apply production rules based on the number of right task connections from current node, when multiple rules can be applied, all of them have the same probability of being picked
                switch (connections.Count)
                {
                case 2:
                    // Only one rule can be applied
                    ProductionRules.ReorganizeThreeTasks((TaskNode)currentNode, (TaskNode)connections[0], (TaskNode)connections[1]);
                    break;

                case 3:
                    // Two rules can be applied
                    if (Random.Range(0.0f, 1.0f) > 0.5f)
                    {
                        ProductionRules.ReorganizeThreeTasks((TaskNode)currentNode, (TaskNode)connections[0], (TaskNode)connections[1]);
                    }
                    else
                    {
                        ProductionRules.ReorganizeFourTasks((TaskNode)currentNode, (TaskNode)connections[0], (TaskNode)connections[1], (TaskNode)connections[2]);
                    }
                    break;

                case 4:
                    // Three rules can be applied
                    float random = Random.Range(0.0f, 1.0f);
                    if (random < (1.0f / 3.0f))
                    {
                        ProductionRules.ReorganizeThreeTasks((TaskNode)currentNode, (TaskNode)connections[0], (TaskNode)connections[1]);
                    }
                    else if (random > (2.0f / 3.0f))
                    {
                        ProductionRules.ReorganizeFourTasks((TaskNode)currentNode, (TaskNode)connections[0], (TaskNode)connections[1], (TaskNode)connections[2]);
                    }
                    else
                    {
                        ProductionRules.ReorganizeFiveTasks((TaskNode)currentNode, (TaskNode)connections[0], (TaskNode)connections[1], (TaskNode)connections[2], (TaskNode)connections[3]);
                    }
                    break;

                case 5:
                    // Four rules can be applied
                    random = Random.Range(0.0f, 1.0f);
                    if (random < 0.25f)
                    {
                        ProductionRules.ReorganizeThreeTasks((TaskNode)currentNode, (TaskNode)connections[0], (TaskNode)connections[1]);
                    }
                    else if (random > 0.25f && random < 0.5f)
                    {
                        ProductionRules.ReorganizeFourTasks((TaskNode)currentNode, (TaskNode)connections[0], (TaskNode)connections[1], (TaskNode)connections[2]);
                    }
                    else if (random > 0.75f)
                    {
                        ProductionRules.ReorganizeFiveTasks((TaskNode)currentNode, (TaskNode)connections[0], (TaskNode)connections[1], (TaskNode)connections[2], (TaskNode)connections[3]);
                    }
                    else
                    {
                        ProductionRules.ReorganizeSixTasks((TaskNode)currentNode, (TaskNode)connections[0], (TaskNode)connections[1], (TaskNode)connections[2], (TaskNode)connections[3], (TaskNode)connections[4]);
                    }
                    break;
                }
            }
            // Get next node, try right first and down second
            AlphabetNode previousCurrent = currentNode;
            currentNode = currentNode.getConnection(Direction.Right);
            if (currentNode == null)
            {
                currentNode = previousCurrent.getConnection(Direction.Down);
            }
            // If the goal node is reached, try to apply the productions rules from the beginnig
            if (currentNode is GoalNode || currentNode == null)
            {
                currentNode = rootNode;
            }
            // Decrease tries
            numberOrganizeTaskTries--;
        }
    }
Exemple #7
0
 public void setRootNode(AlphabetNode node)
 {
     this.rootNode = node;
 }