or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

algorithms.mdcore-structures.mdindex.mdutilities.md

algorithms.mddocs/

0

# Pathfinding Algorithms

1

2

Seven different pathfinding algorithms providing optimal paths for various scenarios and performance requirements. All algorithms inherit from the base Finder class and implement the same interface for easy switching between strategies.

3

4

## Capabilities

5

6

### A* Algorithm

7

8

A* pathfinding using heuristics to guide search toward the goal. Provides optimal paths when using admissible heuristics and supports weighted nodes and various diagonal movement policies.

9

10

```python { .api }

11

class AStarFinder:

12

def __init__(self, heuristic=None, weight=1, diagonal_movement=DiagonalMovement.never,

13

time_limit=TIME_LIMIT, max_runs=MAX_RUNS):

14

"""

15

Create A* pathfinder.

16

17

Parameters:

18

- heuristic (function): Heuristic function (defaults to manhattan/octile based on diagonal_movement)

19

- weight (int): Edge weight multiplier for weighted A*

20

- diagonal_movement (int): Diagonal movement policy

21

- time_limit (float): Maximum execution time in seconds

22

- max_runs (int): Maximum algorithm iterations

23

"""

24

25

def find_path(self, start, end, grid):

26

"""

27

Find optimal path using A* algorithm.

28

29

Parameters:

30

- start (Node): Starting node

31

- end (Node): Target node

32

- grid (Grid|Graph): Search space

33

34

Returns:

35

Tuple[List[Node], int]: (path_nodes, runs_count)

36

"""

37

```

38

39

#### Usage Example

40

41

```python

42

from pathfinding.core.grid import Grid

43

from pathfinding.core.diagonal_movement import DiagonalMovement

44

from pathfinding.finder.a_star import AStarFinder

45

from pathfinding.core.heuristic import euclidean

46

47

# Create grid and finder

48

grid = Grid(matrix=[[1,1,1],[1,0,1],[1,1,1]])

49

finder = AStarFinder(

50

heuristic=euclidean,

51

diagonal_movement=DiagonalMovement.always,

52

weight=2 # Weighted A* for faster, suboptimal paths

53

)

54

55

# Find path

56

path, runs = finder.find_path(grid.node(0,0), grid.node(2,2), grid)

57

print(f"Path length: {len(path)}, Runs: {runs}")

58

```

59

60

### Dijkstra Algorithm

61

62

Dijkstra's algorithm for finding shortest paths by exploring nodes in order of distance from start. Guarantees optimal paths and works well with weighted edges but doesn't use heuristics.

63

64

```python { .api }

65

class DijkstraFinder:

66

def __init__(self, weight=1, diagonal_movement=DiagonalMovement.never,

67

time_limit=TIME_LIMIT, max_runs=MAX_RUNS):

68

"""

69

Create Dijkstra pathfinder.

70

71

Parameters:

72

- weight (int): Edge weight multiplier

73

- diagonal_movement (int): Diagonal movement policy

74

- time_limit (float): Maximum execution time in seconds

75

- max_runs (int): Maximum algorithm iterations

76

"""

77

78

def find_path(self, start, end, grid):

79

"""

80

Find optimal path using Dijkstra's algorithm.

81

82

Parameters:

83

- start (Node): Starting node

84

- end (Node): Target node

85

- grid (Grid|Graph): Search space

86

87

Returns:

88

Tuple[List[Node], int]: (path_nodes, runs_count)

89

"""

90

```

91

92

#### Usage Example

93

94

```python

95

from pathfinding.core.graph import Graph

96

from pathfinding.finder.dijkstra import DijkstraFinder

97

98

# Create weighted graph

99

edges = [

100

[1, 2, 10], [1, 3, 15], [2, 3, 12],

101

[2, 4, 15], [3, 4, 10]

102

]

103

graph = Graph(edges=edges, bi_directional=True)

104

105

# Find shortest path

106

finder = DijkstraFinder()

107

path, runs = finder.find_path(graph.node(1), graph.node(4), graph)

108

109

# Extract path

110

node_path = [node.node_id for node in path]

111

print(f"Shortest path: {node_path}")

112

```

113

114

### Best-First Search

115

116

Best-first search using only heuristic values to guide search. Fast but doesn't guarantee optimal paths. Good for scenarios where speed is more important than optimality.

117

118

```python { .api }

119

class BestFirst:

120

def __init__(self, heuristic=None, weight=1, diagonal_movement=DiagonalMovement.never,

121

time_limit=TIME_LIMIT, max_runs=MAX_RUNS):

122

"""

123

Create Best-First pathfinder.

124

125

Parameters:

126

- heuristic (function): Heuristic function (defaults to manhattan/octile)

127

- weight (int): Edge weight multiplier

128

- diagonal_movement (int): Diagonal movement policy

129

- time_limit (float): Maximum execution time in seconds

130

- max_runs (int): Maximum algorithm iterations

131

"""

132

133

def find_path(self, start, end, grid):

134

"""

135

Find path using Best-First search.

136

137

Parameters:

138

- start (Node): Starting node

139

- end (Node): Target node

140

- grid (Grid|Graph): Search space

141

142

Returns:

143

Tuple[List[Node], int]: (path_nodes, runs_count)

144

"""

145

```

146

147

### Bi-directional A*

148

149

Bi-directional A* searching simultaneously from start and end until paths meet. More efficient for long paths but doesn't support weighted nodes.

150

151

```python { .api }

152

class BiAStarFinder:

153

def __init__(self, heuristic=None, weight=1, diagonal_movement=DiagonalMovement.never,

154

time_limit=TIME_LIMIT, max_runs=MAX_RUNS):

155

"""

156

Create Bi-directional A* pathfinder.

157

158

Parameters:

159

- heuristic (function): Heuristic function (defaults to manhattan/octile)

160

- weight (int): Edge weight multiplier

161

- diagonal_movement (int): Diagonal movement policy

162

- time_limit (float): Maximum execution time in seconds

163

- max_runs (int): Maximum algorithm iterations

164

"""

165

166

def find_path(self, start, end, grid):

167

"""

168

Find path using bi-directional A*.

169

170

Parameters:

171

- start (Node): Starting node

172

- end (Node): Target node

173

- grid (Grid|Graph): Search space

174

175

Returns:

176

Tuple[List[Node], int]: (path_nodes, runs_count)

177

"""

178

```

179

180

### Breadth-First Search

181

182

Breadth-first search exploring nodes level by level from the start. Guarantees shortest path in unweighted graphs but can be slow for large spaces.

183

184

```python { .api }

185

class BreadthFirstFinder:

186

def __init__(self, heuristic=None, weight=1, diagonal_movement=DiagonalMovement.never,

187

time_limit=TIME_LIMIT, max_runs=MAX_RUNS):

188

"""

189

Create Breadth-First pathfinder.

190

191

Parameters:

192

- heuristic (function): Ignored (BFS doesn't use heuristics)

193

- weight (int): Edge weight multiplier

194

- diagonal_movement (int): Diagonal movement policy

195

- time_limit (float): Maximum execution time in seconds

196

- max_runs (int): Maximum algorithm iterations

197

"""

198

199

def find_path(self, start, end, grid):

200

"""

201

Find path using Breadth-First search.

202

203

Parameters:

204

- start (Node): Starting node

205

- end (Node): Target node

206

- grid (Grid|Graph): Search space

207

208

Returns:

209

Tuple[List[Node], int]: (path_nodes, runs_count)

210

"""

211

```

212

213

### IDA* (Iterative Deepening A*)

214

215

Memory-efficient iterative deepening A* using successive depth limits. Provides optimal paths with minimal memory usage but can be slower than regular A*.

216

217

```python { .api }

218

class IDAStarFinder:

219

def __init__(self, heuristic=None, weight=1, diagonal_movement=DiagonalMovement.never,

220

time_limit=TIME_LIMIT, max_runs=MAX_RUNS, track_recursion=True):

221

"""

222

Create IDA* pathfinder.

223

224

Parameters:

225

- heuristic (function): Heuristic function (defaults to manhattan/octile)

226

- weight (int): Edge weight multiplier

227

- diagonal_movement (int): Diagonal movement policy

228

- time_limit (float): Maximum execution time in seconds

229

- max_runs (int): Maximum algorithm iterations

230

- track_recursion (bool): Track recursion for visualization

231

"""

232

233

@property

234

def nodes_visited(self) -> int:

235

"""Statistics counter for nodes visited during search."""

236

237

def find_path(self, start, end, grid):

238

"""

239

Find path using IDA* algorithm.

240

241

Parameters:

242

- start (Node): Starting node

243

- end (Node): Target node

244

- grid (Grid|Graph): Search space

245

246

Returns:

247

Tuple[List[Node], int]: (path_nodes, runs_count)

248

"""

249

```

250

251

#### Usage Example

252

253

```python

254

from pathfinding.finder.ida_star import IDAStarFinder

255

256

# Memory-efficient pathfinding for large grids

257

finder = IDAStarFinder(track_recursion=False) # Disable tracking for performance

258

path, runs = finder.find_path(start, end, large_grid)

259

print(f"Nodes visited: {finder.nodes_visited}")

260

```

261

262

### Minimum Spanning Tree

263

264

Pathfinding via minimum spanning tree generation. Useful for finding paths in graphs where you need to connect all nodes with minimum total cost.

265

266

```python { .api }

267

class MinimumSpanningTree:

268

def __init__(self, *args, **kwargs):

269

"""Create Minimum Spanning Tree pathfinder."""

270

271

def find_path(self, start, end, grid):

272

"""

273

Find path via minimum spanning tree.

274

275

Parameters:

276

- start (Node): Starting node

277

- end (Node): Target node

278

- grid (Grid|Graph): Search space

279

280

Returns:

281

Tuple[List[Node], int]: (path_nodes, runs_count)

282

"""

283

284

def tree(self, grid, start):

285

"""

286

Generate complete minimum spanning tree.

287

288

Parameters:

289

- grid (Grid|Graph): Search space

290

- start (Node): Root node for tree

291

292

Returns:

293

List[Node]: All nodes in spanning tree order

294

"""

295

296

def itertree(self, grid, start):

297

"""

298

Generator for spanning tree nodes.

299

300

Parameters:

301

- grid (Grid|Graph): Search space

302

- start (Node): Root node for tree

303

304

Yields:

305

Node: Next node in spanning tree

306

"""

307

```

308

309

## Base Finder Class

310

311

All pathfinding algorithms inherit from the base Finder class, providing common functionality and interface consistency.

312

313

```python { .api }

314

class Finder:

315

def __init__(self, heuristic=None, weight=1, diagonal_movement=DiagonalMovement.never,

316

weighted=True, time_limit=TIME_LIMIT, max_runs=MAX_RUNS):

317

"""

318

Base pathfinder class.

319

320

Parameters:

321

- heuristic (function): Heuristic function

322

- weight (int): Edge weight multiplier

323

- diagonal_movement (int): Diagonal movement policy

324

- weighted (bool): Whether algorithm supports weighted nodes

325

- time_limit (float): Maximum execution time in seconds

326

- max_runs (int): Maximum algorithm iterations

327

"""

328

329

def apply_heuristic(self, node_a, node_b, heuristic=None, graph=None):

330

"""

331

Calculate heuristic distance between nodes.

332

333

Parameters:

334

- node_a (Node): Start node

335

- node_b (Node): End node

336

- heuristic (function): Heuristic function to use

337

- graph (Grid|Graph): Search space context

338

339

Returns:

340

float: Heuristic distance

341

"""

342

343

def find_neighbors(self, grid, node, diagonal_movement=None):

344

"""

345

Find neighboring nodes.

346

347

Parameters:

348

- grid (Grid|Graph): Search space

349

- node (Node): Center node

350

- diagonal_movement (int): Diagonal movement policy

351

352

Returns:

353

List[Node]: Neighboring nodes

354

"""

355

356

def keep_running(self):

357

"""

358

Check if algorithm should continue running.

359

360

Returns:

361

bool: True if within time and iteration limits

362

"""

363

```

364

365

## Exceptions

366

367

```python { .api }

368

class ExecutionTimeException(Exception):

369

"""Raised when pathfinding exceeds time limit."""

370

371

class ExecutionRunsException(Exception):

372

"""Raised when pathfinding exceeds maximum runs."""

373

```

374

375

## Constants

376

377

```python { .api }

378

TIME_LIMIT = 10.0 # Default maximum execution time in seconds

379

MAX_RUNS = 100000 # Default maximum algorithm iterations

380

```

381

382

## Algorithm Selection Guide

383

384

### Choose A* when:

385

- You need optimal paths

386

- You have a good heuristic function

387

- Memory usage is acceptable

388

- Grid/graph has moderate size

389

390

### Choose Dijkstra when:

391

- You need guaranteed optimal paths

392

- No good heuristic is available

393

- Graph has weighted edges

394

- You need to find shortest paths to multiple targets

395

396

### Choose Best-First when:

397

- Speed is more important than optimality

398

- You have a good heuristic

399

- Approximate solutions are acceptable

400

401

### Choose Bi-directional A* when:

402

- Paths are typically long

403

- You need optimal paths

404

- Graph/grid is large

405

- Start and end are far apart

406

407

### Choose Breadth-First when:

408

- Graph is unweighted

409

- You need shortest path (by number of steps)

410

- Graph is relatively small

411

412

### Choose IDA* when:

413

- Memory is very limited

414

- You need optimal paths

415

- Grid/graph is large

416

- You can tolerate slower execution

417

418

### Choose MSP when:

419

- You need to connect all nodes

420

- Total connection cost matters more than individual paths

421

- Working with network design problems

422

423

## Usage Patterns

424

425

### Algorithm Comparison

426

427

```python

428

from pathfinding.core.grid import Grid

429

from pathfinding.finder.a_star import AStarFinder

430

from pathfinding.finder.dijkstra import DijkstraFinder

431

from pathfinding.finder.breadth_first import BreadthFirstFinder

432

433

grid = Grid(matrix=large_maze)

434

start = grid.node(0, 0)

435

end = grid.node(99, 99)

436

437

algorithms = [

438

("A*", AStarFinder()),

439

("Dijkstra", DijkstraFinder()),

440

("BFS", BreadthFirstFinder())

441

]

442

443

for name, finder in algorithms:

444

grid.cleanup() # Important: clean between runs

445

path, runs = finder.find_path(start, end, grid)

446

print(f"{name}: path length {len(path)}, runs {runs}")

447

```

448

449

### Performance Monitoring

450

451

```python

452

import time

453

from pathfinding.finder.a_star import AStarFinder

454

455

# Set time and iteration limits

456

finder = AStarFinder(time_limit=5.0, max_runs=10000)

457

458

start_time = time.time()

459

try:

460

path, runs = finder.find_path(start, end, grid)

461

elapsed = time.time() - start_time

462

print(f"Found path in {elapsed:.2f}s with {runs} runs")

463

except ExecutionTimeException:

464

print("Pathfinding timed out")

465

except ExecutionRunsException:

466

print("Pathfinding exceeded maximum runs")

467

```