pathfinding/astar/
astar.rs

1use crate::errors::my_errors::RetResult;
2use crate::map::{CloseList, IndexType, Map, MapType, Point};
3use async_trait::async_trait;
4use std::collections::BinaryHeap;
5use std::sync::{Arc};
6use tokio::fs::File;
7use tokio::io::AsyncReadExt;
8use serde::{Deserialize, Serialize};
9
10pub struct AStar {
11    pub col: usize,
12    pub row: usize,
13    pub map: Box<Vec<Vec<i32>>>,
14}
15
16#[derive(Serialize, Deserialize, Debug)]
17struct AstarMapFile {
18    #[serde(rename = "columnCount")]
19    pub column_count: usize,
20    #[serde(rename = "rowCount")]
21    pub row_count: usize,
22    #[serde(rename = "unWalkCells")]
23    pub un_walk_cells: Vec<usize>
24}
25
26#[async_trait]
27impl Map for AStar {
28    fn new() -> MapType {
29        Arc::new(tokio::sync::RwLock::new(AStar {
30            col: 0,
31            row: 0,
32            map: Box::<Vec<Vec<i32>>>::default(),
33        }))
34    }
35
36    fn load(&mut self, points: Vec<Vec<i32>>) -> RetResult<()> {
37        self.col = points[0].len();
38        self.row = points.len();
39        self.map = Box::new(points);
40        Ok(())
41    }
42
43    async fn load_from_file(&mut self, file_name: String) -> RetResult<()> {
44        // 打开文件
45        let mut file = File::open(file_name).await?;
46
47        // 创建一个缓冲区来存储文件内容
48        let mut buffer = Vec::new();
49
50        // 通过异步读取文件内容到缓冲区
51        file.read_to_end(&mut buffer).await?;
52
53        let mut x = Vec::new();
54        for i in buffer {
55            x.push(i as i32);
56            if x.len() == 16 {
57                self.map.push(x.clone());
58                x.clear();
59            }
60        }
61
62        self.col = self.map[0].len();
63        self.row = self.map.len();
64
65        Ok(())
66    }
67
68    async fn load_from_string(&mut self, file_contend: String) -> RetResult<()> {
69
70        // 打开文件
71        let deser: AstarMapFile = serde_json::from_str(&file_contend)?;
72
73        self.map = Box::new(vec![vec![0; deser.column_count]; deser.row_count]);
74
75        self.col = deser.column_count;
76        self.row = deser.row_count;
77
78        for i in 0..deser.un_walk_cells.len() {
79            self.map[deser.un_walk_cells[i] / self.col][deser.un_walk_cells[i] % self.col] = 1;
80        }
81
82        Ok(())
83    }
84
85    fn find_path(
86        &self,
87        start: (IndexType, IndexType),
88        end: (IndexType, IndexType),
89    ) -> Vec<(IndexType, IndexType)> {
90        let (start_x, start_y) = start;
91        let (end_x, end_y) = end;
92
93        let mut open_list = BinaryHeap::with_capacity(self.col + self.row);
94        let mut close_list = CloseList::new(self.col, self.row);
95        let mut parent = vec![vec![(0, 0); self.col]; self.row];
96        let mut g_score = vec![vec![i32::MAX; self.col]; self.row];
97        let mut f_score = vec![vec![i32::MAX; self.col]; self.row];
98
99        g_score[start_y as usize][start_x as usize] = 0;
100        f_score[start_y as usize][start_x as usize] = dis(start_x, start_y, end_x, end_y);
101
102        open_list.push(Point::new_other(
103            start_x,
104            start_y,
105            f_score[start_y as usize][start_x as usize],
106            0,
107            f_score[start_y as usize][start_x as usize],
108        ));
109
110        while let Some(current) = open_list.pop() {
111            if current.x == end_x && current.y == end_y {
112                let mut path = Vec::with_capacity(128);
113                let mut current = (end_x, end_y);
114                while current != (start_x, start_y) {
115                    path.insert(0,(current.0, current.1));
116                    current = parent[current.1 as usize][current.0 as usize];
117                }
118                path.insert(0,(start_x, start_y));
119                return path;
120            }
121
122            close_list.insert(&current);
123
124            for neighbor in current.neighbors() {
125                let ix = current.x + neighbor.0;
126                let iy = current.y + neighbor.1;
127                let x = ix as usize;
128                let y = iy as usize;
129
130                if !self.in_map(ix, iy) {
131                    continue;
132                }
133
134                let tentative_g_score = g_score[current.y as usize][current.x as usize] + 1;
135                if tentative_g_score <= g_score[y][x] {
136                    parent[y][x] = (current.x, current.y);
137                    g_score[y][x] = tentative_g_score;
138                    f_score[y][x] = tentative_g_score + dis(ix, iy, end_x, end_y);
139                    if !open_list.iter().any(|node| node.x == ix && node.y == iy) {
140                        open_list.push(Point::new_other(
141                            ix,
142                            iy,
143                            f_score[y][x],
144                            g_score[y][x],
145                            dis(ix, iy, end_x, end_y),
146                        ));
147                    }
148                }
149            }
150        }
151
152        vec![]
153    }
154
155    fn set_walkable(&mut self, point: (IndexType, IndexType), walkable: i32) {
156        self.map[point.1 as usize][point.0 as usize] = walkable;
157    }
158
159    #[inline]
160    fn in_map(&self, x: i32, y: i32) -> bool {
161        let x_usize = x as usize;
162        let y_usize = y as usize;
163
164        match (x, y) {
165            (x, y) if y < 0 || x < 0 => false,
166            (_x, _y) if y_usize >= self.row || x_usize >= self.col => false,
167            _ => self.map[y_usize][x_usize] == 0,
168        }
169    }
170}
171
172#[inline]
173pub fn dis(x: IndexType, y: IndexType, x1: IndexType, y1: IndexType) -> IndexType {
174    let xx = (x1 - x).abs();
175    let xy = (y1 - y).abs();
176
177    //第一种:用min来获取xx与xy较小的那一个,内部隐含match操作
178    //(xx, xy) * 14 +  (xx + xy) * 10
179
180    //第二种,不用if或者min函数,会非常快
181    let sum = (xx + xy) * 10;
182    let condition = (xx > xy) as i32; // 1 if xx > xy, 0 otherwise
183    (xy * 14 + sum) * (1 - condition) + (xx * 14 + sum) * condition
184}
185
186impl Drop for AStar {
187    fn drop(&mut self) {
188        self.map.clear()
189    }
190}