Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bracket-pathfinding/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.8.7"
authors = ["Herbert Wolverson <herberticus@gmail.com>"]
edition = "2024"
publish = true
description = "Pathfinding and field-of view utilities. A Star, Dijkstra. Part of the bracket-lib family."
description = "Pathfinding and field-of view utilities. A Star, BFS, Dijkstra. Part of the bracket-lib family."
homepage = "https://github.com/thebracket/bracket-lib"
repository = "https://github.com/thebracket/bracket-lib"
readme = "README.md"
Expand Down
30 changes: 25 additions & 5 deletions bracket-pathfinding/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# bracket-pathfinding

This crate is part of the overall `bracket-lib` system, and (in conjunction with `bracket-algorithm-traits`) provides pathfinding functionality. A-Star (A*) and Dijkstra are supported. It also provides field of view (FOV) functionality.
This crate is part of the overall `bracket-lib` system, and (in conjunction with `bracket-algorithm-traits`) provides pathfinding functionality. A-Star (A*), breadth-first search (BFS), and Dijkstra are supported. It also provides field of view (FOV) functionality.

## Trait Implementation

Expand All @@ -26,7 +26,7 @@ impl BaseMap for Map {
}
```

Dijkstra and A-Star need to know what exits are valid from a tile, and the "cost" of moving to that tile (most of the time you can use `1.0`). For example:
BFS, Dijkstra and A-Star need to know what exits are valid from a tile. Dijkstra and A-Star use the "cost" of moving to that tile (most of the time you can use `1.0`), while BFS treats each exit as one step. For example:

```rust
impl BaseMap for Map {
Expand Down Expand Up @@ -88,6 +88,23 @@ let path = a_star_search(

The example `astar` demonstrates this.

## BFS Mapping

Bracket-lib includes BFS maps for unweighted flow mapping. BFS can include as many search targets as you want, and treats each valid exit as one step regardless of the exit cost.

To generate a BFS map, you need a vector of target tile indices. You can then make the map:

```rust
let mut search_targets : Vec<usize> = Vec::new();
search_targets.push(map.point2d_to_index(START_POINT));
search_targets.push(map.point2d_to_index(END_POINT));
let flow_map = BfsMap::new(MAP_WIDTH, MAP_HEIGHT, &search_targets, &map, 1024.0);
```

Once you have the map, you can access individual distances at `flow_map.map` - or you can use helper functions such as `find_highest_exit` and `find_lowest_exit` to help with path-finding.

The example `bfs` demonstrates this.

## Dijkstra Mapping

Bracket-lib also includes Dijkstra maps, that can include as many search targets as you want. See [The Incredible Power of Dijkstra Maps](http://www.roguebasin.com/index.php?title=The_Incredible_Power_of_Dijkstra_Maps) for some ideas as to what you can do with this.
Expand All @@ -101,7 +118,7 @@ search_targets.push(map.point2d_to_index(END_POINT));
let flow_map = DijkstraMap::new(MAP_WIDTH, MAP_HEIGHT, &search_targets, &map, 1024.0);
```

Once you have the map, you can access individual distances at `flow_map.map` - or you can use various helper functions such as `find_highest_exist` and `find_lowest_exit` to help with path-finding.
Once you have the map, you can access individual distances at `flow_map.map` - or you can use helper functions such as `find_highest_exit` and `find_lowest_exit` to help with path-finding.

The example `dijkstra` demonstrates this.

Expand All @@ -117,14 +134,17 @@ You can see this in action with the example `fov`.

## Feature Flags

If you enable the `threaded` feature, some Dijkstra functions will use a multi-threaded algorithm.
If you enable the `threaded` feature, some BFS and Dijkstra functions will use a multi-threaded algorithm.

## Examples

There are three examples (ignore `common.rs` - it's shared code):
There are six examples (ignore `common.rs` - it's shared code):

* `astar` (`cargo run --example astar`), demonstrating A-Star pathing across a random map.
* `astar_manhattan` (`cargo run --example astar_manhattan`), demonstrating A-Star pathing with Manhattan distance.
* `bfs` (`cargo run --example bfs`), demonstrating BFS mapping to two targets.
* `dijkstra` (`cargo run --example dijkstra`), demonstrating Dijkstra mapping to two targets.
* `dijkstra_weighted` (`cargo run --example dijkstra_weighted`), demonstrating weighted Dijkstra mapping.
* `fov` (`cargo run --example fov`), demonstrating field-of-view generation.

These use `crossterm` for rendering to your terminal.
47 changes: 47 additions & 0 deletions bracket-pathfinding/examples/bfs/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#[path = "../dijkstra/common.rs"]
mod common;

use bracket_color::prelude::*;
use bracket_pathfinding::prelude::*;
use common::*;

fn main() {
let map = Map::new();

// Perform the search
let search_targets: Vec<usize> = vec![
map.point2d_to_index(START_POINT),
map.point2d_to_index(END_POINT),
];
let flow_map = BfsMap::new(MAP_WIDTH, MAP_HEIGHT, &search_targets, &map, 1024.0);

// Draw the result
for y in 0..MAP_HEIGHT {
let base_idx = map.point2d_to_index(Point::new(0, y));
for x in 0..MAP_WIDTH {
let idx = base_idx + x;

let tile = map.tiles[idx];
let color = match tile {
'#' => RGB::named(YELLOW),
_ => {
if flow_map.map[idx] < f32::MAX {
RGB::from_u8(
0,
255 - {
let n = flow_map.map[idx] * 6.0;
if n > 255.0 { 255.0 } else { n }
} as u8,
0,
)
} else {
RGB::named(CHOCOLATE)
}
}
};
print_color(color, &tile.to_string());
}
print_color(RGB::named(WHITE), "\n");
}
flush_console();
}
Loading
Loading