fast-astar 1.0.6 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,55 +1,291 @@
1
1
  # fast-astar
2
2
 
3
- fast-astar is an implementation of a* algorithm using javascript. Small and fast.
3
+ A high-performance A* pathfinding algorithm library with WebAssembly support. Small, fast, and memory-efficient.
4
4
 
5
- # Use
6
- Install fast-astar using npm or introduce Grid.js and Astar.js on the page
5
+ ## Features
6
+
7
+ - 🚀 **Multiple Implementations**: Ultra A*, Master A*, and WebAssembly A* with automatic selection
8
+ - ⚡ **High Performance**: Optimized for speed with WebAssembly support
9
+ - 💾 **Memory Efficient**: Sparse data structures for ultra-large maps (up to 100,000×100,000)
10
+ - 🎬 **Animation Support**: Full search process visualization with step-by-step callbacks
11
+ - 🌐 **Universal**: Works in Node.js, browsers, and Web Workers
12
+ - 📦 **Zero Dependencies**: Pure JavaScript/WebAssembly implementation
13
+
14
+ ## Installation
7
15
 
8
- **Install:**
9
16
  ```bash
10
- npm install fast-astar --save
17
+ npm install fast-astar
11
18
  ```
12
19
 
13
- **Install:**
20
+ ## Quick Start
21
+
22
+ ### Basic Usage
23
+
14
24
  ```javascript
15
- import {Grid,Astar} from "fast-astar";
25
+ import { Grid, Astar } from 'fast-astar';
16
26
 
17
27
  // Create a grid
18
- let grid = new Grid({
19
- col:11, // col
20
- row:7, // row
21
- render:function(){ // Optional, this method is triggered when the grid point changes
22
- // console.log(this);
23
- }
24
- });
25
-
26
- // Add obstacles to the grid
27
- [[5,2],[5,3],[5,4]].forEach(item => {
28
- grid.set(item,'value',1); // Values greater than 0 are obstacles
28
+ const grid = new Grid({
29
+ col: 20, // width
30
+ row: 15, // height
31
+ render: function() {
32
+ // Optional: called when grid points change (for animation)
33
+ }
34
+ });
35
+
36
+ // Add obstacles
37
+ grid.setWalkAt(5, 5, false); // Set obstacle at (5, 5)
38
+ grid.setWalkAt(6, 5, false);
39
+ grid.setWalkAt(7, 5, false);
40
+
41
+ // Create A* instance
42
+ const astar = new Astar(grid);
43
+
44
+ // Find path
45
+ const path = await astar.search(
46
+ [0, 0], // start point [x, y]
47
+ [19, 14], // end point [x, y]
48
+ {
49
+ rightAngle: false, // Allow diagonal movement (default: false)
50
+ optimalResult: true // Ensure optimal path (default: true)
51
+ }
52
+ );
53
+
54
+ console.log(path); // [[0,0], [1,1], [2,2], ...]
55
+ ```
56
+
57
+ ### Advanced Usage
58
+
59
+ ```javascript
60
+ import { Grid, Astar } from 'fast-astar';
61
+
62
+ // Create grid with memory-efficient mode for large maps
63
+ const grid = new Grid({
64
+ col: 10000,
65
+ row: 10000,
66
+ useMemoryEfficientMode: true // Enable for maps > 1000×1000
67
+ });
68
+
69
+ // Set obstacles in batch
70
+ const obstacles = [[5, 2], [5, 3], [5, 4], [10, 10]];
71
+ grid.setObstacles(obstacles);
72
+
73
+ // Create A* with specific algorithm preference
74
+ const astar = new Astar(grid, {
75
+ prefer: 'wasm', // 'ultra' | 'master' | 'wasm' | 'auto' (default)
76
+ strategy: 'auto' // 'auto' | 'performance' | 'memory' | 'compatibility'
77
+ });
78
+
79
+ // Search with options
80
+ const path = await astar.search(
81
+ [0, 0],
82
+ [9999, 9999],
83
+ {
84
+ rightAngle: false,
85
+ optimalResult: true
86
+ }
87
+ );
88
+
89
+ // Get current implementation info
90
+ const info = astar.getCurrentImplementation();
91
+ console.log(info.name); // e.g., "WebAssembly A*"
92
+ ```
93
+
94
+ ## API Reference
95
+
96
+ ### Grid
97
+
98
+ #### Constructor
99
+
100
+ ```javascript
101
+ new Grid(options)
102
+ ```
103
+
104
+ **Options:**
105
+ - `col` (number): Grid width (columns)
106
+ - `row` (number): Grid height (rows)
107
+ - `render` (function, optional): Callback function triggered when grid points change
108
+ - `useMemoryEfficientMode` (boolean, optional): Enable memory-efficient mode for large maps (>1000×1000)
109
+
110
+ #### Methods
111
+
112
+ - `setWalkAt(x, y, walkable)`: Set whether a cell is walkable
113
+ - `isWalkableAt(x, y)`: Check if a cell is walkable
114
+ - `setObstacles(obstacles)`: Set multiple obstacles at once (array of [x, y] pairs)
115
+ - `clearObstacles()`: Remove all obstacles
116
+ - `get([x, y])`: Get node at position
117
+ - `set([x, y], key, value)`: Set node property (for animation)
118
+
119
+ ### Astar
120
+
121
+ #### Constructor
122
+
123
+ ```javascript
124
+ new Astar(grid, options)
125
+ ```
126
+
127
+ **Options:**
128
+ - `prefer` (string): Preferred algorithm - `'ultra'` | `'master'` | `'wasm'` | `'auto'` (default)
129
+ - `strategy` (string): Selection strategy - `'auto'` | `'performance'` | `'memory'` | `'compatibility'`
130
+ - `avoid` (string): Algorithm to avoid
131
+ - `debug` (boolean): Enable debug logging
132
+
133
+ #### Methods
134
+
135
+ - `search(start, end, options)`: Find path from start to end
136
+ - Returns: `Promise<Array<[x, y]> | null>`
137
+ - Options:
138
+ - `rightAngle` (boolean): Only allow 4-directional movement (default: false)
139
+ - `optimalResult` (boolean): Ensure optimal path (default: true)
140
+ - `getCurrentImplementation()`: Get current algorithm implementation info
141
+ - `getPerformanceStats()`: Get performance statistics
142
+ - `getMemoryUsage()`: Get memory usage information
143
+
144
+ ## Algorithm Selection
145
+
146
+ The library automatically selects the optimal algorithm based on map size:
147
+
148
+ | Map Size | Algorithm | Performance |
149
+ |----------|-----------|-------------|
150
+ | ≤50×50 | Master A* | Best for small maps |
151
+ | 50×50 - 1000×1000 | WebAssembly A* | **17-25x faster** than JS |
152
+ | 1000×1000 - 10000×10000 | WebAssembly A* | **25x faster** than JS |
153
+ | ≥10000×10000 | WebAssembly A* (Sparse) | **18x faster** than JS |
154
+
155
+ ### Manual Selection
156
+
157
+ ```javascript
158
+ // Force specific algorithm
159
+ const astar = new Astar(grid, { prefer: 'wasm' });
160
+
161
+ // Performance priority
162
+ const astar = new Astar(grid, { strategy: 'performance' });
163
+
164
+ // Memory priority
165
+ const astar = new Astar(grid, { strategy: 'memory' });
166
+ ```
167
+
168
+ ## Animation Support
169
+
170
+ For visualization, provide a `render` callback in the Grid constructor:
171
+
172
+ ```javascript
173
+ const grid = new Grid({
174
+ col: 20,
175
+ row: 15,
176
+ render: function() {
177
+ // This is called during pathfinding
178
+ // Use grid.set([x, y], 'type', 'open'|'close'|'highlight'|'update')
179
+ // to track the search process
180
+ }
29
181
  });
30
182
 
31
- // Pass the grid as a parameter to the Astar object
32
- let astar = new Astar(grid),
33
- path = astar.search(
34
- [2,3], // start
35
- [8,3], // end
36
- { // option
37
- rightAngle:false, // default:false,Allow diagonal
38
- optimalResult:true // default:true,In a few cases, the speed is slightly slower
39
- }
40
- );
183
+ const astar = new Astar(grid);
184
+ const path = await astar.search([0, 0], [19, 14]);
185
+
186
+ // During search, the render callback will be triggered with:
187
+ // - 'open': Node added to open set
188
+ // - 'close': Node added to closed set
189
+ // - 'highlight': Current node being examined
190
+ // - 'update': Node cost updated
191
+ ```
192
+
193
+ ## Performance
194
+
195
+ Benchmark results (average of 3 runs):
196
+
197
+ | Map Size | WebAssembly A* | Ultra A* | Master A* |
198
+ |----------|----------------|----------|-----------|
199
+ | 100×100 | **0.12ms** | 1.9ms | 0.58ms |
200
+ | 500×500 | **2.3ms** | 37.9ms | 17.7ms |
201
+ | 1000×1000 | **9.6ms** | 167.7ms | 53.1ms |
202
+ | 5000×5000 | **1.0ms** | 25.7ms | 11.5ms |
203
+ | 10000×10000 | **2.3ms** | 58.6ms | 26.3ms |
204
+ | 50000×50000 | **20.6ms** | 369.4ms | - |
205
+ | 100000×100000 | **46.9ms** | 836.0ms | - |
206
+
207
+ ## Memory Optimization
208
+
209
+ For large maps (>1000×1000), enable memory-efficient mode:
210
+
211
+ ```javascript
212
+ const grid = new Grid({
213
+ col: 10000,
214
+ row: 10000,
215
+ useMemoryEfficientMode: true // Uses bitmap compression
216
+ });
217
+
218
+ // Memory usage comparison:
219
+ // - Standard mode: ~1.4GB for 10000×10000
220
+ // - Memory-efficient mode: ~12MB for 10000×10000
221
+ ```
222
+
223
+ For ultra-large maps (>10 billion nodes), WebAssembly automatically uses sparse HashMap implementation:
41
224
 
42
- console.log('Result',path); // [[2,3],[3,2],[4,1],[5,1],[6,1],[7,2],[8,3]]
225
+ ```javascript
226
+ // 100000×100000 map automatically uses sparse implementation
227
+ const grid = new Grid({ col: 100000, row: 100000 });
228
+ const astar = new Astar(grid, { prefer: 'wasm' });
229
+ // Automatically uses WebAssembly A* (Sparse) - only stores visited nodes
43
230
  ```
44
231
 
232
+ ## Building from Source
233
+
234
+ ### Prerequisites
235
+
236
+ - Rust (for WebAssembly compilation)
237
+ - wasm-pack
238
+ - Node.js 16+
239
+
240
+ ### Build Commands
241
+
242
+ ```bash
243
+ # Development build (faster compilation, includes debug info)
244
+ npm run build:dev
245
+
246
+ # Release build (optimized, smaller size)
247
+ npm run build:rel
248
+ ```
249
+
250
+ ### Testing
251
+
252
+ ```bash
253
+ # Run performance tests
254
+ npm test
255
+
256
+ # Full test suite (requires more memory)
257
+ npm run test:full
258
+
259
+ # WebAssembly-specific tests
260
+ npm run test:wasm
261
+ ```
262
+
263
+ ## Browser Support
264
+
265
+ - Chrome/Edge: ✅ Full support
266
+ - Firefox: ✅ Full support
267
+ - Safari: ✅ Full support (iOS 11.3+)
268
+ - Node.js: ✅ Full support (v16+)
269
+
270
+ ## License
271
+
272
+ MIT
273
+
274
+ ## Related
275
+
276
+ - [A* Search Algorithm (Wikipedia)](https://en.wikipedia.org/wiki/A*_search_algorithm)
277
+ - [A* Pathfinding for Beginners](https://www.gamedev.net/articles/programming/artificial-intelligence/a-pathfinding-for-beginners-r2003/)
45
278
 
46
- # Demo
47
- - [https://sbfkcel.github.io/fast-astar](https://sbfkcel.github.io/fast-astar)
279
+ ## Contributing
48
280
 
49
- # Related
50
- - [wiki](http://wikipedia.moesalih.com/A*_search_algorithm)
51
- - [achieve](https://www.gamedev.net/articles/programming/artificial-intelligence/a-pathfinding-for-beginners-r2003/)
281
+ Contributions are welcome! Please feel free to submit a Pull Request.
52
282
 
283
+ ## Changelog
53
284
 
54
- # License
55
- MIT
285
+ ### v0.1.0
286
+ - Initial release with WebAssembly support
287
+ - Multiple algorithm implementations (Ultra, Master, WASM)
288
+ - Automatic algorithm selection
289
+ - Memory-efficient mode for large maps
290
+ - Sparse implementation for ultra-large maps (100K×100K+)
291
+ - Animation support with step-by-step callbacks
package/astar.wasm ADDED
Binary file
package/index.js ADDED
@@ -0,0 +1,282 @@
1
+ // 🚀 A* 算法最终整合版本 - 智能自适应入口
2
+ // 自动选择最优算法实现,支持所有环境
3
+
4
+ import Grid from './Grid.js';
5
+ import Astar from './Astar.js';
6
+ import { isNode, isBrowser, getEnvironmentInfo, checkCompatibility, getPerformanceNow } from './utils.js';
7
+
8
+ // 便捷创建函数
9
+ function createAstar(gridOptions = {}, astarOptions = {}) {
10
+ const grid = new Grid(gridOptions);
11
+ return new Astar(grid, astarOptions);
12
+ }
13
+
14
+ // 快速路径查找
15
+ function quickPath(gridSize, obstacles = [], start = [0, 0], end = null) {
16
+ // 输入验证
17
+ if (typeof gridSize !== 'number' && !Array.isArray(gridSize)) {
18
+ throw new Error('gridSize 必须是数字或数组 [width, height]');
19
+ }
20
+
21
+ if (gridSize <= 0 || (Array.isArray(gridSize) && (gridSize[0] <= 0 || gridSize[1] <= 0))) {
22
+ throw new Error('网格大小必须大于0');
23
+ }
24
+
25
+ if (!Array.isArray(start) || start.length < 2) {
26
+ throw new Error('起点必须是包含至少2个元素的数组 [x, y]');
27
+ }
28
+
29
+ const size = Array.isArray(gridSize) ? gridSize : [gridSize, gridSize];
30
+ const grid = new Grid({ col: size[0], row: size[1] });
31
+
32
+ // 设置障碍物
33
+ if (obstacles.length > 0) {
34
+ if (!Array.isArray(obstacles)) {
35
+ throw new Error('障碍物必须是数组');
36
+ }
37
+ grid.setObstacles(obstacles);
38
+ }
39
+
40
+ // 默认终点为右下角
41
+ const endPoint = end || [size[0] - 1, size[1] - 1];
42
+
43
+ if (!Array.isArray(endPoint) || endPoint.length < 2) {
44
+ throw new Error('终点必须是包含至少2个元素的数组 [x, y]');
45
+ }
46
+
47
+ const astar = new Astar(grid);
48
+ return astar.search(start, endPoint);
49
+ }
50
+
51
+ // 批量路径查找
52
+ async function findMultiplePaths(gridOptions, pathRequests) {
53
+ // 输入验证
54
+ if (!gridOptions || (typeof gridOptions !== 'object' && typeof gridOptions !== 'number')) {
55
+ throw new Error('gridOptions 必须是对象或数字');
56
+ }
57
+
58
+ if (!Array.isArray(pathRequests)) {
59
+ throw new Error('pathRequests 必须是数组');
60
+ }
61
+
62
+ if (pathRequests.length === 0) {
63
+ return [];
64
+ }
65
+
66
+ const grid = new Grid(gridOptions);
67
+ const astar = new Astar(grid);
68
+
69
+ const results = [];
70
+ for (const request of pathRequests) {
71
+ try {
72
+ // 验证请求格式
73
+ if (!request || !Array.isArray(request.start) || !Array.isArray(request.end)) {
74
+ throw new Error('每个请求必须包含 start 和 end 数组');
75
+ }
76
+
77
+ const path = await astar.search(request.start, request.end, request.options || {});
78
+ results.push({
79
+ success: true,
80
+ path,
81
+ request
82
+ });
83
+ } catch (error) {
84
+ results.push({
85
+ success: false,
86
+ error: error.message,
87
+ request
88
+ });
89
+ }
90
+ }
91
+
92
+ return results;
93
+ }
94
+
95
+ // 性能基准测试
96
+ function benchmark(gridSize = 100, iterations = 100) {
97
+ // 输入验证
98
+ if (typeof gridSize !== 'number' || gridSize <= 0) {
99
+ throw new Error('gridSize 必须是大于0的数字');
100
+ }
101
+
102
+ if (typeof iterations !== 'number' || iterations <= 0) {
103
+ throw new Error('iterations 必须是大于0的数字');
104
+ }
105
+
106
+ if (iterations > 10000) {
107
+ console.warn('⚠️ 迭代次数过大,可能会影响性能');
108
+ }
109
+
110
+ const grid = new Grid({ col: gridSize, row: gridSize });
111
+ const astar = new Astar(grid);
112
+
113
+ // 预热
114
+ for (let i = 0; i < 10; i++) {
115
+ astar.search([0, 0], [gridSize - 1, gridSize - 1]);
116
+ }
117
+
118
+ // 测试
119
+ const startTime = getPerformanceNow();
120
+
121
+ for (let i = 0; i < iterations; i++) {
122
+ astar.search([0, 0], [gridSize - 1, gridSize - 1]);
123
+ }
124
+
125
+ const endTime = getPerformanceNow();
126
+ const totalTime = endTime - startTime;
127
+
128
+ return {
129
+ totalTime,
130
+ avgTime: totalTime / iterations,
131
+ throughput: iterations / (totalTime / 1000),
132
+ gridSize,
133
+ iterations
134
+ };
135
+ }
136
+
137
+ // 预设配置
138
+ const presets = {
139
+ // 游戏开发预设
140
+ game: {
141
+ strategy: 'performance',
142
+ appType: 'game',
143
+ performance: 'high',
144
+ memory: 'moderate',
145
+ prefer: 'wasm'
146
+ },
147
+
148
+ // Web应用预设
149
+ web: {
150
+ strategy: 'auto',
151
+ appType: 'web',
152
+ performance: 'medium',
153
+ memory: 'moderate'
154
+ },
155
+
156
+ // 移动应用预设
157
+ mobile: {
158
+ strategy: 'memory',
159
+ appType: 'mobile',
160
+ performance: 'medium',
161
+ memory: 'strict',
162
+ avoid: 'wasm'
163
+ },
164
+
165
+ // 服务端预设
166
+ server: {
167
+ strategy: 'performance',
168
+ appType: 'server',
169
+ performance: 'extreme',
170
+ memory: 'relaxed',
171
+ prefer: 'wasm'
172
+ },
173
+
174
+ // 嵌入式预设
175
+ embedded: {
176
+ strategy: 'memory',
177
+ appType: 'embedded',
178
+ performance: 'low',
179
+ memory: 'strict',
180
+ avoid: 'wasm'
181
+ }
182
+ };
183
+
184
+ // 预设工厂函数
185
+ function createPresetAstar(grid, presetName, customOptions = {}) {
186
+ const preset = presets[presetName];
187
+ if (!preset) {
188
+ throw new Error(`未知预设: ${presetName}. 可用预设: ${Object.keys(presets).join(', ')}`);
189
+ }
190
+
191
+ return new Astar(grid, { ...preset, ...customOptions });
192
+ }
193
+
194
+ // 智能创建函数 - 根据网格大小自动选择最佳配置
195
+ function createSmartAstar(gridOptions, customOptions = {}) {
196
+ const grid = new Grid(gridOptions);
197
+ const gridSize = grid.col * grid.row;
198
+
199
+ let autoOptions = {};
200
+
201
+ // 根据网格大小自动选择策略
202
+ if (gridSize > 250000) {
203
+ autoOptions = { strategy: 'performance', prefer: 'wasm' };
204
+ } else if (gridSize > 50000) {
205
+ autoOptions = { strategy: 'performance', prefer: 'master' };
206
+ } else if (gridSize > 10000) {
207
+ autoOptions = { strategy: 'auto' };
208
+ } else {
209
+ autoOptions = { strategy: 'compatibility' };
210
+ }
211
+
212
+ return new Astar(grid, { ...autoOptions, ...customOptions });
213
+ }
214
+
215
+ // 主要导出API
216
+ const AstarLib = {
217
+ // 核心类
218
+ Grid: Grid,
219
+ Astar: Astar,
220
+
221
+ // 工厂函数
222
+ create: createAstar,
223
+ createAstar,
224
+ createSmartAstar,
225
+ createPresetAstar,
226
+
227
+ // 便捷函数
228
+ quickPath,
229
+ findMultiplePaths,
230
+
231
+ // 工具函数
232
+ benchmark,
233
+ getEnvironmentInfo,
234
+ checkCompatibility,
235
+
236
+ // 预设配置
237
+ presets,
238
+
239
+ // 快速创建函数
240
+ createGameAstar: (grid, options = {}) => createPresetAstar(grid, 'game', options),
241
+ createWebAstar: (grid, options = {}) => createPresetAstar(grid, 'web', options),
242
+ createMobileAstar: (grid, options = {}) => createPresetAstar(grid, 'mobile', options),
243
+ createServerAstar: (grid, options = {}) => createPresetAstar(grid, 'server', options),
244
+ createEmbeddedAstar: (grid, options = {}) => createPresetAstar(grid, 'embedded', options),
245
+
246
+ // 版本信息
247
+ version: '2.0.0',
248
+ name: 'Smart A* Algorithm Library',
249
+
250
+ // 环境标识
251
+ isNode,
252
+ isBrowser
253
+ };
254
+
255
+ // 自动兼容性检查
256
+ const compatibility = checkCompatibility();
257
+ if (!compatibility.compatible) {
258
+ console.error('❌ 兼容性检查失败:', compatibility.issues);
259
+
260
+ // 在浏览器环境中,如果只是缺少一些API,不要抛出错误
261
+ if (isBrowser && compatibility.issues.length > 0) {
262
+ console.warn('⚠️ 浏览器环境兼容性问题,但将继续运行:', compatibility.issues);
263
+ } else {
264
+ throw new Error('环境不兼容: ' + compatibility.issues.join(', '));
265
+ }
266
+ }
267
+
268
+ if (compatibility.warnings.length > 0 && typeof console !== 'undefined') {
269
+ console.warn('⚠️ 兼容性警告:', compatibility.warnings);
270
+ }
271
+
272
+ // 初始化日志
273
+ if (typeof console !== 'undefined' && console.log) {
274
+ console.log('🚀 Smart A* Algorithm Library v2.0.0 已加载');
275
+ console.log('📱 环境:', compatibility.environment.platform);
276
+ console.log('💾 内存:', compatibility.environment.memory);
277
+ console.log('🖥️ CPU核心:', compatibility.environment.cores);
278
+ }
279
+
280
+ // ES Module 导出
281
+ export default AstarLib;
282
+ export { Grid, Astar, createAstar, createSmartAstar, quickPath, benchmark, presets };
package/package.json CHANGED
@@ -1,28 +1,30 @@
1
1
  {
2
2
  "name": "fast-astar",
3
- "version": "1.0.6",
3
+ "type": "module",
4
+ "version": "2.0.0",
4
5
  "description": "fast-astar is an implementation of a* algorithm using javascript. Small and fast.",
5
- "main": "dist/index.js",
6
- "scripts": {
7
- "test": "node test.js"
8
- },
6
+ "files": [
7
+ "astar.wasm",
8
+ "wasm.js",
9
+ "wasm.d.ts",
10
+ "index.js",
11
+ "Grid.js",
12
+ "Astar.js"
13
+ ],
14
+ "main": "index.js",
15
+ "types": "wasm.d.ts",
16
+ "sideEffects": [
17
+ "./snippets/*"
18
+ ],
9
19
  "repository": {
10
20
  "type": "git",
11
21
  "url": "git+https://github.com/sbfkcel/fast-astar.git"
12
22
  },
13
- "keywords": [
14
- "astar",
15
- "a-star",
16
- "a*",
17
- "algorithm",
18
- "graph",
19
- "traversal",
20
- "path search"
21
- ],
22
- "author": "sbfkcel@163.com",
23
- "license": "MIT",
24
- "bugs": {
25
- "url": "https://github.com/sbfkcel/fast-astar/issues"
26
- },
27
- "homepage": "https://github.com/sbfkcel/fast-astar#readme"
28
- }
23
+ "scripts": {
24
+ "test": "node tests/test.js",
25
+ "test:full": "node --max-old-space-size=8192 tests/test.js",
26
+ "test:wasm": "node tests/test_wasm.js",
27
+ "build:dev": "./scripts/build-dev.sh",
28
+ "build:rel": "./scripts/build-rel.sh"
29
+ }
30
+ }