Skip to content

Commit b6c5a23

Browse files
committed
..
1 parent 5a220f4 commit b6c5a23

File tree

9 files changed

+206
-71
lines changed

9 files changed

+206
-71
lines changed

cargo/Cargo.lock

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

cargo/snk-js/src/lib.rs

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,33 @@ pub fn log() {
2222
#[wasm_bindgen]
2323
pub fn get_snake_path(grid: IColorGrid, snake: Vec<IPoint>, to: IPoint) -> Option<Vec<IPoint>> {
2424
let grid = snk_grid::grid::Grid::from(grid);
25+
let snake = Snake4::from_points(
26+
snake
27+
.into_iter()
28+
.map(|p| Point::from(p))
29+
.collect::<Vec<_>>()
30+
.try_into()
31+
.expect("snake should be 4 points"),
32+
);
2533
let res = snk_solver::snake_path::get_snake_path(
26-
|p| grid.get_color(p).cost(),
27-
Snake4::from_points(
28-
snake
29-
.into_iter()
30-
.map(|p| Point::from(p))
31-
.collect::<Vec<_>>()
32-
.try_into()
33-
.expect("snake should be 4 points"),
34-
),
34+
|p| match grid.get_color(p) {
35+
Color::Empty => 1,
36+
Color::Color1 => 10,
37+
Color::Color2 => 100,
38+
Color::Color3 => 200,
39+
Color::Color4 => 300,
40+
},
41+
&snake,
3542
to.into(),
36-
99999,
43+
10,
3744
);
3845

39-
res.map(|d| d.into_iter().map(|d| IPoint::from(d.to_point())).collect())
46+
res.map(|d| {
47+
d.into_iter()
48+
.map(|dir| dir.to_point())
49+
.map(IPoint::from)
50+
.collect()
51+
})
4052
}
4153

4254
// #[wasm_bindgen]

cargo/snk-solver/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ authors.workspace = true
77

88
[dependencies]
99
snk-grid = { workspace = true }
10+
log = "0.4"

cargo/snk-solver/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,25 @@ for each cell, true if there is two separated path from the cell to the outside
1212

1313
useful because it means the snake can freely go there
1414

15+
**coil**
16+
17+
given a cave compute the max length of a snake that can loop
18+
19+
assumptions:
20+
- can add any cell that is linked to ast least two other coilable cells
21+
- should be rounded by 2
22+
23+
edge case:
24+
```
25+
// tunnel
26+
#########
27+
# ###
28+
# # ###
29+
# # ###
30+
# ###
31+
#########
32+
```
33+
1534
## Steps
1635

1736
For each color
Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,50 @@
11
use snk_grid::{
22
color::Color,
3-
direction::iter_neighbour,
3+
direction::{add_direction, iter_neighbour},
44
grid::{Grid, iter_rectangle_hull},
55
point::Point,
66
};
77
use std::collections::HashSet;
88

9-
struct CollectionCost {
9+
use crate::path_to_outside_grid::ExitDirection;
10+
11+
pub struct CollectionCost {
1012
in_cost: u32,
1113
out_cost: u32,
1214
}
1315

14-
pub fn get_collect_cost(is_outside: F, get_cost: C) -> CollectionCost
15-
where
16-
F: Fn(Point) -> bool,
17-
F: Fn(Point) -> u32,
18-
{
16+
// pub fn get_collect_cost_(is_outside: F, get_cost: C) -> CollectionCost
17+
// where
18+
// F: Fn(Point) -> bool,
19+
// F: Fn(Point) -> u32,
20+
// {
21+
// }
22+
23+
pub fn get_collect_cost(
24+
grid: &Grid<Color>,
25+
exit_grid: &Grid<ExitDirection>,
26+
dot: Point,
27+
) -> CollectionCost {
28+
let in_cost = exit_grid.get(dot).cost;
29+
30+
let mut grid = grid.clone();
31+
32+
let mut p = dot;
33+
loop {
34+
let e = exit_grid.get(dot);
35+
if e.cost == 0 {
36+
break;
37+
}
38+
grid.set(p, Color::Empty);
39+
p = add_direction(p, e.exit_direction);
40+
}
41+
42+
// TODO compute a probable initial snake
43+
44+
// TODO from that snake, seak the outside without self-colliding
45+
46+
CollectionCost {
47+
in_cost,
48+
out_cost: 0,
49+
}
1950
}

cargo/snk-solver/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// pub mod cave;
22
// pub mod reach_outside;
3+
mod collect_cost;
34
pub mod cost_to_outside;
45
mod fitness;
56
mod path_to_outside_grid;

cargo/snk-solver/src/path_to_outside_grid.rs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@ use snk_grid::{
77
use std::collections::HashSet;
88

99
#[derive(Copy, Clone)]
10-
pub struct ExitCell {
11-
cost: u32,
12-
exit_direction: Direction,
10+
pub struct ExitDirection {
11+
pub cost: u32,
12+
pub exit_direction: Direction,
1313
}
14-
impl ToString for ExitCell {
14+
impl ExitDirection {
15+
pub fn is_outside(&self) -> bool {
16+
self.cost == 0
17+
}
18+
}
19+
impl ToString for ExitDirection {
1520
fn to_string(&self) -> String {
1621
if self.cost == 0 {
1722
"o".to_string()
@@ -23,11 +28,11 @@ impl ToString for ExitCell {
2328

2429
//
2530
// cost_to_outside : for each cell return the minimal cost ( = sum of dot, with greater color costing more ) to get outside
26-
pub fn create_path_to_outside(grid: &Grid<Color>) -> Grid<ExitCell> {
27-
let mut path_to_outside = Grid::<ExitCell>::create_with_value(
31+
pub fn create_path_to_outside(grid: &Grid<Color>) -> Grid<ExitDirection> {
32+
let mut path_to_outside = Grid::<ExitDirection>::create_with_value(
2833
grid.width,
2934
grid.height,
30-
ExitCell {
35+
ExitDirection {
3136
cost: u32::MAX,
3237
exit_direction: Direction::UP,
3338
},

cargo/snk-solver/src/snake_path.rs

Lines changed: 85 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use log::info;
12
use snk_grid::{
23
direction::{Direction, iter_directions},
34
point::{Point, get_distance},
@@ -9,23 +10,20 @@ use std::collections::{BinaryHeap, HashSet};
910
struct Node {
1011
pub snake: Snake4,
1112
pub weight: u32,
12-
pub heuristic: u32,
13-
pub parent: Option<(Box<Node>, Direction)>,
14-
}
15-
impl Node {
16-
fn f(&self) -> u32 {
17-
self.weight + self.heuristic
18-
}
13+
pub distance: u32,
14+
pub f: u32,
15+
pub path: Vec<Direction>,
1916
}
17+
2018
impl Eq for Node {}
2119
impl PartialEq for Node {
2220
fn eq(&self, other: &Self) -> bool {
23-
self.parent == other.parent
21+
self.path == other.path
2422
}
2523
}
2624
impl Ord for Node {
2725
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
28-
self.f().cmp(&other.f()).reverse()
26+
self.f.cmp(&other.f)
2927
}
3028
}
3129
impl PartialOrd for Node {
@@ -36,7 +34,7 @@ impl PartialOrd for Node {
3634

3735
pub fn get_snake_path<F>(
3836
get_walk_cost: F,
39-
from: Snake4,
37+
from: &Snake4,
4038
to: Point,
4139
max_weight: u32,
4240
) -> Option<Vec<Direction>>
@@ -47,21 +45,61 @@ where
4745
let mut close_list: HashSet<Snake4> = HashSet::new();
4846

4947
open_list.push(Node {
50-
heuristic: get_distance(from.get_head(), to) as u32,
51-
snake: from,
48+
distance: 0,
49+
snake: from.clone(),
50+
weight: 0,
51+
f: 0,
52+
path: Vec::new(),
53+
});
54+
55+
open_list.push(Node {
56+
distance: 0,
57+
snake: from.clone(),
5258
weight: 0,
53-
parent: None,
59+
f: 3,
60+
path: Vec::new(),
5461
});
5562

63+
open_list.push(Node {
64+
distance: 0,
65+
snake: from.clone(),
66+
weight: 0,
67+
f: 1,
68+
path: Vec::new(),
69+
});
70+
open_list.push(Node {
71+
distance: 0,
72+
snake: from.clone(),
73+
weight: 0,
74+
f: 5,
75+
path: Vec::new(),
76+
});
77+
78+
log::info!(
79+
"open_list {:?}",
80+
open_list
81+
.clone()
82+
.into_iter()
83+
.map(|n| n.f)
84+
.collect::<Vec<_>>()
85+
);
86+
87+
let mut loop_count = 0;
88+
5689
while let Some(node) = open_list.pop() {
57-
// println!(
58-
// "{:?}",
59-
// open_list
60-
// .clone()
61-
// .into_iter()
62-
// .map(|n| n.weight)
63-
// .collect::<Vec<_>>()
64-
// );
90+
loop_count += 1;
91+
92+
log::info!(
93+
"loop {} node {} {:?} open_list {:?}",
94+
loop_count,
95+
node.f,
96+
node.snake.get_head(),
97+
open_list
98+
.clone()
99+
.into_iter()
100+
.map(|n| n.f)
101+
.collect::<Vec<_>>()
102+
);
65103

66104
for dir in iter_directions() {
67105
if snake_will_self_collide(&node.snake, dir) {
@@ -78,48 +116,61 @@ where
78116

79117
if to == head {
80118
// unroll and return
81-
let mut path = vec![dir];
119+
let mut path = node.path.clone();
120+
path.push(dir);
82121

83-
let mut parent = node.parent;
84-
while let Some((node, dir)) = parent {
85-
path.push(dir);
86-
parent = node.parent;
87-
}
122+
log::info!(" {:?} : {:?}", to, head);
123+
log::info!("found loop {} length: {}", loop_count, path.len());
88124

89125
path.reverse();
90126
return Some(path);
91127
}
92128

93129
let weight = node.weight + get_walk_cost(head);
94-
let heuristic = get_distance(head, to) as u32;
130+
let distance = get_distance(head, to) as u32;
131+
log::info!(" {:?} {:?}", head, distance);
95132

96-
if weight + heuristic > max_weight {
97-
continue;
98-
}
133+
let f = weight + distance;
134+
// if f > max_weight {
135+
// continue;
136+
// }
99137

138+
let mut path = node.path.clone();
139+
path.push(dir);
100140
open_list.push(Node {
101141
snake,
102142
weight,
103-
heuristic,
104-
parent: Some((Box::new(node.clone()), dir)),
143+
distance,
144+
f,
145+
path,
105146
});
106147
}
107148

108149
close_list.insert(node.snake);
150+
151+
log::info!(
152+
"open_list {:?}",
153+
open_list
154+
.clone()
155+
.into_iter()
156+
.map(|n| n.f)
157+
.collect::<Vec<_>>()
158+
);
109159
}
110160

111161
None
112162
}
113163

114164
#[test]
165+
#[ignore]
115166
fn it_should_found_simple_path() {
116167
let snake = Snake4::from_points([
117168
Point { x: 0, y: 0 },
118169
Point { x: 1, y: 0 },
119170
Point { x: 2, y: 0 },
120171
Point { x: 3, y: 0 },
121172
]);
122-
let res = get_snake_path(|_| 1, snake, Point { x: 0, y: 3 }, 9999);
173+
let res = get_snake_path(|_| 1, &snake, Point { x: 0, y: 3 }, 9999);
123174

124175
assert_eq!(
125176
res,

0 commit comments

Comments
 (0)