Skip to content

Commit d61b459

Browse files
committed
..
1 parent 74536c7 commit d61b459

File tree

7 files changed

+247
-14
lines changed

7 files changed

+247
-14
lines changed

cargo/snk-grid/src/direction.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@ pub const DIRECTIONS: [Direction; 4] = [
1818
Direction::RIGHT,
1919
];
2020

21+
impl Into<Point> for Direction {
22+
fn into(self) -> Point {
23+
match self {
24+
Direction::UP => Point { x: 0, y: -1 },
25+
Direction::DOWN => Point { x: 0, y: 1 },
26+
Direction::LEFT => Point { x: -1, y: 0 },
27+
Direction::RIGHT => Point { x: 1, y: 0 },
28+
}
29+
}
30+
}
31+
2132
impl Direction {
2233
pub fn to_point(&self) -> Point {
2334
match self {

cargo/snk-grid/src/grid_samples.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,18 @@ pub enum SampleGrid {
2929
Empty,
3030
OneDot,
3131
OneCave,
32+
OneSmallCave,
3233
Caves,
3334
Realistic,
3435
Labyrinth,
3536
RandomPack,
3637
SolidBlock,
3738
}
38-
pub const SAMPLEGRIDS: [SampleGrid; 8] = [
39+
pub const SAMPLEGRIDS: [SampleGrid; 9] = [
3940
SampleGrid::Empty,
4041
SampleGrid::OneDot,
4142
SampleGrid::OneCave,
43+
SampleGrid::OneSmallCave,
4244
SampleGrid::Caves,
4345
SampleGrid::Realistic,
4446
SampleGrid::Labyrinth,
@@ -73,6 +75,17 @@ _ ... _
7375
. . _
7476
.... _
7577
78+
"#,
79+
),
80+
81+
SampleGrid::OneSmallCave => Grid::<_>::from(
82+
r#"
83+
_ _
84+
_ ### _
85+
_ #.# _
86+
_ ### _
87+
_ _
88+
7689
"#,
7790
),
7891

cargo/snk-grid/src/point.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,37 @@
1+
use std::ops::{Add, AddAssign};
2+
13
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
24
pub struct Point {
35
pub x: i8,
46
pub y: i8,
57
}
68

9+
impl Point {
10+
pub fn new(x: i8, y: i8) -> Self {
11+
Self { x, y }
12+
}
13+
pub fn zero() -> Self {
14+
Self { x: 0, y: 0 }
15+
}
16+
}
17+
18+
impl Add for Point {
19+
type Output = Self;
20+
21+
fn add(self, rhs: Self) -> Self {
22+
Self {
23+
x: self.x + rhs.x,
24+
y: self.y + rhs.y,
25+
}
26+
}
27+
}
28+
impl AddAssign for Point {
29+
fn add_assign(&mut self, rhs: Self) {
30+
self.x += rhs.x;
31+
self.y += rhs.y;
32+
}
33+
}
34+
735
pub fn add(a: Point, b: Point) -> Point {
836
Point {
937
x: a.x + b.x,
Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
use snk_grid::{
22
color::Color,
3-
direction::{add_direction, iter_neighbour},
3+
direction::{Direction, add_direction, iter_neighbour},
44
grid::{Grid, iter_rectangle_hull},
5+
grid_samples::{SampleGrid, get_grid_sample},
56
point::Point,
7+
snake::Snake4,
68
};
79
use std::collections::HashSet;
810

9-
use crate::{cost::Cost, path_to_outside_grid::ExitDirection};
11+
use crate::{
12+
cost::Cost,
13+
path_to_outside_grid::{ExitDirection, create_path_to_outside},
14+
};
1015

11-
pub struct CollectionCost {
16+
pub struct Tunnel {
17+
path: Vec<Point>,
1218
in_cost: Cost,
1319
out_cost: Cost,
1420
}
@@ -20,31 +26,84 @@ pub struct CollectionCost {
2026
// {
2127
// }
2228

23-
pub fn get_collect_cost(
24-
grid: &Grid<Color>,
25-
exit_grid: &Grid<ExitDirection>,
26-
dot: Point,
27-
) -> CollectionCost {
29+
pub fn get_collect_cost(grid: &Grid<Color>, exit_grid: &Grid<ExitDirection>, dot: Point) -> Tunnel {
2830
let in_cost = exit_grid.get(dot).cost;
2931

3032
let mut grid = grid.clone();
3133

34+
let mut path_out_1 = Vec::new();
35+
3236
let mut p = dot;
37+
3338
loop {
34-
let e = exit_grid.get(dot);
35-
if e.cost.is_free() {
39+
path_out_1.push(p);
40+
41+
let (dir, outside) = if exit_grid.is_inside(p) {
42+
let e = exit_grid.get(p);
43+
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+
};
49+
50+
if path_out_1.len() >= 6 && outside {
3651
break;
3752
}
38-
grid.set(p, Color::Empty);
39-
p = add_direction(p, e.exit_direction);
53+
54+
p += dir.into();
4055
}
4156

57+
println!("path_out_1 {:?}", path_out_1);
58+
59+
let path = path_out_1
60+
.iter()
61+
.take_while(|p| exit_grid.is_inside(**p) && !exit_grid.get(**p).is_outside())
62+
.collect::<Vec<_>>();
63+
64+
println!("path {:?}", path);
65+
66+
let mut snake = Snake4::from_points(
67+
path_out_1[0..4]
68+
.try_into()
69+
.expect("snake should be 4 points"),
70+
);
71+
72+
println!("{:?}", snake);
73+
4274
// TODO compute a probable initial snake
4375

4476
// TODO from that snake, seak the outside without self-colliding
4577

46-
CollectionCost {
78+
Tunnel {
79+
path: path_out_1,
4780
in_cost,
4881
out_cost: Cost::zero(),
4982
}
5083
}
84+
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+
}
98+
}
99+
100+
#[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);
105+
106+
get_collect_cost(&grid, &pto, Point { x: 4, y: 2 });
107+
108+
assert!(false)
109+
}

cargo/snk-solver/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ mod cost;
55
mod fitness;
66
mod path_to_outside_grid;
77
pub mod snake_path;
8+
mod snake_path_to_outside;
89
pub mod solver;

cargo/snk-solver/src/path_to_outside_grid.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use snk_grid::{
33
direction::{Direction, add_direction, iter_directions},
44
grid::{Grid, iter_rectangle_hull},
55
grid_ascii::grid_to_ascii_transformed,
6+
grid_samples::{SampleGrid, get_grid_sample},
67
point::Point,
78
};
89
use std::collections::HashSet;
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
use snk_grid::{
2+
color::Color,
3+
direction::{Direction, add_direction, iter_directions, iter_neighbour},
4+
grid::{Grid, iter_rectangle_hull},
5+
grid_samples::{SampleGrid, get_grid_sample},
6+
point::Point,
7+
snake::{Snake, Snake4, snake_will_self_collide},
8+
};
9+
use std::collections::{BinaryHeap, HashSet};
10+
11+
use crate::{
12+
cost::Cost,
13+
path_to_outside_grid::{ExitDirection, create_path_to_outside},
14+
};
15+
16+
#[derive(Clone, Debug)]
17+
struct Node {
18+
pub snake: Snake4,
19+
pub cost: Cost,
20+
pub path: Vec<Direction>,
21+
}
22+
23+
impl Eq for Node {}
24+
impl PartialEq for Node {
25+
fn eq(&self, other: &Self) -> bool {
26+
self.snake == other.snake
27+
}
28+
}
29+
impl Ord for Node {
30+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
31+
other.cost.cmp(&self.cost)
32+
}
33+
}
34+
impl PartialOrd for Node {
35+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
36+
Some(self.cmp(other))
37+
}
38+
}
39+
pub fn get_snake_path_to_outside<FnOutside, FnCost>(
40+
is_outside: FnOutside,
41+
get_walk_cost: FnCost,
42+
snake: &Snake4,
43+
) -> (Vec<Direction>, Cost)
44+
where
45+
FnOutside: Fn(Point) -> bool,
46+
FnCost: Fn(Point) -> Cost,
47+
{
48+
let mut open_list: BinaryHeap<Node> = BinaryHeap::new();
49+
let mut close_list: HashSet<Snake4> = HashSet::new();
50+
51+
open_list.push(Node {
52+
snake: snake.clone(),
53+
cost: Cost::zero(),
54+
path: Vec::new(),
55+
});
56+
57+
while let Some(node) = open_list.pop() {
58+
let head = node.snake.get_head();
59+
if is_outside(head) {
60+
return (node.path, node.cost);
61+
}
62+
63+
for dir in iter_directions() {
64+
if snake_will_self_collide(&node.snake, dir) {
65+
continue;
66+
}
67+
68+
let snake = node.snake.clone_and_move(dir);
69+
70+
if close_list.contains(&snake) {
71+
// need to update open_list
72+
println!("need to update open_list");
73+
continue;
74+
}
75+
76+
let head = snake.get_head();
77+
78+
let cost = node.cost + get_walk_cost(head);
79+
let mut path = node.path.clone();
80+
path.push(dir);
81+
82+
open_list.push(Node { cost, path, snake });
83+
}
84+
85+
close_list.insert(node.snake);
86+
}
87+
88+
assert!(false, "should have terminated");
89+
(vec![], Cost::zero())
90+
}
91+
92+
#[test]
93+
fn it_should_get_snake_path_to_outside() {
94+
let grid = Grid::<_>::from(
95+
r#"
96+
_######## _
97+
_# . . _
98+
_# # _
99+
_######## _
100+
101+
"#,
102+
);
103+
let pto = create_path_to_outside(&grid);
104+
let snake = Snake4::from_points([
105+
Point { x: 2, y: 2 },
106+
Point { x: 3, y: 2 },
107+
Point { x: 4, y: 2 },
108+
Point { x: 5, y: 2 },
109+
]);
110+
111+
let is_outside = |p| !pto.is_inside(p) || pto.get(p).is_outside();
112+
113+
let (path, cost) = get_snake_path_to_outside(is_outside, |p| grid.get_color(p).into(), &snake);
114+
115+
println!("{:?} {:?}", path, cost);
116+
assert!(
117+
cost < Cost::from(Color::Color2) * 2,
118+
"should have taken the smallest path"
119+
);
120+
}

0 commit comments

Comments
 (0)