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 ) ]
166pub 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