next #1
					 3 changed files with 53 additions and 50 deletions
				
			
		
							
								
								
									
										20
									
								
								src/game.rs
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								src/game.rs
									
										
									
									
									
								
							|  | @ -2,23 +2,19 @@ use servicepoint::{Grid, Value, ValueGrid}; | ||||||
| 
 | 
 | ||||||
| use crate::rules::Rules; | use crate::rules::Rules; | ||||||
| 
 | 
 | ||||||
| pub(crate) struct Game<TState, TKernel, const KERNEL_SIZE: usize> | pub(crate) struct Game<T: Value> | ||||||
| where |  | ||||||
|     TState: Value + PartialEq, |  | ||||||
|     TKernel: Value, |  | ||||||
| { | { | ||||||
|     pub field: ValueGrid<TState>, |     pub field: ValueGrid<T>, | ||||||
|     pub rules: Rules<TState, TKernel, KERNEL_SIZE>, |     pub rules: Rules<T>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<TState: Value + PartialEq, TKernel: Value, const KERNEL_SIZE: usize> | impl<T: Value> Game<T> | ||||||
|     Game<TState, TKernel, KERNEL_SIZE> |  | ||||||
| { | { | ||||||
|     pub fn step(&mut self) { |     pub fn step(&mut self) { | ||||||
|         self.field = self.field_iteration(); |         self.field = self.field_iteration(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn field_iteration(&self) -> ValueGrid<TState> { |     fn field_iteration(&self) -> ValueGrid<T> { | ||||||
|         let mut next = ValueGrid::new(self.field.width(), self.field.height()); |         let mut next = ValueGrid::new(self.field.width(), self.field.height()); | ||||||
|         for x in 0..self.field.width() { |         for x in 0..self.field.width() { | ||||||
|             for y in 0..self.field.height() { |             for y in 0..self.field.height() { | ||||||
|  | @ -37,14 +33,12 @@ impl<TState: Value + PartialEq, TKernel: Value, const KERNEL_SIZE: usize> | ||||||
|         let mut count = 0; |         let mut count = 0; | ||||||
| 
 | 
 | ||||||
|         let kernel = &self.rules.kernel; |         let kernel = &self.rules.kernel; | ||||||
|         assert_eq!(KERNEL_SIZE % 2, 1); |  | ||||||
|         let offset = KERNEL_SIZE as i32 / 2; |  | ||||||
| 
 | 
 | ||||||
|         for (kernel_y, kernel_row) in kernel.iter().enumerate() { |         for (kernel_y, kernel_row) in kernel.iter().enumerate() { | ||||||
|             let offset_y = kernel_y as i32 - offset; |             let offset_y = kernel_y as i32 - 1; | ||||||
| 
 | 
 | ||||||
|             for (kernel_x, kernel_value) in kernel_row.iter().enumerate() { |             for (kernel_x, kernel_value) in kernel_row.iter().enumerate() { | ||||||
|                 let offset_x = kernel_x as i32 - offset; |                 let offset_x = kernel_x as i32 - 1; | ||||||
|                 let neighbor_x = x + offset_x; |                 let neighbor_x = x + offset_x; | ||||||
|                 let neighbor_y = y + offset_y; |                 let neighbor_y = y + offset_y; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										63
									
								
								src/rules.rs
									
										
									
									
									
								
							
							
						
						
									
										63
									
								
								src/rules.rs
									
										
									
									
									
								
							|  | @ -1,28 +1,27 @@ | ||||||
| use rand::rngs::ThreadRng; | use rand::rngs::ThreadRng; | ||||||
| use rand::{thread_rng, Rng}; | use rand::{thread_rng, Rng}; | ||||||
| 
 | use servicepoint::Value; | ||||||
| use crate::print::println_info; | use crate::print::println_info; | ||||||
| 
 | 
 | ||||||
| pub struct Rules<TState, TKernel, const KERNEL_SIZE: usize> | pub struct Rules<T: Value> | ||||||
| where |  | ||||||
|     TState: Copy + PartialEq, |  | ||||||
|     TKernel: Copy, |  | ||||||
| { | { | ||||||
|     pub kernel: [[TKernel; KERNEL_SIZE]; KERNEL_SIZE], |     pub kernel: Kernel3x3, | ||||||
|     pub count_neighbor: Box<dyn Fn(TState, TKernel) -> i32>, |     pub count_neighbor: Box<dyn Fn(T, bool) -> i32>, | ||||||
|     pub next_state: Box<dyn Fn(TState, i32) -> TState>, |     pub next_state: Box<dyn Fn(T, i32) -> T>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub const MOORE_NEIGHBORHOOD: [[bool; 3]; 3] = | type Kernel3x3 = [[bool; 3]; 3]; | ||||||
|  | 
 | ||||||
|  | pub const MOORE_NEIGHBORHOOD: Kernel3x3 = | ||||||
|     [[true, true, true], [true, false, true], [true, true, true]]; |     [[true, true, true], [true, false, true], [true, true, true]]; | ||||||
| 
 | 
 | ||||||
| pub const NEUMANN_NEIGHBORHOOD: [[bool; 3]; 3] = [ | pub const NEUMANN_NEIGHBORHOOD: Kernel3x3 = [ | ||||||
|     [false, true, false], |     [false, true, false], | ||||||
|     [true, false, true], |     [true, false, true], | ||||||
|     [false, true, false], |     [false, true, false], | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
| pub const DIAGONALS_NEIGHBORHOOD: [[bool; 3]; 3] = [ | pub const DIAGONALS_NEIGHBORHOOD: Kernel3x3 = [ | ||||||
|     [true, false, true], |     [true, false, true], | ||||||
|     [false, false, false], |     [false, false, false], | ||||||
|     [true, false, true], |     [true, false, true], | ||||||
|  | @ -37,16 +36,11 @@ pub fn count_true_neighbor(neighbor_state: bool, kernel_value: bool) -> i32 { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[must_use] | #[must_use] | ||||||
| pub fn generate_bb3() -> Rules<bool, bool, 3> { | pub fn generate_bb3() -> Rules<bool> { | ||||||
|     let mut rng = thread_rng(); |     let mut rng = thread_rng(); | ||||||
| 
 | 
 | ||||||
|     let is_moore = rng.gen_bool(1.0 / 2.0); |     let kernel = choose_neighborhood(&mut rng); | ||||||
|     let kernel = if is_moore { |     let max_neighbors = count_max_neighbors(kernel); | ||||||
|         MOORE_NEIGHBORHOOD |  | ||||||
|     } else { |  | ||||||
|         NEUMANN_NEIGHBORHOOD |  | ||||||
|     }; |  | ||||||
|     let max_neighbors = if is_moore { 8 } else { 4 }; |  | ||||||
| 
 | 
 | ||||||
|     let birth = generate_neighbor_counts(rng.gen_range(1..=max_neighbors), &mut rng, &[0]); |     let birth = generate_neighbor_counts(rng.gen_range(1..=max_neighbors), &mut rng, &[0]); | ||||||
|     let survive = generate_neighbor_counts(rng.gen_range(1..=max_neighbors), &mut rng, &[]); |     let survive = generate_neighbor_counts(rng.gen_range(1..=max_neighbors), &mut rng, &[]); | ||||||
|  | @ -76,16 +70,10 @@ fn generate_neighbor_counts(count: u8, rng: &mut ThreadRng, exclude: &[i32]) -> | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[must_use] | #[must_use] | ||||||
| pub fn generate_u8b3() -> Rules<u8, bool, 3> { | pub fn generate_u8b3() -> Rules<u8> { | ||||||
|     let mut rng = thread_rng(); |     let mut rng = thread_rng(); | ||||||
| 
 | 
 | ||||||
|     let kernel = match rng.gen_range(0..3) { |     let kernel = choose_neighborhood(&mut rng); | ||||||
|         0 => MOORE_NEIGHBORHOOD, |  | ||||||
|         1 => NEUMANN_NEIGHBORHOOD, |  | ||||||
|         2 => DIAGONALS_NEIGHBORHOOD, |  | ||||||
|         _ => panic!(), |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     let alive_threshold = u8::max(1, rng.gen()); |     let alive_threshold = u8::max(1, rng.gen()); | ||||||
| 
 | 
 | ||||||
|     let birth = generate_neighbor_counts(rng.gen_range(1..=9), &mut rng, &[0]); |     let birth = generate_neighbor_counts(rng.gen_range(1..=9), &mut rng, &[0]); | ||||||
|  | @ -113,3 +101,24 @@ pub fn generate_u8b3() -> Rules<u8, bool, 3> { | ||||||
|         }), |         }), | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | fn choose_neighborhood(rng: &mut ThreadRng) -> Kernel3x3 { | ||||||
|  |     match rng.gen_range(0..3) { | ||||||
|  |         0 => MOORE_NEIGHBORHOOD, | ||||||
|  |         1 => NEUMANN_NEIGHBORHOOD, | ||||||
|  |         2 => DIAGONALS_NEIGHBORHOOD, | ||||||
|  |         _ => unreachable!(), | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn count_max_neighbors<const SIZE: usize>(kernel: [[bool; SIZE]; SIZE]) -> u8 { | ||||||
|  |     let mut result = 0; | ||||||
|  |     for row in kernel { | ||||||
|  |         for cell in row { | ||||||
|  |             if cell { | ||||||
|  |                 result += 1; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     result | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -11,10 +11,10 @@ use servicepoint::{ | ||||||
| use std::num::Wrapping; | use std::num::Wrapping; | ||||||
| 
 | 
 | ||||||
| pub(crate) struct Simulation { | pub(crate) struct Simulation { | ||||||
|     pub(crate) left_pixels: Game<bool, bool, 3>, |     pub(crate) left_pixels: Game<bool>, | ||||||
|     pub(crate) right_pixels: Game<bool, bool, 3>, |     pub(crate) right_pixels: Game<bool>, | ||||||
|     pub(crate) left_luma: Game<u8, bool, 3>, |     pub(crate) left_luma: Game<u8>, | ||||||
|     pub(crate) right_luma: Game<u8, bool, 3>, |     pub(crate) right_luma: Game<u8>, | ||||||
|     split_pixel: usize, |     split_pixel: usize, | ||||||
|     pub(crate) split_speed: i32, |     pub(crate) split_speed: i32, | ||||||
|     iteration: Wrapping<u8>, |     iteration: Wrapping<u8>, | ||||||
|  | @ -64,7 +64,7 @@ impl Simulation { | ||||||
|         std::mem::swap(&mut self.left_pixels, &mut self.right_pixels); |         std::mem::swap(&mut self.left_pixels, &mut self.right_pixels); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn regenerate(pixels: &mut Game<bool, bool, 3>, luma: &mut Game<u8, bool, 3>) { |     fn regenerate(pixels: &mut Game<bool>, luma: &mut Game<u8>) { | ||||||
|         randomize(&mut pixels.field); |         randomize(&mut pixels.field); | ||||||
|         randomize(&mut luma.field); |         randomize(&mut luma.field); | ||||||
|         pixels.rules = generate_bb3(); |         pixels.rules = generate_bb3(); | ||||||
|  | @ -120,8 +120,8 @@ impl Simulation { | ||||||
|                 &self.right_luma.field |                 &self.right_luma.field | ||||||
|             }; |             }; | ||||||
|             for y in 0..luma.height() { |             for y in 0..luma.height() { | ||||||
|                 let set: u8 = left_or_right.get(x, y) / u8::MAX * u8::from(Brightness::MAX); |                 let set = left_or_right.get(x, y) as f32 / u8::MAX as f32 * u8::from(Brightness::MAX) as f32; | ||||||
|                 let set = Brightness::try_from(set).unwrap(); |                 let set = Brightness::try_from(set as u8).unwrap(); | ||||||
|                 luma.set(x, y, set); |                 luma.set(x, y, set); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -161,9 +161,9 @@ fn make_randomized<T: Value>(width: usize, height: usize) -> ValueGrid<T> | ||||||
| where | where | ||||||
|     Standard: Distribution<T>, |     Standard: Distribution<T>, | ||||||
| { | { | ||||||
|     let mut pixels = ValueGrid::new(width, height); |     let mut grid = ValueGrid::new(width, height); | ||||||
|     randomize(&mut pixels); |     randomize(&mut grid); | ||||||
|     pixels |     grid | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn randomize<T: Value>(field: &mut ValueGrid<T>) | fn randomize<T: Value>(field: &mut ValueGrid<T>) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue