screeps_pathfinding/utils/movement_costs.rs
1use std::cell::RefCell;
2use std::rc::Rc;
3
4use screeps::constants::Terrain;
5use screeps::local::{LocalCostMatrix, LocalRoomTerrain};
6use screeps::{Position, RoomName, RoomXY};
7
8use super::cache::{LCMCache, TerrainCache};
9
10pub fn get_movement_cost_lcm_from_terrain(
11 room_terrain: &LocalRoomTerrain,
12 plain_cost: u8,
13 swamp_cost: u8,
14) -> LocalCostMatrix {
15 let mut cm = LocalCostMatrix::new();
16
17 for (xy, val) in cm.iter_mut() {
18 *val = match room_terrain.get_xy(xy) {
19 Terrain::Wall => u8::MAX,
20 Terrain::Plain => plain_cost,
21 Terrain::Swamp => swamp_cost,
22 }
23 }
24
25 cm
26}
27
28/// Builds a cost function closure that pulls costs from a `LocalCostMatrix`.
29///
30/// # Example
31/// ```rust
32/// use screeps::{LocalRoomTerrain, Position, RoomCoordinate, RoomXY};
33///
34/// let room_terrain = LocalRoomTerrain::new_from_bits(Box::new([0; 2500])); // Terrain that's all plains
35/// let plain_cost = 1;
36/// let swamp_cost = 5;
37/// let costs = screeps_pathfinding::utils::movement_costs::get_movement_cost_lcm_from_terrain(&room_terrain, plain_cost, swamp_cost);
38///
39/// let roomxy_costs_fn = screeps_pathfinding::utils::movement_costs::movement_costs_from_lcm(&costs);
40///
41/// let xy = RoomXY::checked_new(24, 18).unwrap();
42/// assert_eq!(roomxy_costs_fn(xy), plain_cost as u32);
43///
44/// let position_costs_fn = screeps_pathfinding::utils::movement_costs::movement_costs_from_lcm(&costs);
45///
46/// let pos = Position::new(
47/// RoomCoordinate::try_from(24).unwrap(),
48/// RoomCoordinate::try_from(18).unwrap(),
49/// "E5N6".parse().unwrap(),
50/// );
51/// assert_eq!(position_costs_fn(pos), plain_cost as u32);
52/// ```
53pub fn movement_costs_from_lcm<T>(lcm: &LocalCostMatrix) -> impl Fn(T) -> u32 + '_
54where
55 T: Into<RoomXY>,
56{
57 |xy| {
58 let value = lcm.get(xy.into());
59 match value {
60 u8::MAX => u32::MAX,
61 _ => value as u32,
62 }
63 }
64}
65
66/// Builds a cost function closure that pulls costs from a `LocalCostMatrix`.
67///
68/// # Example
69/// ```rust
70/// use screeps::{LocalRoomTerrain, Position, RoomCoordinate, RoomXY};
71///
72/// let room_terrain = LocalRoomTerrain::new_from_bits(Box::new([0; 2500])); // Terrain that's all plains
73/// let plain_cost = 1;
74/// let swamp_cost = 5;
75/// let costs = screeps_pathfinding::utils::movement_costs::get_movement_cost_lcm_from_terrain(&room_terrain, plain_cost, swamp_cost);
76///
77/// let roomxy_costs_fn = screeps_pathfinding::utils::movement_costs::astar_movement_costs_from_lcm(&costs);
78///
79/// let xy = RoomXY::checked_new(24, 18).unwrap();
80/// assert_eq!(roomxy_costs_fn(xy), Some(plain_cost as u32));
81///
82/// let position_costs_fn = screeps_pathfinding::utils::movement_costs::astar_movement_costs_from_lcm(&costs);
83///
84/// let pos = Position::new(
85/// RoomCoordinate::try_from(24).unwrap(),
86/// RoomCoordinate::try_from(18).unwrap(),
87/// "E5N6".parse().unwrap(),
88/// );
89/// assert_eq!(position_costs_fn(pos), Some(plain_cost as u32));
90/// ```
91pub fn astar_movement_costs_from_lcm<T>(lcm: &LocalCostMatrix) -> impl Fn(T) -> Option<u32> + '_
92where
93 T: Into<RoomXY>,
94{
95 |xy| {
96 let value = lcm.get(xy.into());
97 match value {
98 u8::MAX => None,
99 _ => Some(value as u32),
100 }
101 }
102}
103/// Utility function to create an LCM generation closure from a terrain cache and terrain costs.
104pub fn get_lcm_generation_closure_from_terrain_cache(
105 terrain_cache_ref: Rc<RefCell<TerrainCache>>,
106 plain_cost: u8,
107 swamp_cost: u8,
108 default_cost: u8,
109) -> impl Clone + Fn(&RoomName) -> LocalCostMatrix {
110 move |room_name: &RoomName| {
111 let mut cm = LocalCostMatrix::new_with_value(default_cost);
112
113 if let Ok(mut terrain_cache) = terrain_cache_ref.try_borrow_mut() {
114 if let Some(room_terrain) = terrain_cache.get_terrain(room_name) {
115 for (xy, val) in cm.iter_mut() {
116 *val = match room_terrain.get_xy(xy) {
117 Terrain::Wall => u8::MAX,
118 Terrain::Plain => plain_cost,
119 Terrain::Swamp => swamp_cost,
120 }
121 }
122 }
123 }
124
125 cm
126 }
127}
128
129/// Utility function to create a movement costs closure from an LCM cache.
130pub fn movement_costs_from_lcm_cache<
131 'a,
132 'b,
133 F: Clone + Fn(&RoomName) -> LocalCostMatrix + 'a + 'b,
134>(
135 lcm_cache_ref: &'b RefCell<LCMCache>,
136 generator_fn: F,
137) -> impl Fn(Position) -> Option<u32> + 'b {
138 move |pos: Position| {
139 let mut lcm_cache = lcm_cache_ref.borrow_mut();
140 let lcm = lcm_cache.get_lcm(&pos.room_name(), generator_fn.clone());
141 let value = lcm.get(pos.into());
142 match value {
143 u8::MAX => None,
144 _ => Some(value as u32),
145 }
146 }
147}