azalea/pathfinder/
costs.rs1use std::sync::LazyLock;
2
3use num_traits::Float;
4
5pub const WALK_ONE_BLOCK_COST: f32 = 20. / 4.317; pub const SPRINT_ONE_BLOCK_COST: f32 = 20. / 5.612; pub const WALK_OFF_BLOCK_COST: f32 = WALK_ONE_BLOCK_COST * 0.8; pub const SPRINT_MULTIPLIER: f32 = SPRINT_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST; pub const JUMP_PENALTY: f32 = 2.;
11pub const ENTER_WATER_PENALTY: f32 = 3.;
12pub const CENTER_AFTER_FALL_COST: f32 = WALK_ONE_BLOCK_COST - WALK_OFF_BLOCK_COST; pub const WALK_ONE_IN_WATER_COST: f32 = 20. / 1.960; pub const COST_HEURISTIC: f32 = 3.563;
20
21pub const BLOCK_BREAK_ADDITIONAL_PENALTY: f32 = 2.;
24
25pub static FALL_1_25_BLOCKS_COST: LazyLock<f32> = LazyLock::new(|| distance_to_ticks(1.25));
26pub static FALL_0_25_BLOCKS_COST: LazyLock<f32> = LazyLock::new(|| distance_to_ticks(0.25));
27pub static JUMP_ONE_BLOCK_COST: LazyLock<f32> =
28 LazyLock::new(|| *FALL_1_25_BLOCKS_COST - *FALL_0_25_BLOCKS_COST); pub static FALL_N_BLOCKS_COST: LazyLock<[f32; 4097]> = LazyLock::new(|| {
32 let mut fall_n_blocks_cost = [0.; 4097];
36 let mut last_distance_blocks = 0;
37 let mut current_distance = 0.;
38 let mut tick_count = 0;
39
40 'outer: loop {
41 let fall_distance_per_tick = velocity(tick_count);
42
43 let current_distance_blocks = (current_distance + fall_distance_per_tick) as usize;
44 if current_distance_blocks > last_distance_blocks {
45 for blocks in (last_distance_blocks + 1)..=current_distance_blocks {
46 if blocks == fall_n_blocks_cost.len() {
47 break 'outer;
48 }
49
50 fall_n_blocks_cost[blocks] =
51 tick_count as f32 + (blocks as f32 - current_distance) / fall_distance_per_tick;
52 }
53
54 last_distance_blocks = current_distance_blocks;
55 }
56
57 current_distance += fall_distance_per_tick;
58 tick_count += 1;
59 }
60
61 fall_n_blocks_cost
62});
63
64fn velocity(ticks: u32) -> f32 {
65 (0.98.powi(ticks as i32) - 1.) * -3.92
66}
67
68fn distance_to_ticks(distance: f32) -> f32 {
69 if distance == 0. {
70 return 0.;
71 }
72 let mut tick_count = 0;
73 let mut remaining_distance = distance;
74 loop {
75 let fall_distance_per_tick = velocity(tick_count);
76 if fall_distance_per_tick >= remaining_distance {
77 return (tick_count as f32) + (remaining_distance / fall_distance_per_tick);
80 }
81 remaining_distance -= fall_distance_per_tick;
82 tick_count += 1;
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use crate::pathfinder::costs::{FALL_N_BLOCKS_COST, distance_to_ticks};
89
90 #[test]
91 fn test_fall_n_blocks_cost() {
92 for i in 0..4 {
93 let a = FALL_N_BLOCKS_COST[i];
94 let b = distance_to_ticks(i as f32);
95 assert!((a - b).abs() < 0.1, "{a} != {b}");
96 }
97 }
98}