Skip to content

Commit fe8325d

Browse files
committed
wip
1 parent 2cb2fbd commit fe8325d

7 files changed

Lines changed: 177 additions & 42 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
.idea
22
node_modules
33
coverage
4+
target

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "oh_pathfinding"
3+
version = "0.0.0"
4+
edition = "2024"
5+
6+
[lib]
7+
path = "src/lib.rs"
8+
crate-type = ["cdylib"]
9+
10+
[dependencies]

deno.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@
44
"exports": "./mod.ts",
55
"imports": {
66
"std/": "https://deno.land/std@0.224.0/"
7+
},
8+
"tasks": {
9+
"build:lib": "cargo build --release"
710
}
811
}

preview/bundle.js

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// src/utils/grid.utils.ts
22
var makeSquare = (layout) => {
33
const maxLength = Math.max(layout.length, ...layout.map((row) => row.length));
4-
const squareLayout = Array.from({ length: maxLength }, () =>
5-
Array(maxLength).fill(null),
4+
const squareLayout = Array.from(
5+
{ length: maxLength },
6+
() => Array(maxLength).fill(null)
67
);
78
for (let i = 0; i < layout.length; i++) {
89
for (let j = 0; j < layout[i].length; j++) {
@@ -13,8 +14,9 @@ var makeSquare = (layout) => {
1314
};
1415
var transpose = (matrix) => {
1516
const maxCols = Math.max(...matrix.map((row) => row.length));
16-
const transposed = Array.from({ length: maxCols }, () =>
17-
Array(matrix.length).fill(null),
17+
const transposed = Array.from(
18+
{ length: maxCols },
19+
() => Array(matrix.length).fill(null)
1820
);
1921
for (let i = 0; i < matrix.length; i++) {
2022
for (let j = 0; j < matrix[i].length; j++) {
@@ -92,7 +94,7 @@ var findPath = (startPoint, endPoint, grid, config) => {
9294
const orthogonalCostMultiplier = config.orthogonalCostMultiplier ?? 1;
9395
const maxJumpCost = config.maxJumpCost ?? 5;
9496
const maxIterations = config.maxIterations ?? 99999;
95-
const jumpDiagonals = config.jumpDiagonals ?? false;
97+
const jumpBlockedDiagonals = config.jumpBlockedDiagonals ?? false;
9698
const index = (point) => {
9799
return point.y * grid.height + point.x;
98100
};
@@ -110,7 +112,7 @@ var findPath = (startPoint, endPoint, grid, config) => {
110112
while (true) {
111113
const target = {
112114
x: src.x + dirX * jumpDistance,
113-
y: src.y + dirY * jumpDistance,
115+
y: src.y + dirY * jumpDistance
114116
};
115117
if (!grid.isWalkable(target)) {
116118
break;
@@ -125,7 +127,7 @@ var findPath = (startPoint, endPoint, grid, config) => {
125127
if (totalCost < visited[targetIndex]) {
126128
visited[targetIndex] = totalCost;
127129
queue.push(
128-
new PathNode(target, prevNode, totalCost, heuristic(target)),
130+
new PathNode(target, prevNode, totalCost, heuristic(target))
129131
);
130132
}
131133
prevPoint = target;
@@ -137,24 +139,13 @@ var findPath = (startPoint, endPoint, grid, config) => {
137139
};
138140
const addDiagonal = (prevNode, src, srcCost, dirX, dirY) => {
139141
const target = { x: src.x + dirX, y: src.y + dirY };
140-
const moveCost =
141-
srcCost +
142-
(getMoveCostAt(src, target) ?? NOT_REACHED_COST) * diagonalCostMultiplier;
142+
const moveCost = srcCost + (getMoveCostAt(src, target) ?? NOT_REACHED_COST) * diagonalCostMultiplier;
143143
const targetHeight = grid.getHeightAt(target);
144144
const aux1 = { x: src.x, y: src.y + dirY };
145145
const aux2 = { x: src.x + dirX, y: src.y };
146146
const targetIndex = index(target);
147-
const canJumpDiagonals =
148-
jumpDiagonals ||
149-
(grid.isWalkable(aux1) &&
150-
grid.isWalkable(aux2) &&
151-
targetHeight == grid.getHeightAt(aux1) &&
152-
targetHeight == grid.getHeightAt(aux2));
153-
if (
154-
grid.isWalkable(target) &&
155-
canJumpDiagonals &&
156-
moveCost < visited[targetIndex]
157-
) {
147+
const canJumpDiagonals = jumpBlockedDiagonals || grid.isWalkable(aux1) && grid.isWalkable(aux2) && targetHeight == grid.getHeightAt(aux1) && targetHeight == grid.getHeightAt(aux2);
148+
if (grid.isWalkable(target) && canJumpDiagonals && moveCost < visited[targetIndex]) {
158149
visited[targetIndex] = moveCost;
159150
queue.push(new PathNode(target, prevNode, moveCost, heuristic(target)));
160151
}
@@ -253,24 +244,15 @@ var Grid = class _Grid {
253244
return new _Grid(
254245
this.width,
255246
this.height,
256-
new Float32Array(this.heightMatrix),
247+
new Float32Array(this.heightMatrix)
257248
);
258249
}
259250
inBounds(point) {
260-
return (
261-
point.x >= 0 &&
262-
point.x < this.width &&
263-
point.y >= 0 &&
264-
point.y < this.height
265-
);
251+
return point.x >= 0 && point.x < this.width && point.y >= 0 && point.y < this.height;
266252
}
267253
isWalkable(point) {
268254
const heightAt = this.getHeightAt(point);
269-
return (
270-
this.inBounds(point) &&
271-
heightAt !== null &&
272-
heightAt !== NON_WALKABLE_HEIGHT
273-
);
255+
return this.inBounds(point) && heightAt !== null && heightAt !== NON_WALKABLE_HEIGHT;
274256
}
275257
walkMatrix(callback) {
276258
for (let y = 0; y < this.height; y++) {
@@ -291,15 +273,15 @@ var Grid = class _Grid {
291273
}
292274
return matrix;
293275
}
294-
findPath(
295-
startPoint,
296-
endPoint,
297-
config = {
298-
maxJumpCost: 5,
299-
travelCosts: void 0,
300-
},
301-
) {
276+
findPath(startPoint, endPoint, config = {
277+
maxJumpCost: 5,
278+
travelCosts: void 0
279+
}) {
302280
return findPath(startPoint, endPoint, this, config);
303281
}
304282
};
305-
export { Grid, makeSquare, transpose };
283+
export {
284+
Grid,
285+
makeSquare,
286+
transpose
287+
};

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mod open_list;

src/open_list.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
use std::cmp::Ordering;
2+
use std::fmt::Debug;
3+
4+
#[derive(Debug)]
5+
pub struct ListNode<Value> {
6+
pub value: Value,
7+
pub next: Option<Box<ListNode<Value>>>
8+
}
9+
10+
#[allow(dead_code)]
11+
impl<Value> ListNode<Value> {
12+
fn new(value: Value, next: Option<Box<ListNode<Value>>>) -> Self {
13+
ListNode { value, next }
14+
}
15+
}
16+
17+
pub trait Compare<Value>: Debug {
18+
fn compare(&self, a: &Value, b: &Value) -> Ordering;
19+
}
20+
21+
#[derive(Debug)]
22+
pub struct OpenList<Value> {
23+
start: Option<Box<ListNode<Value>>>,
24+
size: usize,
25+
comparator: Box<dyn Compare<Value>>
26+
}
27+
#[allow(dead_code)]
28+
impl<Value> OpenList<Value> {
29+
pub fn new(comparator: Box<dyn Compare<Value>>) -> Self {
30+
OpenList {
31+
start: None,
32+
size: 0,
33+
comparator,
34+
}
35+
}
36+
pub fn push(&mut self, value: Value) {
37+
if self.start.is_none() {
38+
self.start = Some(Box::new(ListNode { value, next: None }));
39+
self.size += 1;
40+
return;
41+
}
42+
43+
let start = self.start.take().unwrap();
44+
if self.comparator.compare(&value, &start.value) == Ordering::Less {
45+
self.start = Some(Box::new(ListNode {
46+
value,
47+
next: Some(start),
48+
}));
49+
self.size += 1;
50+
return;
51+
}
52+
53+
let mut current = Some(start);
54+
let mut prev = &mut self.start;
55+
56+
while let Some(mut node) = current.take() {
57+
if let Some(next_node) = &node.next {
58+
if self.comparator.compare(&value, &next_node.value) != Ordering::Greater {
59+
node.next = Some(Box::new(ListNode {
60+
value,
61+
next: node.next.take(),
62+
}));
63+
*prev = Some(node);
64+
self.size += 1;
65+
return;
66+
}
67+
}
68+
69+
current = node.next.take();
70+
*prev = Some(node);
71+
prev = &mut prev.as_mut().unwrap().next;
72+
}
73+
74+
*prev = Some(Box::new(ListNode { value, next: None }));
75+
self.size += 1;
76+
}
77+
78+
pub fn pop (&mut self) -> Result<Value, String> {
79+
match self.start.take() {
80+
None => Err("popping from an empty list".to_string()),
81+
Some(mut popped) => {
82+
self.start = popped.next.take();
83+
self.size -= 1;
84+
Ok(popped.value)
85+
}
86+
}
87+
}
88+
89+
pub fn length(&self) -> usize {
90+
self.size
91+
}
92+
93+
pub fn is_empty(&self) -> bool {
94+
self.start.is_none()
95+
}
96+
}
97+
98+
#[cfg(test)]
99+
mod tests {
100+
use super::*;
101+
102+
#[derive(Debug)]
103+
struct IntComparator;
104+
105+
impl Compare<i32> for IntComparator {
106+
fn compare(&self, a: &i32, b: &i32) -> Ordering {
107+
a.cmp(b)
108+
}
109+
}
110+
111+
#[test]
112+
fn test_open_list() {
113+
let comparator = Box::new(IntComparator);
114+
let mut list = OpenList::new(comparator);
115+
116+
assert!(list.is_empty());
117+
assert_eq!(list.length(), 0);
118+
119+
list.push(3);
120+
list.push(1);
121+
list.push(4);
122+
123+
assert!(!list.is_empty());
124+
assert_eq!(list.length(), 3);
125+
126+
assert_eq!(list.pop(), Ok(1));
127+
assert_eq!(list.pop(), Ok(3));
128+
assert_eq!(list.pop(), Ok(4));
129+
assert!(list.pop().is_err());
130+
}
131+
}

0 commit comments

Comments
 (0)