Skip to content

Commit 16b1d9c

Browse files
committed
.
1 parent 21e28f1 commit 16b1d9c

File tree

10 files changed

+174
-79
lines changed

10 files changed

+174
-79
lines changed

packages/demo/demo.astar.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

packages/demo/demo.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
"getPathTo",
88
"svg",
99
"rust",
10-
"astar"
10+
"rust_astar",
11+
"rust_astar_snake"
1112
]

packages/demo/demo.rust.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { grid } from "./sample";
77

88
const g = api.IGrid.create(grid.width, grid.height, grid.data);
99

10-
const freeCells = api.iget_free_cell(g);
10+
const freeCells = api.iget_free_cells(g);
1111

1212
{
1313
const { canvas, draw, highlightCell } = createCanvas(g);

packages/solver-r/src/astar.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::grid::{Point, DIRECTIONS};
1+
use crate::grid::{get_distance, Point, DIRECTIONS};
22
use std::cmp::Reverse;
33
use std::collections::{BinaryHeap, HashMap};
44

@@ -29,7 +29,7 @@ impl PartialOrd for Node {
2929
}
3030

3131
fn get_heuristic(a: &Point, b: &Point) -> u8 {
32-
(a.x - b.x).abs() as u8 + (a.y - b.y).abs() as u8
32+
get_distance(a, b)
3333
}
3434

3535
pub fn get_path<F>(mut walkable: F, start: &Point, end: &Point) -> Option<Vec<Point>>

packages/solver-r/src/grid.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ pub struct Point {
33
pub x: i8,
44
pub y: i8,
55
}
6+
pub fn get_distance(a: &Point, b: &Point) -> u8 {
7+
(a.x - b.x).abs() as u8 + (a.y - b.y).abs() as u8
8+
}
69

710
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
811
#[repr(u8)]
@@ -32,7 +35,7 @@ impl Grid {
3235
}
3336
}
3437

35-
pub fn get_index(&self, x: i8, y: i8) -> usize {
38+
fn get_index(&self, x: i8, y: i8) -> usize {
3639
return (x as usize) * (self.height as usize) + (y as usize);
3740
}
3841
pub fn get_cell(&self, p: &Point) -> Cell {
@@ -48,6 +51,25 @@ impl Grid {
4851
}
4952
}
5053

54+
pub struct WalkableGrid {
55+
grid: Grid,
56+
wall: Cell,
57+
}
58+
impl WalkableGrid {
59+
pub fn create(grid: Grid, wall: Cell) -> WalkableGrid {
60+
WalkableGrid { grid, wall }
61+
}
62+
pub fn is_cell_walkable(&self, p: &Point) -> bool {
63+
!self.grid.is_inside(p) || self.grid.get_cell(p) < self.wall
64+
}
65+
pub fn set_wall(&mut self, wall: Cell) -> () {
66+
self.wall = wall;
67+
}
68+
pub fn is_inside(&self, p: &Point) -> bool {
69+
self.grid.is_inside(p)
70+
}
71+
}
72+
5173
pub const DIRECTION_RIGHT: Point = Point { x: 1, y: 0 };
5274
pub const DIRECTION_LEFT: Point = Point { x: -1, y: 0 };
5375
pub const DIRECTION_UP: Point = Point { x: 0, y: 1 };

packages/solver-r/src/lib.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
mod astar;
2+
mod astar_snake;
23
mod grid;
34
mod snake;
45
mod snake_compact;
56
mod snake_walk;
67
mod solver;
78

89
use astar::get_path;
10+
use astar_snake::get_snake_path;
911
use grid::{Cell, Grid, Point};
1012
use js_sys;
11-
use solver::get_free_cell;
13+
use solver::get_free_cells;
1214
use wasm_bindgen::prelude::*;
1315

1416
#[wasm_bindgen]
@@ -96,12 +98,22 @@ impl From<IPoint> for Point {
9698
}
9799
}
98100
}
101+
impl From<&IPoint> for Point {
102+
fn from(value: &IPoint) -> Self {
103+
Self {
104+
x: value.x,
105+
y: value.y,
106+
}
107+
}
108+
}
109+
110+
type ISnake = Vec<IPoint>;
99111

100112
#[wasm_bindgen]
101-
pub fn iget_free_cell(grid: &IGrid) -> js_sys::Uint8Array {
113+
pub fn iget_free_cells(grid: &IGrid) -> js_sys::Uint8Array {
102114
let g = Grid::from(grid.clone());
103115

104-
let (_, out) = get_free_cell(&g, Cell::Color1);
116+
let (_, out) = get_free_cells(&g, Cell::Color1);
105117

106118
let o: Vec<u8> = out.iter().flat_map(|p| [p.x as u8, p.y as u8]).collect();
107119

@@ -125,3 +137,21 @@ pub fn iastar(grid: &IGrid, start: IPoint, end: IPoint) -> Option<js_sys::Array>
125137

126138
res.map(|l| l.into_iter().map(IPoint::from).map(JsValue::from).collect())
127139
}
140+
141+
#[wasm_bindgen]
142+
pub fn iastar_snake(grid: &IGrid, start: ISnake, end: IPoint) -> Option<js_sys::Array> {
143+
let g = Grid::from(grid.clone());
144+
let res = get_snake_path(
145+
|p| {
146+
(!g.is_inside(p) || g.get_cell(p) <= Cell::Color1)
147+
&& (-3 <= p.x
148+
&& p.x <= grid.width as i8 + 4
149+
&& -3 <= p.y
150+
&& p.y <= grid.height as i8 + 4)
151+
},
152+
&start.iter().map(Point::from).collect(),
153+
&Point::from(end),
154+
);
155+
156+
res.map(|l| l.into_iter().map(IPoint::from).map(JsValue::from).collect())
157+
}

packages/solver-r/src/snake.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,15 @@ pub fn move_snake(s: &mut Snake, dir: &Point) -> () {
1111
e.y = s[0].y + dir.y;
1212
s.insert(0, e);
1313
}
14-
pub fn snake_will_self_collide(s: &Snake, dir: &Point) -> bool {
15-
let next_head = Point {
16-
x: s[0].x + dir.x,
17-
y: s[0].y + dir.y,
18-
};
14+
pub fn snake_will_self_collide(s: &[Point], dir: &Point) -> bool {
15+
let next_head = get_next_snake_head(s, dir);
1916

2017
(&s[0..(s.len() - 1)]).contains(&next_head)
2118
}
22-
pub fn get_snake_head(s: &Snake) -> Point {
19+
pub fn get_snake_head(s: &[Point]) -> Point {
2320
s[0]
2421
}
25-
pub fn get_next_snake_head(s: &Snake, dir: &Point) -> Point {
22+
pub fn get_next_snake_head(s: &[Point], dir: &Point) -> Point {
2623
Point {
2724
x: s[0].x + dir.x,
2825
y: s[0].y + dir.y,

packages/solver-r/src/snake_walk.rs

Lines changed: 106 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,135 @@
11
use std::collections::HashSet;
22

33
use crate::astar::get_path;
4-
use crate::grid::{Cell, Grid, Point, DIRECTIONS};
4+
use crate::grid::{get_distance, Cell, Grid, Point, WalkableGrid, DIRECTIONS};
55
use crate::snake::{
66
get_next_snake_head, get_snake_head, move_snake, snake_will_self_collide, Snake,
77
};
88

99
struct Node {
10-
point: Point,
11-
weight: u8,
12-
h: u8,
13-
parent: Option<Point>,
10+
cells_eaten: u8,
11+
path: Vec<Point>,
12+
}
13+
14+
pub fn can_snake_reach_outside(
15+
grid: &WalkableGrid,
16+
free_cells: &HashSet<Point>,
17+
snake: &Snake,
18+
) -> bool {
19+
let mut open_list: Vec<Snake> = Vec::new();
20+
open_list.push(snake.clone());
21+
22+
let mut close_list: HashSet<Snake> = HashSet::new();
23+
24+
while let Some(s) = open_list.pop() {
25+
for dir in DIRECTIONS {
26+
if snake_will_self_collide(&s, &dir) {
27+
continue;
28+
}
29+
30+
let next_head = get_next_snake_head(&s, &dir);
31+
32+
if !grid.is_inside(&next_head) {
33+
return true;
34+
}
35+
36+
if !free_cells.contains(&next_head) {
37+
continue;
38+
}
39+
40+
let mut next_snake = s.clone();
41+
move_snake(&mut next_snake, &dir);
42+
43+
if close_list.contains(&next_snake) {
44+
continue;
45+
}
46+
47+
open_list.push(next_snake);
48+
}
49+
50+
close_list.insert(s);
51+
}
52+
53+
false
1454
}
1555

1656
pub fn get_route_to_eat_all(
17-
grid: &Grid,
18-
walkable: Cell,
57+
grid: &WalkableGrid,
58+
free_cells: &HashSet<Point>,
1959
initial_snake: &Snake,
20-
cells_to_eat: HashSet<Point>,
60+
cells_to_eat: Vec<Point>,
2161
) -> Vec<Point> {
22-
// let mut targets: Vec<Point> = cells_to_eat.iter().map(|p| p.clone()).collect();
62+
// element 0 is the snake head
63+
let mut path: Vec<Point> = Vec::new();
64+
65+
// path.append(&mut initial_snake.clone());
66+
67+
// while true {
68+
// let head = path[0];
69+
70+
// let forbidden_direction = Point {
71+
// x: path[1].x - head.x,
72+
// y: path[1].y - head.y,
73+
// };
74+
75+
// // get best route to best target
76+
// let route = vec![];
77+
// }
78+
79+
path
80+
}
81+
82+
/*
83+
* snake astar
84+
*/
2385

24-
// let open_list = get_path(|p|);
86+
pub fn get_route_to_cell(grid: &WalkableGrid, snake: &Snake, target: &Point) -> Vec<Point> {
87+
let mut open_list: Vec<Node> = Vec::new();
88+
89+
vec![]
90+
}
2591

26-
let mut targets: Vec<&Point> = cells_to_eat.iter().collect();
92+
pub fn get_route_to_eat_all_2(
93+
grid: &WalkableGrid,
94+
free_cells: &HashSet<Point>,
95+
initial_snake: &Snake,
96+
cells_to_eat: Vec<Point>,
97+
) -> Vec<Point> {
98+
let mut open_list: Vec<Node> = Vec::new();
2799

28100
let mut path: Vec<Point> = Vec::new();
29101

30102
let mut initial_snake = initial_snake.clone();
31103

32-
while let Some(target) = targets.pop() {
33-
// prepare
34-
let mut open_list: HashSet<(Snake, Vec<Point>)> = HashSet::new();
35-
open_list.insert((initial_snake.clone(), Vec::new()));
104+
open_list.push(Node {
105+
cells_eaten: 0,
106+
path: {
107+
let mut initial_path = initial_snake.clone();
108+
initial_path.reverse();
109+
initial_path
110+
},
111+
});
36112

37-
while let Some(x) = open_list.iter().next().cloned() {
38-
open_list.remove(&x);
113+
while let Some(n) = open_list.pop() {
114+
// determine next target
39115

40-
let snake = x.0;
41-
let mut sub_path = x.1;
42-
43-
if get_snake_head(&snake) == *target {
44-
path.append(&mut sub_path);
45-
initial_snake = snake;
46-
break;
116+
let mut best_target = None;
117+
let mut min_score: u8 = 200;
118+
for t in cells_to_eat.iter() {
119+
// if already visited ignore
120+
if n.path.contains(t) {
121+
continue;
47122
}
48123

49-
for dir in DIRECTIONS {
50-
if {
51-
let h = get_next_snake_head(&snake, &dir);
52-
grid.get_cell(&h) <= walkable
53-
} && !snake_will_self_collide(&snake, &dir)
54-
{
55-
let mut next_snake = snake.clone();
56-
move_snake(&mut next_snake, &dir);
124+
let head = n.path.last().unwrap();
125+
126+
let distance = get_distance(head, t);
57127

58-
let mut next_sub_path = sub_path.clone();
59-
next_sub_path.push(dir.clone());
128+
let score = distance;
60129

61-
open_list.insert((next_snake, next_sub_path));
62-
}
130+
if score < min_score {
131+
min_score = score;
132+
best_target = Some(t);
63133
}
64134
}
65135
}

packages/solver-r/src/solver.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::collections::HashSet;
22

33
use crate::grid::{Cell, Grid, Point};
44

5-
pub fn get_free_cell(grid: &Grid, walkable: Cell) -> (HashSet<Point>, HashSet<Point>) {
5+
pub fn get_free_cells(grid: &Grid, walkable: Cell) -> (HashSet<Point>, HashSet<Point>) {
66
let mut free_cells: HashSet<Point> = HashSet::new();
77
let mut one_way_cells: HashSet<Point> = HashSet::new();
88
let mut open_list: HashSet<Point> = HashSet::new();
@@ -113,7 +113,7 @@ fn it_should_collect_free_cell() {
113113

114114
grid.set_cell(&Point { x: 1, y: 1 }, Cell::Color2);
115115

116-
let (free_cells, _) = get_free_cell(&grid, Cell::Color1);
116+
let (free_cells, _) = get_free_cells(&grid, Cell::Color1);
117117

118118
assert_eq!(
119119
free_cells,

packages/types/__fixtures__/grid.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,4 @@ export const smallFull = createRandom(10, 7, 0);
107107
// small realistic
108108
export const realistic = createRandom(52, 7, 3);
109109
export const realisticFull = createRandom(52, 7, 0);
110+

0 commit comments

Comments
 (0)