Example #1
0
 public void addNeighbor(Node node, SpecialConnection settings = null, bool possibleDuplicate = false)
 {
     if (!possibleDuplicate && this.neighbors.Find(o => o.neighbor == node) != null)
     {
         throw new Exception("");
     }
     this.neighbors.Add(new Connection(node, settings));
 }
Example #2
0
 public Connection(NormalNode neighbor, SpecialConnection settings = null)
 {
     this.neighbor = neighbor;
     this.settings = settings;
 }
Example #3
0
        public void CreateDatabase()
        {
            Stopwatch sw;

            File.Delete("nodes.db");

            var doors = CreateDoors();

            sw = Stopwatch.StartNew();
            List <Node[, ]> nodeLists = new List <Node[, ]>();

            // Create the set of nodes for every map image
            for (int i = 0; i <= 15; i++)
            {
                nodeLists.Add(CreateNodes(mapImages[i], i, doors));
            }
            sw.Stop();
            Console.WriteLine("Create initial nodes {0}ms", sw.Elapsed.TotalMilliseconds);

            var specialConnections = CreateSpecialConnections(nodeLists);

            sw = Stopwatch.StartNew();
            // Now do some optimization stuff
            List <Node> allNodes       = new List <Node>();
            List <Node> highLevelNodes = new List <Node>();

            for (int k = 0; k <= 15; k++)
            {
                HashSet <Node> hierarchicalNodes = new HashSet <Node>();
                Node[,] nodes = nodeLists[k];
                for (int x = 0; x < mapImages[7].Width; x++)
                {
                    for (int y = 0; y < mapImages[7].Height; y++)
                    {
                        if (nodes[x, y] != null)
                        {
                            hierarchicalNodes.Add(nodes[x, y]);
                            nodes[x, y].parent = null;
                        }
                    }
                }

                // we create a layer above the 'base' nodes
                // this layer is used to speed up pathfinding significantly
                // basically, we create a high-level node that is the parent to a certain amount of nodes
                // it connects to other high level nodes that are reachable from the child-nodes
                // this is basically a high level 'filter' step that allows us to immediately discard a large number of paths early on
                // by first computing the path on these high level nodes (which is cheap because there are few of them)
                // we only need to consider paths that go through the high level nodes, filtering a significant amount of possible paths
                int childCount = 100; // this is the maximum amount of children for the hierachical node
                while (hierarchicalNodes.Count > 0)
                {
                    Node current = null;
                    foreach (Node n in hierarchicalNodes)
                    {
                        current = n;
                        break;
                    }
                    if (current == null)
                    {
                        break;
                    }

                    Node hierarchicalNode = new Node(current);

                    hierarchicalNode.children = new List <Node>();
                    List <Node> openSet = new List <Node> {
                        current
                    };
                    HashSet <Node> closedSet = new HashSet <Node>()
                    {
                        current
                    };
                    while (openSet.Count > 0 && hierarchicalNode.children.Count < childCount)
                    {
                        Node n = openSet[0];
                        openSet.RemoveAt(0);
                        hierarchicalNode.children.Add(n);
                        hierarchicalNodes.Remove(n);
                        if (n.parent != null)
                        {
                            throw new Exception("Already has a parent.");
                        }
                        n.parent = hierarchicalNode;
                        foreach (Connection conn in n.neighbors)
                        {
                            if (conn.settings != null)
                            {
                                continue;
                            }
                            Node neighbor = conn.neighbor as Node;
                            if (hierarchicalNodes.Contains(neighbor) && !closedSet.Contains(neighbor))
                            {
                                closedSet.Add(neighbor);
                                openSet.Add(neighbor);
                            }
                        }
                    }
                    // set up the bounding rectangles of the high level nodes
                    foreach (Node n in hierarchicalNode.children)
                    {
                        hierarchicalNode.Merge(n.rect);
                    }
                    highLevelNodes.Add(hierarchicalNode);
                }
            }

            // now set up the neighbors of the high level nodes
            // we check the neighbors of the low-level nodes, and check the high-level node they are part of
            // if they are part of a different high-level node, that high-level node is reachable from this high-level node, thus it is a neighbor
            for (int k = 0; k <= 15; k++)
            {
                foreach (Node hierarchicalNode in highLevelNodes)
                {
                    foreach (Node n in hierarchicalNode.children)
                    {
                        foreach (Connection conn in n.neighbors)
                        {
                            Node neighbor = conn.neighbor as Node;
                            if (neighbor.parent == null)
                            {
                                throw new Exception("Node without a parent.");
                            }
                            if (neighbor.parent != hierarchicalNode)
                            {
                                Connection existingConnection = hierarchicalNode.getNeighbor(neighbor.parent);
                                if (existingConnection == null)
                                {
                                    hierarchicalNode.addNeighbor(neighbor.parent, conn.settings);
                                }
                            }
                        }
                    }
                }
            }

            Node node = nodeLists[beginz][beginx, beginy];

            sw.Stop();
            Console.WriteLine("Create hierarchical stuff: {0}ms", sw.Elapsed.TotalMilliseconds);


            SQLiteConnection sqlconn = new SQLiteConnection(String.Format("Data Source={0};Version=3;", "nodes.db"));

            sqlconn.Open();
            SQLiteCommand command;

            command = new SQLiteCommand("CREATE TABLE Doors(x INTEGER, y INTEGER, z INTEGER, condition STRING)", sqlconn);
            command.ExecuteNonQuery();
            command = new SQLiteCommand("CREATE TABLE SpecialConnections(id INTEGER PRIMARY KEY AUTOINCREMENT, x1 INTEGER, y1 INTEGER, z1 INTEGER, x2 INTEGER, y2 INTEGER, z2 INTEGER, name STRING, cost INTEGER)", sqlconn);
            command.ExecuteNonQuery();
            command = new SQLiteCommand("CREATE TABLE HierarchicalNode(id INTEGER PRIMARY KEY AUTOINCREMENT, x INTEGER, y INTEGER, z INTEGER,  width INTEGER, height INTEGER)", sqlconn);
            command.ExecuteNonQuery();
            command = new SQLiteCommand("CREATE TABLE HierarchicalConnections(nodeid INTEGER, nodeid2 INTEGER, specialid INTEGER)", sqlconn);
            command.ExecuteNonQuery();

            using (SQLiteTransaction transaction = sqlconn.BeginTransaction()) {
                for (int i = 0; i < doors.Count; i++)
                {
                    foreach (var value in doors[i])
                    {
                        command = new SQLiteCommand(String.Format("INSERT INTO Doors(x, y, z, condition) VALUES ({0},{1},{2},{3})", value.Key.Item1, value.Key.Item2, i, value.Value == null ? "NULL" : String.Format("'{0}'", value.Value)), sqlconn, transaction);
                        command.ExecuteNonQuery();
                    }
                }

                foreach (Node n in highLevelNodes)
                {
                    command = new SQLiteCommand(String.Format("INSERT INTO HierarchicalNode(x, y, z, width, height) VALUES ({0},{1},{2},{3},{4})", n.rect.X, n.rect.Y, n.z, n.rect.Width, n.rect.Height), sqlconn, transaction);
                    command.ExecuteNonQuery();
                    command.CommandText = "select last_insert_rowid()";
                    int rowid = (int)(long)command.ExecuteScalar();
                    n.weight = rowid;
                }
                foreach (Node n in highLevelNodes)
                {
                    foreach (Connection c in n.neighbors)
                    {
                        int special_id = -1;
                        if (c.settings != null)
                        {
                            SpecialConnection connection = c.settings;
                            command = new SQLiteCommand(String.Format("INSERT INTO SpecialConnections(x1, y1, z1, x2, y2, z2, name, cost) VALUES ({0}, {1}, {2}, {3}, {4}, {5}, '{6}', {7});", connection.source.rect.X, connection.source.rect.Y, connection.source.z, connection.destination.rect.X, connection.destination.rect.Y, connection.destination.z, connection.name.Replace("'", "''"), connection.cost), sqlconn, transaction);
                            command.ExecuteNonQuery();
                            command.CommandText = "select last_insert_rowid()";
                            special_id          = (int)(long)command.ExecuteScalar();
                        }
                        command = new SQLiteCommand(String.Format("INSERT INTO HierarchicalConnections(nodeid, nodeid2, specialid) VALUES ({0},{1}, {2})", n.weight, (c.neighbor as Node).weight, special_id), sqlconn, transaction);
                        command.ExecuteNonQuery();
                    }
                }
                transaction.Commit();
            }
        }
Example #4
0
        public List <SpecialConnection> CreateSpecialConnections(List <Node[, ]> nodeLists)
        {
            Stopwatch sw;

            List <SpecialConnection> specialConnections = new List <SpecialConnection>();

            sw = Stopwatch.StartNew();
            // Add connections between floors created by stairs/rope holes (these are added if both image (i) and image (i + 1) have the color yellow at a pixel)
            for (int x = 0; x < mapImages[7].Width; x++)
            {
                for (int y = 0; y < mapImages[7].Height; y++)
                {
                    for (int i = 0; i < 15; i++)
                    {
                        if (nodeLists[i][x, y] != null && nodeLists[i][x, y].color == stairsColor)
                        {
                            Node other = null;
                            if (nodeLists[i + 1][x, y] != null && nodeLists[i + 1][x, y].color == stairsColor)
                            {
                                other = nodeLists[i + 1][x, y];
                            }
                            else if (nodeLists[i + 1][x + 1, y] != null && nodeLists[i + 1][x + 1, y].color == stairsColor)
                            {
                                other = nodeLists[i + 1][x + 1, y];
                            }
                            else if (nodeLists[i + 1][x - 1, y] != null && nodeLists[i + 1][x - 1, y].color == stairsColor)
                            {
                                other = nodeLists[i + 1][x - 1, y];
                            }
                            else if (nodeLists[i + 1][x, y - 1] != null && nodeLists[i + 1][x, y - 1].color == stairsColor)
                            {
                                other = nodeLists[i + 1][x, y - 1];
                            }
                            else if (nodeLists[i + 1][x, y + 1] != null && nodeLists[i + 1][x, y + 1].color == stairsColor)
                            {
                                other = nodeLists[i + 1][x, y + 1];
                            }
                            if (other != null)
                            {
                                SpecialConnection connection = new SpecialConnection {
                                    source = nodeLists[i][x, y], destination = other, cost = 50, name = "Stairs"
                                };
                                SpecialConnection connection2 = new SpecialConnection {
                                    source = other, destination = nodeLists[i][x, y], cost = 50, name = "Stairs"
                                };
                                specialConnections.Add(connection);
                                specialConnections.Add(connection2);
                                nodeLists[i][x, y].addNeighbor(other, connection);
                                other.addNeighbor(nodeLists[i][x, y], connection2);
                            }
                        }
                    }
                }
            }

            // Add connections that are stored in the teleports.xml file
            // These are teleports that cannot be deduced from the image files themselves (i.e. actual teleporters, boats)
            using (StreamReader str = new StreamReader("teleports.xml")) {
                using (XmlReader reader = XmlReader.Create(str)) {
                    Node   startNode = null, endNode = null;
                    string currentNode = null;
                    string startName   = "";
                    Dictionary <string, string> attributes = new Dictionary <string, string>();
                    while (reader.Read())
                    {
                        switch (reader.NodeType)
                        {
                        case XmlNodeType.Element:
                            currentNode = reader.Name;
                            attributes.Clear();
                            if (currentNode == "Destination")
                            {
                                attributes.Add("Name", reader.GetAttribute("Name"));
                                attributes.Add("Cost", reader.GetAttribute("Cost"));
                            }
                            break;

                        case XmlNodeType.Text:
                            if (currentNode == "Name")
                            {
                                startName = reader.Value;
                            }
                            else if (currentNode == "Start")
                            {
                                string[] split = reader.Value.Split(',');
                                int      x     = int.Parse(split[0]);
                                int      y     = int.Parse(split[1]);
                                int      z     = int.Parse(split[2]);
                                startNode = nodeLists[z][x, y];
                            }
                            else if (currentNode == "Destination")
                            {
                                string   name  = startName + " to " + attributes["Name"];
                                int      cost  = int.Parse(attributes["Cost"]);
                                string[] split = reader.Value.Split(',');
                                int      x     = int.Parse(split[0]);
                                int      y     = int.Parse(split[1]);
                                int      z     = int.Parse(split[2]);
                                endNode = nodeLists[z][x, y];

                                SpecialConnection connection = new SpecialConnection {
                                    source = startNode, destination = endNode, cost = cost, name = name
                                };
                                SpecialConnection connection2 = new SpecialConnection {
                                    source = endNode, destination = startNode, cost = cost, name = ReverseName(name)
                                };
                                specialConnections.Add(connection);
                                specialConnections.Add(connection2);
                                startNode.addNeighbor(endNode, connection);
                                endNode.addNeighbor(startNode, connection2);
                            }
                            break;

                        case XmlNodeType.XmlDeclaration:
                        case XmlNodeType.ProcessingInstruction:
                        case XmlNodeType.Comment:
                            break;

                        case XmlNodeType.EndElement:
                            currentNode = null;
                            if (reader.Name == "Teleport")
                            {
                                startNode = null;
                            }
                            break;
                        }
                    }
                }
            }
            // Add connections that are stored in the 'teleports' file
            using (StreamReader reader = new StreamReader("teleports")) {
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    string[] split = line.Split('-');
                    if (split.Length != 3)
                    {
                        continue;
                    }

                    string[] source  = split[0].Split(',');
                    string[] dest    = split[1].Split(',');
                    string   name    = split[2];
                    bool     one_way = false;
                    if (name.Contains(" ONE WAY"))
                    {
                        one_way = true;
                        name    = name.Replace(" ONE WAY", "");
                    }
                    int x, y, z;
                    x = int.Parse(source[0]);
                    y = int.Parse(source[1]);
                    z = int.Parse(source[2]);
                    Node startNode = nodeLists[z][x, y];
                    x = int.Parse(dest[0]);
                    y = int.Parse(dest[1]);
                    z = int.Parse(dest[2]);
                    Node endNode = nodeLists[z][x, y];

                    if (startNode == null || endNode == null)
                    {
                        Console.WriteLine(String.Format("Warning: {0}", line));
                        continue;
                    }

                    SpecialConnection connection;
                    if (!startNode.hasNeighbor(endNode))
                    {
                        connection = new SpecialConnection {
                            source = startNode, destination = endNode, cost = 100, name = name
                        };
                        specialConnections.Add(connection);
                        startNode.addNeighbor(endNode, connection);
                    }

                    if (!one_way)
                    {
                        if (!endNode.hasNeighbor(startNode))
                        {
                            connection = new SpecialConnection {
                                source = endNode, destination = startNode, cost = 100, name = ReverseName(name)
                            };
                            specialConnections.Add(connection);
                            endNode.addNeighbor(startNode, connection);
                        }
                    }
                }
            }

            sw.Stop();
            Console.WriteLine("Create teleports: {0}ms", sw.Elapsed.TotalMilliseconds);

            return(specialConnections);
        }
Example #5
0
 public Connection(NormalNode neighbor, SpecialConnection settings = null)
 {
     this.neighbor = neighbor;
     this.settings = settings;
 }
Example #6
0
 public void addNeighbor(Node node, SpecialConnection settings = null, bool possibleDuplicate = false)
 {
     if (!possibleDuplicate && this.neighbors.Find(o => o.neighbor == node) != null) {
         throw new Exception("");
     }
     this.neighbors.Add(new Connection(node, settings));
 }