rust/land2d/src/lib.rs
changeset 13924 a140f28decc4
parent 13917 a83ba9ba1566
child 13931 9230aed8a32e
equal deleted inserted replaced
13923:4d63acb2b978 13924:a140f28decc4
     6     pixels: vec2d::Vec2D<T>,
     6     pixels: vec2d::Vec2D<T>,
     7     width_mask: usize,
     7     width_mask: usize,
     8     height_mask: usize,
     8     height_mask: usize,
     9 }
     9 }
    10 
    10 
    11 impl<T: Default + Copy> Land2D<T> {
    11 impl<T: Default + Copy + PartialEq> Land2D<T> {
    12     pub fn new(width: usize, height: usize) -> Self {
    12     pub fn new(width: usize, height: usize) -> Self {
    13         assert!(width.is_power_of_two());
    13         assert!(width.is_power_of_two());
    14         assert!(height.is_power_of_two());
    14         assert!(height.is_power_of_two());
    15 
    15 
    16         Self {
    16         Self {
    19             height_mask: !(height - 1),
    19             height_mask: !(height - 1),
    20         }
    20         }
    21     }
    21     }
    22 
    22 
    23     #[inline]
    23     #[inline]
    24     fn is_valid_coordinate(&self, x: i32, y: i32) -> bool {
    24     pub fn width(&self) -> usize {
       
    25         self.pixels.width()
       
    26     }
       
    27 
       
    28     #[inline]
       
    29     pub fn height(&self) -> usize {
       
    30         self.pixels.height()
       
    31     }
       
    32 
       
    33     #[inline]
       
    34     pub fn is_valid_coordinate(&self, x: i32, y: i32) -> bool {
    25         (x as usize & self.width_mask) == 0 && (y as usize & self.height_mask) == 0
    35         (x as usize & self.width_mask) == 0 && (y as usize & self.height_mask) == 0
    26     }
    36     }
    27 
    37 
    28     #[inline]
    38     #[inline]
    29     pub fn map<U, F: FnOnce(&mut T) -> U>(&mut self, y: i32, x: i32, f: F) {
    39     pub fn map<U, F: FnOnce(&mut T) -> U>(&mut self, y: i32, x: i32, f: F) {
    78             }
    88             }
    79 
    89 
    80             self.map(y, x, |p| *p = value);
    90             self.map(y, x, |p| *p = value);
    81         }
    91         }
    82     }
    92     }
       
    93 
       
    94     pub fn fill(&mut self, start_x: i32, start_y: i32, border_value: T, fill_value: T) {
       
    95         debug_assert!(self.is_valid_coordinate(start_x - 1, start_y));
       
    96         debug_assert!(self.is_valid_coordinate(start_x, start_y));
       
    97 
       
    98         let mut stack: Vec<(usize, usize, usize, isize)> = Vec::new();
       
    99         fn push<T: Default + Copy + PartialEq>(
       
   100             land: &Land2D<T>,
       
   101             stack: &mut Vec<(usize, usize, usize, isize)>,
       
   102             xl: usize,
       
   103             xr: usize,
       
   104             y: usize,
       
   105             dir: isize,
       
   106         ) {
       
   107             let yd = y as isize + dir;
       
   108 
       
   109             if land.is_valid_coordinate(0, yd as i32) {
       
   110                 stack.push((xl, xr, yd as usize, dir));
       
   111             }
       
   112         };
       
   113 
       
   114         let start_x_l = (start_x - 1) as usize;
       
   115         let start_x_r = start_x as usize;
       
   116         push(self, &mut stack, start_x_l, start_x_r, start_y as usize, -1);
       
   117         push(self, &mut stack, start_x_l, start_x_r, start_y as usize, 1);
       
   118 
       
   119         loop {
       
   120             let a = stack.pop();
       
   121             match a {
       
   122                 None => return,
       
   123                 Some(a) => {
       
   124                     let (mut xl, mut xr, y, mut dir) = a;
       
   125 
       
   126                     while xl > 0 && self
       
   127                         .pixels
       
   128                         .get(y, xl)
       
   129                         .map_or(false, |v| *v != border_value && *v != fill_value)
       
   130                     {
       
   131                         xl -= 1;
       
   132                     }
       
   133 
       
   134                     while xr < self.width() - 1 && self
       
   135                         .pixels
       
   136                         .get(y, xr)
       
   137                         .map_or(false, |v| *v != border_value && *v != fill_value)
       
   138                     {
       
   139                         xr += 1;
       
   140                     }
       
   141 
       
   142                     while xl < xr {
       
   143                         while xl <= xr
       
   144                             && (self.pixels[y][xl] == border_value
       
   145                                 || self.pixels[y][xl] == fill_value)
       
   146                         {
       
   147                             xl += 1;
       
   148                         }
       
   149 
       
   150                         let mut x = xl;
       
   151 
       
   152                         while xl <= xr
       
   153                             && (self.pixels[y][xl] != border_value
       
   154                                 && self.pixels[y][xl] != fill_value)
       
   155                         {
       
   156                             self.pixels[y][xl] = fill_value;
       
   157 
       
   158                             xl += 1;
       
   159                         }
       
   160 
       
   161                         if x < xl {
       
   162                             push(self, &mut stack, x, xl - 1, y, dir);
       
   163                             push(self, &mut stack, x, xl - 1, y, -dir);
       
   164                         }
       
   165                     }
       
   166                 }
       
   167             }
       
   168         }
       
   169     }
    83 }
   170 }
    84 
   171 
    85 #[cfg(test)]
   172 #[cfg(test)]
    86 mod tests {
   173 mod tests {
    87     use super::*;
   174     use super::*;
    88 
   175 
    89     #[test]
   176     #[test]
    90     fn basics() {
   177     fn basics() {
    91         let  l:Land2D<u8> = Land2D::new(32, 64);
   178         let l: Land2D<u8> = Land2D::new(32, 64);
    92 
   179 
    93         assert!(l.is_valid_coordinate(0, 0));
   180         assert!(l.is_valid_coordinate(0, 0));
    94         assert!(!l.is_valid_coordinate(-1, -1));
   181         assert!(!l.is_valid_coordinate(-1, -1));
    95 
   182 
    96         assert!(l.is_valid_coordinate(31, 63));
   183         assert!(l.is_valid_coordinate(31, 63));
    97         assert!(!l.is_valid_coordinate(32, 63));
   184         assert!(!l.is_valid_coordinate(32, 63));
    98         assert!(!l.is_valid_coordinate(31, 64));
   185         assert!(!l.is_valid_coordinate(31, 64));
    99     }
   186     }
   100 
   187 
       
   188     #[test]
       
   189     fn fill() {
       
   190         let mut l: Land2D<u8> = Land2D::new(128, 128);
       
   191 
       
   192         l.draw_line(0, 0, 32, 96, 1);
       
   193         l.draw_line(32, 96, 64, 32, 1);
       
   194         l.draw_line(64, 32, 96, 80, 1);
       
   195         l.draw_line(96, 80, 128, 0, 1);
       
   196 
       
   197         l.draw_line(0, 128, 64, 96, 1);
       
   198         l.draw_line(128, 128, 64, 96, 1);
       
   199 
       
   200         l.fill(32, 32, 1, 2);
       
   201         l.fill(16, 96, 1, 3);
       
   202         l.fill(60, 100, 1, 4);
       
   203 
       
   204         assert_eq!(l.pixels[0][0], 1);
       
   205         assert_eq!(l.pixels[96][64], 1);
       
   206 
       
   207         assert_eq!(l.pixels[40][32], 2);
       
   208         assert_eq!(l.pixels[40][96], 2);
       
   209         assert_eq!(l.pixels[5][0], 3);
       
   210         assert_eq!(l.pixels[120][0], 3);
       
   211         assert_eq!(l.pixels[5][127], 3);
       
   212         assert_eq!(l.pixels[120][127], 3);
       
   213         assert_eq!(l.pixels[35][64], 3);
       
   214         assert_eq!(l.pixels[120][20], 4);
       
   215         assert_eq!(l.pixels[120][100], 4);
       
   216         assert_eq!(l.pixels[100][64], 4);
       
   217     }
   101 }
   218 }