diff --git a/packages/solver-r/src/grid.rs b/packages/solver-r/src/grid.rs index 0e83970..f70c463 100644 --- a/packages/solver-r/src/grid.rs +++ b/packages/solver-r/src/grid.rs @@ -1,10 +1,10 @@ #[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)] pub struct Point { - pub x: u8, - pub y: u8, + pub x: i8, + pub y: i8, } -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] #[repr(u8)] pub enum Cell { Empty = 0, @@ -32,7 +32,7 @@ impl Grid { } } - pub fn get_index(&self, x: u8, y: u8) -> usize { + pub fn get_index(&self, x: i8, y: i8) -> usize { return (x as usize) * (self.height as usize) + (y as usize); } pub fn get_cell(&self, p: &Point) -> Cell { @@ -43,8 +43,18 @@ impl Grid { let i = self.get_index(p.x, p.y); self.cells[i] = value; } + pub fn is_inside(&self, p: &Point) -> bool { + p.x >= 0 && p.x < (self.width as i8) && p.y >= 0 && p.y < (self.height as i8) + } } +#[test] +fn it_should_sort_cell() { + assert_eq!(Cell::Empty < Cell::Color1, true); + assert_eq!(Cell::Color1 < Cell::Color2, true); + assert_eq!(Cell::Color2 < Cell::Color3, true); + assert_eq!(Cell::Color3 < Cell::Color4, true); +} #[test] fn it_should_grid_create() { let grid = Grid::create_empty(30, 10); diff --git a/packages/solver-r/src/lib.rs b/packages/solver-r/src/lib.rs index 00ed748..98179bb 100644 --- a/packages/solver-r/src/lib.rs +++ b/packages/solver-r/src/lib.rs @@ -70,7 +70,7 @@ pub fn iget_free_cell(grid: &IGrid) -> js_sys::Uint8Array { let out = get_free_cell(&g, Cell::Color1); - let o: Vec = out.iter().flat_map(|p| [p.x, p.y]).collect(); + let o: Vec = out.iter().flat_map(|p| [p.x as u8, p.y as u8]).collect(); js_sys::Uint8Array::from(&o[..]) } diff --git a/packages/solver-r/src/solver.rs b/packages/solver-r/src/solver.rs index 059b18f..c2e0cc4 100644 --- a/packages/solver-r/src/solver.rs +++ b/packages/solver-r/src/solver.rs @@ -5,15 +5,62 @@ use crate::grid::{Cell, Grid, Point}; pub fn get_free_cell(grid: &Grid, walkable: Cell) -> HashSet { let mut free: HashSet = HashSet::new(); let mut open_list: HashSet = HashSet::new(); - let mut changed = true; - open_list.insert(Point { x: 0, y: 0 }); - - while changed { - changed = false + for x in -1..((grid.width as i8) + 1) { + open_list.insert(Point { x, y: 0 }); + open_list.insert(Point { + x, + y: (grid.height as i8) - 1, + }); } - open_list + let directions = [ + Point { x: 1, y: 0 }, + Point { x: -1, y: 0 }, + Point { x: 0, y: 1 }, + Point { x: 0, y: -1 }, + ]; + + while let Some(p) = open_list.iter().next().cloned() { + open_list.remove(&p); + + let exit_count: u8 = directions.iter().fold(0, |sum, dir| { + let neighbour = Point { + x: p.x + dir.x, + y: p.y + dir.y, + }; + + if !grid.is_inside(&neighbour) { + sum + 2 + } else if free.contains(&neighbour) { + sum + 1 + } else { + sum + } + }); + + if exit_count >= 2 { + if grid.is_inside(&p) && grid.get_cell(&p) <= walkable { + free.insert(p); + } + + for dir in directions { + let neighbour = Point { + x: p.x + dir.x, + y: p.y + dir.y, + }; + + if grid.is_inside(&neighbour) + && (grid.get_cell(&neighbour) <= walkable) + && !free.contains(&neighbour) + { + open_list.insert(neighbour); + } + } + } + } + + free } #[test] @@ -28,7 +75,9 @@ fn it_should_collect_free_cell() { free_cells, HashSet::from([ // - Point { x: 0, y: 0 } + Point { x: 0, y: 0 }, + Point { x: 0, y: 1 }, + Point { x: 1, y: 0 }, ]) ); }