Add mutation for layouts.
This commit is contained in:
		
							parent
							
								
									0c1345053b
								
							
						
					
					
						commit
						be1d26ebd0
					
				
					 3 changed files with 132 additions and 11 deletions
				
			
		|  | @ -1,6 +1,6 @@ | |||
| use crate::common::visualize::{Color, Symbol, Visualization, Visualize}; | ||||
| use crate::prelude::*; | ||||
| use rand::Rng; | ||||
| use rand::{seq::SliceRandom, Rng}; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| 
 | ||||
| #[derive(Debug, Serialize, Deserialize)] | ||||
|  | @ -143,11 +143,115 @@ impl Layout<'_> { | |||
| 
 | ||||
|     /// Mutate existing layout, creating a valid layout
 | ||||
|     pub fn mutate<R: Rng + ?Sized>(&self, rng: &mut R) -> Self { | ||||
|         let s = self.clone(); | ||||
|         let mut s = self.clone(); | ||||
| 
 | ||||
|         #[allow(clippy::type_complexity)] | ||||
|         let r: &[(&dyn Fn(&mut Layout, &mut R) -> bool, _)] = &[ | ||||
|             (&Self::mutate_replace::<R>, 30), | ||||
|             (&Self::mutate_flip::<R>, 50), | ||||
|             (&Self::mutate_jiggle::<R>, 80), | ||||
|         ]; | ||||
| 
 | ||||
|         loop { | ||||
|             let p = r.choose_weighted(rng, |i| i.1).unwrap(); | ||||
| 
 | ||||
|             if p.0(&mut s, rng) && rng.gen_bool(0.4) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         s | ||||
|     } | ||||
| 
 | ||||
|     fn mutate_replace<R: Rng + ?Sized>(layout: &mut Layout, rng: &mut R) -> bool { | ||||
|         let i = rng.gen_range(0..layout.blocks.len()); | ||||
| 
 | ||||
|         let dir = rng.gen::<Direction>(); | ||||
| 
 | ||||
|         let b = &layout.problem.blocks[i]; | ||||
| 
 | ||||
|         let pos = match dir { | ||||
|             Direction::Up => Position::new( | ||||
|                 rng.gen_range(0..=(layout.problem.size.x - b.size.x)), | ||||
|                 rng.gen_range(0..=(layout.problem.size.y - b.size.y)), | ||||
|             ), | ||||
|             Direction::Right => Position::new( | ||||
|                 rng.gen_range((b.size.y - 1)..layout.problem.size.x), | ||||
|                 rng.gen_range(0..=(layout.problem.size.y - b.size.x)), | ||||
|             ), | ||||
|             Direction::Down => Position::new( | ||||
|                 rng.gen_range((b.size.x - 1)..layout.problem.size.x), | ||||
|                 rng.gen_range((b.size.y - 1)..layout.problem.size.y), | ||||
|             ), | ||||
|             Direction::Left => Position::new( | ||||
|                 rng.gen_range(0..=(layout.problem.size.x - b.size.y)), | ||||
|                 rng.gen_range((b.size.x - 1)..layout.problem.size.y), | ||||
|             ), | ||||
|         }; | ||||
| 
 | ||||
|         if layout.blocks.iter().enumerate().all(|(j, (p, d))| { | ||||
|             j == i || !Self::collision((&layout.problem.blocks[j], *p, *d), (b, pos, dir)) | ||||
|         }) { | ||||
|             layout.blocks[i] = (pos, dir); | ||||
|             true | ||||
|         } else { | ||||
|             false | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn mutate_flip<R: Rng + ?Sized>(layout: &mut Layout, rng: &mut R) -> bool { | ||||
|         let i = rng.gen_range(0..layout.blocks.len()); | ||||
|         let b = &mut layout.blocks[i]; | ||||
|         let block = &layout.problem.blocks[i]; | ||||
| 
 | ||||
|         b.0 = match &b.1 { | ||||
|             Direction::Up => b.0 + block.size - Position::new(1, 1), | ||||
|             Direction::Right => b.0 + Position::new(1 - block.size.y, block.size.x - 1), | ||||
|             Direction::Down => b.0 - block.size + Position::new(1, 1), | ||||
|             Direction::Left => b.0 + Position::new(block.size.y - 1, 1 - block.size.x), | ||||
|         }; | ||||
|         b.1 = b.1.reverse(); | ||||
| 
 | ||||
|         true | ||||
|     } | ||||
| 
 | ||||
|     fn mutate_jiggle<R: Rng + ?Sized>(layout: &mut Layout, rng: &mut R) -> bool { | ||||
|         let i = rng.gen_range(0..layout.blocks.len()); | ||||
|         let dir = rng.gen::<Direction>(); | ||||
|         // let step = [(1, 10), (2, 5), (3, 5)]
 | ||||
|         //     .choose_weighted(rng, |i| i.1)
 | ||||
|         //     .unwrap()
 | ||||
|         //     .0;
 | ||||
|         let step = 1; | ||||
| 
 | ||||
|         let b = &layout.problem.blocks[i]; | ||||
| 
 | ||||
|         let new_pos = layout.blocks[i].0.in_direction(&dir, step); | ||||
| 
 | ||||
|         let (npos, nsize) = Self::normalize_pos((b, new_pos, layout.blocks[i].1)); | ||||
| 
 | ||||
|         if npos.x < 0 | ||||
|             || npos.y < 0 | ||||
|             || npos.x + nsize.x > layout.problem.size.x | ||||
|             || npos.y + nsize.y > layout.problem.size.y | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         if layout.blocks.iter().enumerate().all(|(j, (p, d))| { | ||||
|             j == i | ||||
|                 || !Self::collision( | ||||
|                     (&layout.problem.blocks[j], *p, *d), | ||||
|                     (b, new_pos, layout.blocks[i].1), | ||||
|                 ) | ||||
|         }) { | ||||
|             layout.blocks[i].0 = new_pos; | ||||
|             true | ||||
|         } else { | ||||
|             false | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn collision( | ||||
|         block1: (&Block, Position, Direction), | ||||
|         block2: (&Block, Position, Direction), | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue