Skip to content

Commit 5ad908f

Browse files
committed
..
1 parent c354bf5 commit 5ad908f

14 files changed

Lines changed: 387 additions & 278 deletions

File tree

cargo/snk-grid/src/grid.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ pub fn iter_rectangle_hull(width: i8, height: i8) -> impl Iterator<Item = Point>
1313

1414
#[derive(Clone, Debug, PartialEq)]
1515
pub struct Grid<T: Copy> {
16-
pub width: u8,
17-
pub height: u8,
16+
pub width: i8,
17+
pub height: i8,
1818
pub cells: Vec<T>,
1919
}
2020
impl<T: Copy> Grid<T> {
@@ -45,13 +45,13 @@ impl<T: Copy> Grid<T> {
4545
}
4646

4747
/// ⚠️ assuming the point is inside the grid
48-
pub fn distance_from_outside(&self, p: Point) -> u8 {
49-
let x = p.x as u8;
50-
let y = p.y as u8;
51-
y.min(self.height - 1 - y).min(x).min(self.width - 1 - x)
48+
pub fn distance_from_outside(&self, p: Point) -> i8 {
49+
p.y.min(self.height - 1 - p.y)
50+
.min(p.x)
51+
.min(self.width - 1 - p.x)
5252
}
5353

54-
pub fn create_with_value(width: u8, height: u8, value: T) -> Grid<T> {
54+
pub fn create_with_value(width: i8, height: i8, value: T) -> Grid<T> {
5555
let n = (width as usize) * (height as usize);
5656
let cells = (0..n).map(|_| value).collect();
5757

@@ -71,7 +71,7 @@ impl<T: Copy> Grid<T> {
7171
}
7272
}
7373
impl<T: Default + Copy> Grid<T> {
74-
pub fn create_with_default(width: u8, height: u8) -> Grid<T> {
74+
pub fn create_with_default(width: i8, height: i8) -> Grid<T> {
7575
let n = (width as usize) * (height as usize);
7676
let cells = (0..n).map(|_| T::default()).collect();
7777

cargo/snk-grid/src/grid_ascii.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ pub fn grid_from_ascii<T: Copy + Default + From<char>>(ascii: &str) -> Grid<T> {
1010
let width = rows.iter().fold(0, |max_len, r| max_len.max(r.len()));
1111
let height = rows.len();
1212

13-
let mut grid = Grid::<T>::create_with_default(width as u8, height as u8);
13+
let mut grid = Grid::<T>::create_with_default(width as i8, height as i8);
1414

1515
for p in iter_rectangle_fill(width as i8, height as i8) {
1616
let mut c = rows[p.y as usize].chars().nth(p.x as usize).unwrap_or(' ');
@@ -51,6 +51,25 @@ where
5151
out
5252
}
5353

54+
pub fn get_ascii_grid<F>(grid_width: i8, grid_height: i8, to_string: F) -> String
55+
where
56+
F: Fn(Point) -> String,
57+
{
58+
let mut out: String = String::new();
59+
for y in 0..grid_height {
60+
for x in 0..grid_width {
61+
let p = Point { x, y };
62+
let s = to_string(p);
63+
let fist_char = s.chars().nth(0).unwrap();
64+
out.push(fist_char);
65+
}
66+
out.push('\n');
67+
}
68+
69+
out.pop();
70+
out
71+
}
72+
5473
pub fn grid_to_ascii<T: Copy + ToString>(grid: &Grid<T>) -> String {
5574
grid_to_ascii_transformed(grid, |value| value.to_string())
5675
}

cargo/snk-grid/src/grid_samples.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,14 @@ _ _
9191

9292
SampleGrid::Caves => Grid::<_>::from(
9393
r#"
94-
_ ### #### _
95-
# ### # # ### _
96-
# .. # # . # #.# _
97-
# # # # # # _
98-
### # ### # _
99-
#.# _
100-
### _
101-
_
94+
_ ### #### _
95+
# ### # # ### ###### _
96+
# .. # # . # #.# ## # _
97+
# # # # # # ## # _
98+
### # ### # ###### _
99+
#.# _
100+
### _
101+
_
102102
"#,
103103
),
104104

cargo/snk-js/src/lib.rs

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
use js_sys;
2-
use log::info;
3-
use snk_grid::{
4-
color::Color, direction::Direction, grid::Grid, grid_samples::SampleGrid, point::Point,
5-
snake::Snake4,
6-
};
2+
use snk_grid::{color::Color, grid_samples::SampleGrid, point::Point, snake::Snake4};
73
use wasm_bindgen::prelude::*;
84

95
#[wasm_bindgen]
@@ -12,10 +8,8 @@ pub fn init_panic_hook() {
128
}
139

1410
#[wasm_bindgen]
15-
pub fn log() {
16-
init_panic_hook();
11+
pub fn init_log() {
1712
console_log::init_with_level(log::Level::Debug).unwrap();
18-
1913
log::info!("It works!");
2014
}
2115

@@ -50,6 +44,18 @@ pub fn get_snake_path(grid: IColorGrid, snake: Vec<IPoint>, to: IPoint) -> Optio
5044
.collect()
5145
})
5246
}
47+
#[wasm_bindgen]
48+
pub fn get_best_tunnel_to_collect_point(grid: &IColorGrid, to: &IPoint) -> Vec<IPoint> {
49+
let grid = snk_grid::grid::Grid::from(grid);
50+
let exit_grid = snk_solver::exit_grid::ExitGrid::create_from_grid_color(&grid);
51+
let res =
52+
snk_solver::collect_cost::get_best_tunnel_to_collect_point(&grid, &exit_grid, to.into());
53+
54+
log::info!("{:?} {:?} {:?}",res.path,res.in_cost,res.out_cost);
55+
56+
57+
res.path.into_iter().map(IPoint::from).collect()
58+
}
5359

5460
// #[wasm_bindgen]
5561
// pub fn solve(grid: IColorGrid) -> js_sys::Uint8Array {
@@ -85,14 +91,14 @@ pub fn get_grid_sample(sample_name: String) -> IColorGrid {
8591
#[wasm_bindgen]
8692
#[derive(Clone)]
8793
pub struct IColorGrid {
88-
pub width: u8,
89-
pub height: u8,
94+
pub width: i8,
95+
pub height: i8,
9096
cells: Vec<Color>,
9197
}
9298

9399
#[wasm_bindgen]
94100
impl IColorGrid {
95-
pub fn create(width: u8, height: u8, data: js_sys::Uint8Array) -> IColorGrid {
101+
pub fn create(width: i8, height: i8, data: js_sys::Uint8Array) -> IColorGrid {
96102
if (width as usize) * (height as usize) != (data.length() as usize) {
97103
panic!(
98104
"grid {}x{} should have {} elements, found {}",
@@ -128,6 +134,15 @@ impl From<IColorGrid> for snk_grid::grid::Grid<Color> {
128134
}
129135
}
130136
}
137+
impl From<&IColorGrid> for snk_grid::grid::Grid<Color> {
138+
fn from(value: &IColorGrid) -> Self {
139+
Self {
140+
width: value.width,
141+
height: value.height,
142+
cells: value.cells.clone(),
143+
}
144+
}
145+
}
131146
impl From<snk_grid::grid::Grid<Color>> for IColorGrid {
132147
fn from(value: snk_grid::grid::Grid<Color>) -> Self {
133148
Self {
Lines changed: 86 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,12 @@
1-
use snk_grid::{
2-
color::Color,
3-
direction::{Direction, add_direction, iter_neighbour},
4-
grid::{Grid, iter_rectangle_hull},
5-
grid_samples::{SampleGrid, get_grid_sample},
6-
point::Point,
7-
snake::Snake4,
8-
};
9-
use std::collections::HashSet;
10-
11-
use crate::{
12-
cost::Cost,
13-
path_to_outside_grid::{ExitDirection, create_path_to_outside},
14-
};
1+
use snk_grid::{color::Color, grid::Grid, point::Point, snake::Snake4};
152

3+
use crate::{cost::Cost, exit_grid::ExitGrid, snake_path_to_outside::get_snake_path_to_outside};
4+
5+
#[derive(Debug)]
166
pub struct Tunnel {
17-
path: Vec<Point>,
18-
in_cost: Cost,
19-
out_cost: Cost,
7+
pub path: Vec<Point>,
8+
pub in_cost: Cost,
9+
pub out_cost: Cost,
2010
}
2111

2212
// pub fn get_collect_cost_(is_outside: F, get_cost: C) -> CollectionCost
@@ -26,84 +16,119 @@ pub struct Tunnel {
2616
// {
2717
// }
2818

29-
pub fn get_collect_cost(grid: &Grid<Color>, exit_grid: &Grid<ExitDirection>, dot: Point) -> Tunnel {
30-
let in_cost = exit_grid.get(dot).cost;
19+
pub fn get_best_tunnel_to_collect_point(
20+
grid: &Grid<Color>,
21+
exit_grid: &ExitGrid,
22+
dot: Point,
23+
) -> Tunnel {
24+
let in_cost = exit_grid.get_cost_to_outside(dot);
3125

3226
let mut grid = grid.clone();
3327

28+
// first path, from the dot to the outside, it should be at least snake length long and ends in outside
3429
let mut path_out_1 = Vec::new();
3530

3631
let mut p = dot;
3732

3833
loop {
3934
path_out_1.push(p);
40-
41-
let (dir, outside) = if exit_grid.is_inside(p) {
42-
let e = exit_grid.get(p);
35+
if grid.is_inside(p) {
4336
grid.set(p, Color::Empty);
44-
(e.exit_direction, e.is_outside())
45-
} else {
46-
println!("{:?}", get_outside_direction(&grid, p));
47-
(get_outside_direction(&grid, p), true)
48-
};
37+
}
4938

50-
if path_out_1.len() >= 6 && outside {
39+
if path_out_1.len() >= 6 && exit_grid.is_outside(p) {
5140
break;
5241
}
5342

54-
p += dir.into();
43+
p += exit_grid.get_exit_direction(p).into();
5544
}
5645

57-
println!("path_out_1 {:?}", path_out_1);
58-
59-
let path = path_out_1
46+
// path from the outside to the dot
47+
let mut path = path_out_1
6048
.iter()
61-
.take_while(|p| exit_grid.is_inside(**p) && !exit_grid.get(**p).is_outside())
49+
.map(|p| *p)
50+
.take_while(|p| !exit_grid.is_outside(*p))
6251
.collect::<Vec<_>>();
52+
path.reverse();
6353

64-
println!("path {:?}", path);
65-
66-
let mut snake = Snake4::from_points(
54+
// snake arriving from the outside to the dot
55+
let snake = Snake4::from_points(
6756
path_out_1[0..4]
6857
.try_into()
6958
.expect("snake should be 4 points"),
7059
);
7160

72-
println!("{:?}", snake);
61+
// /!\
62+
// at this stage the exit grid is not in sync with the grid_color
63+
// since we modified the grid_color
7364

74-
// TODO compute a probable initial snake
75-
76-
// TODO from that snake, seak the outside without self-colliding
65+
// from that snake, seek the outside without self-colliding
66+
let (path_out, out_cost) = get_snake_path_to_outside(
67+
|p| exit_grid.is_outside(p),
68+
|p| grid.get_color(p).into(),
69+
&snake,
70+
);
71+
for dir in path_out {
72+
let p = *path.last().unwrap();
73+
path.push(p + dir.into());
74+
}
75+
path.pop();
7776

7877
Tunnel {
79-
path: path_out_1,
78+
path,
8079
in_cost,
81-
out_cost: Cost::zero(),
80+
out_cost,
8281
}
8382
}
8483

85-
fn get_outside_direction<T: Copy>(grid: &Grid<T>, p: Point) -> Direction {
86-
if p.x < 0 {
87-
Direction::LEFT
88-
} else if p.y < 0 {
89-
Direction::UP
90-
} else if (p.x as u8) >= grid.width {
91-
Direction::RIGHT
92-
} else if (p.y as u8) >= grid.height {
93-
Direction::DOWN
94-
} else {
95-
assert!(false, "fail here");
96-
Direction::DOWN
97-
}
84+
#[test]
85+
fn it_should_compute_the_tunnel_for_enclaved_dot() {
86+
let grid = Grid::<_>::from(
87+
r#"
88+
_ _
89+
_ ### _
90+
_ #.# _
91+
_ ### _
92+
_ _
93+
94+
"#,
95+
);
96+
assert_eq!(grid.get_color(Point { x: 4, y: 2 }), Color::Color1);
97+
98+
let pto = ExitGrid::create_from_grid_color(&grid);
99+
100+
let tunnel = get_best_tunnel_to_collect_point(&grid, &pto, Point { x: 4, y: 2 });
101+
102+
assert_eq!(tunnel.in_cost.get_color_count(Color::Color4), 1);
103+
assert_eq!(tunnel.out_cost.get_color_count(Color::Color4), 1);
104+
105+
assert_eq!(tunnel.in_cost.get_color_count(Color::Color1), 1);
106+
assert_eq!(tunnel.out_cost.get_color_count(Color::Color1), 0);
98107
}
99108

100109
#[test]
101-
#[ignore]
102-
fn it_should_compute_the_tunnel_for_small_cave() {
103-
let grid = get_grid_sample(SampleGrid::OneSmallCave);
104-
let pto = create_path_to_outside(&grid);
110+
fn it_should_compute_the_tunnel_for_enclaved_dot_in_large_cave() {
111+
let grid = Grid::<_>::from(
112+
r#"
113+
_ _
114+
_ ##### _
115+
_ # # _
116+
_ # . # _
117+
_ # # _
118+
_ ##### _
119+
_ _
120+
121+
"#,
122+
);
123+
124+
assert_eq!(grid.get_color(Point { x: 5, y: 3 }), Color::Color1);
125+
126+
let pto = ExitGrid::create_from_grid_color(&grid);
105127

106-
get_collect_cost(&grid, &pto, Point { x: 4, y: 2 });
128+
let tunnel = get_best_tunnel_to_collect_point(&grid, &pto, Point { x: 5, y: 3 });
129+
assert_eq!(tunnel.in_cost.get_color_count(Color::Color4), 1);
130+
assert_eq!(tunnel.out_cost.get_color_count(Color::Color4), 0);
107131

108-
assert!(false)
132+
assert_eq!(tunnel.in_cost.get_color_count(Color::Color1), 1);
133+
assert_eq!(tunnel.out_cost.get_color_count(Color::Color1), 0);
109134
}

0 commit comments

Comments
 (0)