Пример #1
0
        public static void LoadFromDatabase(string databaseFile)
        {
            SQLiteConnection conn;
            SQLiteCommand command;
            SQLiteDataReader reader;

            conn = new SQLiteConnection(String.Format("Data Source={0};Version=3;", databaseFile));
            conn.Open();

            // First add a list for each of the 16 floors
            for (int k = 0; k <= 15; k++) {
                nodes.Add(new List<Node>());
            }
            // we keep a temporary <id,Node> map for adding connections
            Dictionary<int, Node> hnodeids = new Dictionary<int, Node>();
            // Read the hierarchical nodes
            command = new SQLiteCommand("SELECT id,x,y,z,width,height FROM HierarchicalNode", conn);
            reader = command.ExecuteReader();
            while (reader.Read()) {
                int id = reader.GetInt32(0);
                int x = reader.GetInt32(1);
                int y = reader.GetInt32(2);
                int z = reader.GetInt32(3);
                int width = reader.GetInt32(4);
                int height = reader.GetInt32(5);
                Node n = new Node(x, y, z, width, height);
                // add the node to the appropriate floor
                nodes[z].Add(n);
                // id-map
                hnodeids.Add(id, n);
            }
            // Now read the hierarchical connections from the database
            command = new SQLiteCommand("SELECT nodeid,nodeid2 FROM HierarchicalConnections", conn);
            reader = command.ExecuteReader();
            while (reader.Read()) {
                int nodeid = reader.GetInt32(0);
                int nodeid2 = reader.GetInt32(1);
                // Add the connection to the nodes, using the id-map to extract the nodes
                hnodeids[nodeid].neighbors.Add(hnodeids[nodeid2]);
                hnodeids[nodeid2].neighbors.Add(hnodeids[nodeid]);
            }
        }
Пример #2
0
 public static double Distance(Node a, Node b)
 {
     // Euclidean distance
     return Math.Sqrt(Math.Pow(a.rect.X - b.rect.X, 2) + Math.Pow(a.rect.Y - b.rect.Y, 2));
 }
Пример #3
0
        public static DijkstraNode FindRoute(Node start, Node goal)
        {
            // Dijkstra algorithm
            // We use Dijkstra instead of A* because there are random teleports in Tibia (e.g. boats)
            // And it is difficult to create a good A* heuristic that takes random teleports into account
            // and Dijkstra has more consistently good performance than A* with a bad heuristic
            List<DijkstraNode> openSet = new List<DijkstraNode> { new DijkstraNode(null, start, 0) };
            HashSet<Node> closedSet = new HashSet<Node>();

            while (openSet.Count > 0) {
                // Extract path with current minimal cost
                DijkstraNode current = GetMinimum(openSet);
                if (current.node == goal) {
                    return current;
                }
                // Add node to closed set
                openSet.Remove(current);
                closedSet.Add(current.node);

                // Iterate over all neighboring nodes
                foreach (Node neighbor in current.node.neighbors) {
                    if (closedSet.Contains(neighbor)) continue;

                    // If node is not in closed set, create a new path, we use conn.settings.cost for 'special' connections (e.g. teleports, stairs)
                    double newCost = current.cost + Distance(current.node, neighbor);

                    DijkstraNode neighborAStar = openSet.Find(o => o.node == neighbor);
                    if (neighborAStar == null) {
                        // The node is not in the open set; add it
                        openSet.Add(new DijkstraNode(current, neighbor, newCost));
                    } else if (neighborAStar.cost < newCost) {
                        // If the node is already in the open set and with a lower cost than this path, this path cannot be optimal, so skip it
                        continue;
                    } else {
                        // If the node is already in the open set but with a higher cost, remove it and add this node
                        openSet.Remove(neighborAStar);
                        openSet.Add(new DijkstraNode(current, neighbor, newCost));
                    }
                }
            }
            return null;
        }
Пример #4
0
 public DijkstraNode(DijkstraNode previous, Node node, double cost)
 {
     this.previous = previous;
     this.node = node;
     this.cost = cost;
 }
Пример #5
0
        public static void LoadFromDatabase(string databaseFile)
        {
            SQLiteConnection conn;
            SQLiteCommand command;
            SQLiteDataReader reader;

            conn = new SQLiteConnection(String.Format("Data Source={0};Version=3;", databaseFile));
            conn.Open();

            // First add a list for each of the 16 floors
            for (int k = 0; k <= 15; k++) {
                nodes.Add(new List<Node>());
            }
            // we keep a temporary <id,Node> map for adding connections
            Dictionary<int, Node> hnodeids = new Dictionary<int, Node>();
            // Read the hierarchical nodes
            command = new SQLiteCommand("SELECT id,x,y,z,width,height FROM HierarchicalNode", conn);
            reader = command.ExecuteReader();
            while (reader.Read()) {
                int id = reader.GetInt32(0);
                int x = reader.GetInt32(1);
                int y = reader.GetInt32(2);
                int z = reader.GetInt32(3);
                int width = reader.GetInt32(4);
                int height = reader.GetInt32(5);
                Node n = new Node(x, y, z, width, height);
                // add the node to the appropriate floor
                nodes[z].Add(n);
                // id-map
                hnodeids.Add(id, n);
            }
            Dictionary<int, SpecialConnection> connectionMap = new Dictionary<int, SpecialConnection>();
            command = new SQLiteCommand("SELECT id, x1,y1,z1,x2,y2,z2,name,cost FROM SpecialConnections", conn);
            reader = command.ExecuteReader();
            while (reader.Read()) {
                int id = reader.GetInt32(0);
                Coordinate source = new Coordinate(reader.GetInt32(1), reader.GetInt32(2), reader.GetInt32(3));
                Coordinate dest = new Coordinate(reader.GetInt32(4), reader.GetInt32(5), reader.GetInt32(6));
                string name = reader[7].ToString();
                int cost = reader.GetInt32(8);
                if (!specialConnection.ContainsKey(source.z)) specialConnection.Add(source.z, new Dictionary<Tuple<int, int>, List<SpecialConnection>>());
                Tuple<int, int> tpl = new Tuple<int, int>(source.x, source.y);
                if (!specialConnection[source.z].ContainsKey(tpl)) specialConnection[source.z].Add(tpl, new List<SpecialConnection>());
                SpecialConnection connection = new SpecialConnection { source = source, destination = dest, name = name, cost = cost };
                specialConnection[source.z][tpl].Add(connection);
                connectionMap.Add(id, connection);
            }
            // Now read the hierarchical connections from the database
            command = new SQLiteCommand("SELECT nodeid,nodeid2, specialid FROM HierarchicalConnections", conn);
            reader = command.ExecuteReader();
            while (reader.Read()) {
                int nodeid = reader.GetInt32(0);
                int nodeid2 = reader.GetInt32(1);
                int specialConnection = reader.GetInt32(2);
                SpecialConnection connection = null;
                if (specialConnection >= 0) {
                    connection = connectionMap[specialConnection];
                }
                // Add the connection to the nodes, using the id-map to extract the nodes
                hnodeids[nodeid].neighbors.Add(new Connection(hnodeids[nodeid2], connection));
            }
            for (int i = 0; i <= 15; i++) {
                doors.Add(new Dictionary<Tuple<int, int>, string>());
            }
            command = new SQLiteCommand("SELECT x,y,z,condition FROM Doors", conn);
            reader = command.ExecuteReader();
            while (reader.Read()) {
                int x = reader.GetInt32(0);
                int y = reader.GetInt32(1);
                int z = reader.GetInt32(2);
                string condition = reader.IsDBNull(3) ? null : reader[3].ToString();
                doors[z].Add(new Tuple<int, int>(x, y), condition);
            }
        }
Пример #6
0
 public static double Distance(Node node, Point3D goal)
 {
     return Math.Abs(node.z - goal.Z) * 100 + node.rect.Distance(new Point(goal.X, goal.Y));
 }
Пример #7
0
 public Connection(Node node, SpecialConnection connection = null)
 {
     this.node = node;
     this.connection = connection;
 }
Пример #8
0
        public static DijkstraNode FindRoute(Node start, Node goal, Point3D exactGoal, DijkstraNode previousPath = null)
        {
            // Dijkstra algorithm
            // We use Dijkstra instead of A* because there are random teleports in Tibia (e.g. boats)
            // And it is difficult to create a good A* heuristic that takes random teleports into account
            // and Dijkstra has more consistently good performance than A* with a bad heuristic
            List<DijkstraNode> openSet = new List<DijkstraNode> { new DijkstraNode(null, new Connection(start), 0) };
            HashSet<Node> closedSet = new HashSet<Node>();

            double closestDistance = double.MaxValue;
            DijkstraNode closestNode = null;

            Dictionary<Node, DijkstraNode> nodes = new Dictionary<Node, DijkstraNode>();
            if (previousPath != null) {
                DijkstraNode it = previousPath;
                DijkstraNode prevNode = null;
                while(it != null) {
                    if (it.node == start) {
                        it.previous = null;
                        it.connection = new Connection(it.node);
                        return previousPath;
                    }
                    if (prevNode != null && !nodes.ContainsKey(prevNode.node)) {
                        nodes.Add(prevNode.node, it);
                    }
                    prevNode = it;
                    it = it.previous;
                }
            }

            while (openSet.Count > 0) {
                // Extract path with current minimal cost
                DijkstraNode current = GetMinimum(openSet);
                if (current.node == goal) {
                    return current;
                }
                if (nodes.ContainsKey(current.node)) {
                    DijkstraNode node = nodes[current.node];
                    node.previous = current;
                    return previousPath;
                }
                double distance = Distance(current.node, exactGoal);
                if (distance < closestDistance) {
                    closestNode = current;
                    closestDistance = distance;
                }
                // Add node to closed set
                openSet.Remove(current);
                closedSet.Add(current.node);

                // Iterate over all neighboring nodes
                foreach (Connection neighbor in current.node.neighbors) {
                    if (closedSet.Contains(neighbor.node)) continue;

                    // If node is not in closed set, create a new path, we use conn.settings.cost for 'special' connections (e.g. teleports, stairs)
                    double newCost = current.cost + (neighbor.connection == null ? Distance(current.node, neighbor.node) : 100);

                    DijkstraNode neighborAStar = openSet.Find(o => o.node == neighbor.node);
                    if (neighborAStar == null) {
                        // The node is not in the open set; add it
                        openSet.Add(new DijkstraNode(current, neighbor, newCost));
                    } else if (neighborAStar.cost < newCost) {
                        // If the node is already in the open set and with a lower cost than this path, this path cannot be optimal, so skip it
                        continue;
                    } else {
                        // If the node is already in the open set but with a higher cost, remove it and add this node
                        openSet.Remove(neighborAStar);
                        openSet.Add(new DijkstraNode(current, neighbor, newCost));
                    }
                }
            }
            return closestNode;
        }
Пример #9
0
 public static double Distance(Node node, Point3D goal)
 {
     return Math.Abs(node.z - goal.Z) * 100 + Distance(node.x, node.y, goal.X, goal.Y);
 }