Refactoring layout.
This commit is contained in:
		
							parent
							
								
									1c44d7aec1
								
							
						
					
					
						commit
						e9377de01f
					
				
					 11 changed files with 407 additions and 320 deletions
				
			
		|  | @ -1,12 +1,11 @@ | |||
| use std::sync::atomic::AtomicU32; | ||||
| use std::time::Instant; | ||||
| 
 | ||||
| use crate::belt_finding::common::PathField; | ||||
| use crate::belt_finding::conflict_avoidance::ConflictAvoidance; | ||||
| use crate::common::visualize::{image_grid, Color, Symbol, Visualization, Visualize}; | ||||
| use crate::prelude::*; | ||||
| use rand::{seq::SliceRandom, Rng}; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use std::sync::atomic::AtomicU32; | ||||
| use std::time::Instant; | ||||
| 
 | ||||
| static OUTFILEINDEX: AtomicU32 = AtomicU32::new(0); | ||||
| 
 | ||||
|  | @ -152,7 +151,7 @@ pub fn valid_path_layout<'a, R: Rng + ?Sized>( | |||
| } | ||||
| 
 | ||||
| #[derive(Debug, Serialize, Deserialize)] | ||||
| pub(crate) struct Block { | ||||
| pub(crate) struct MacroBlock { | ||||
|     pub(crate) size: Position, | ||||
|     pub(crate) input: Vec<Interface>, | ||||
|     pub(crate) output: Vec<Interface>, | ||||
|  | @ -175,7 +174,7 @@ pub(crate) struct Connection { | |||
| #[derive(Debug, Serialize, Deserialize)] | ||||
| pub struct Problem { | ||||
|     pub(crate) size: Position, | ||||
|     pub(crate) blocks: Vec<Block>, | ||||
|     pub(crate) blocks: Vec<MacroBlock>, | ||||
|     pub(crate) connections: Vec<Connection>, | ||||
| } | ||||
| 
 | ||||
|  | @ -185,7 +184,7 @@ pub struct Problem { | |||
| #[derive(Debug, Clone)] | ||||
| pub struct Layout<'a> { | ||||
|     pub(crate) problem: &'a Problem, | ||||
|     pub(crate) blocks: Vec<(Position, Direction)>, | ||||
|     pub(crate) blocks: Vec<Block>, | ||||
| } | ||||
| 
 | ||||
| pub struct PathLayout<'a> { | ||||
|  | @ -331,7 +330,7 @@ impl Layout<'_> { | |||
| 
 | ||||
|     fn place_block<R: Rng + ?Sized>( | ||||
|         problem: &'_ Problem, | ||||
|         blocks: &mut Vec<(Position, Direction)>, | ||||
|         blocks: &mut Vec<Block>, | ||||
|         rng: &'_ mut R, | ||||
|     ) -> bool { | ||||
|         if problem.blocks.len() == blocks.len() { | ||||
|  | @ -361,12 +360,15 @@ impl Layout<'_> { | |||
|                 ), | ||||
|             }; | ||||
| 
 | ||||
|             let current = Block::new(pos, dir, problem.blocks[blocks.len()].size); | ||||
| 
 | ||||
|             let current_aabb = current.get_aabb(); | ||||
| 
 | ||||
|             if blocks | ||||
|                 .iter() | ||||
|                 .enumerate() | ||||
|                 .all(|(i, (p, d))| !Self::collision((&problem.blocks[i], *p, *d), (b, pos, dir))) | ||||
|                 .all(|b| !AABB::collision(b.get_aabb(), current_aabb)) | ||||
|             { | ||||
|                 blocks.push((pos, dir)); | ||||
|                 blocks.push(current); | ||||
| 
 | ||||
|                 if Self::place_block(problem, blocks, rng) { | ||||
|                     return true; | ||||
|  | @ -427,10 +429,16 @@ impl Layout<'_> { | |||
|             ), | ||||
|         }; | ||||
| 
 | ||||
|         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); | ||||
|         let current = Block::new(pos, dir, b.size); | ||||
|         let current_aabb = current.get_aabb(); | ||||
| 
 | ||||
|         if layout | ||||
|             .blocks | ||||
|             .iter() | ||||
|             .enumerate() | ||||
|             .all(|(j, b)| j == i || !AABB::collision(b.get_aabb(), current_aabb)) | ||||
|         { | ||||
|             layout.blocks[i] = current; | ||||
|             true | ||||
|         } else { | ||||
|             false | ||||
|  | @ -442,13 +450,15 @@ impl Layout<'_> { | |||
|         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), | ||||
|         let new_pos = match b.dir() { | ||||
|             Direction::Up => b.pos() + block.size - Position::new(1, 1), | ||||
|             Direction::Right => b.pos() + Position::new(1 - block.size.y, block.size.x - 1), | ||||
|             Direction::Down => b.pos() - block.size + Position::new(1, 1), | ||||
|             Direction::Left => b.pos() + Position::new(block.size.y - 1, 1 - block.size.x), | ||||
|         }; | ||||
|         b.1 = b.1.reverse(); | ||||
|         let new_dir = b.dir().reverse(); | ||||
| 
 | ||||
|         *b = Block::new(new_pos, new_dir, b.size()); | ||||
| 
 | ||||
|         true | ||||
|     } | ||||
|  | @ -456,125 +466,44 @@ impl Layout<'_> { | |||
|     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 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 b = &layout.blocks[i]; | ||||
| 
 | ||||
|         let new_pos = layout.blocks[i].0.in_direction(&dir, step); | ||||
|         let current = Block::new(b.pos().in_direction(&dir, step), b.dir(), b.size()); | ||||
|         let current_aabb = current.get_aabb(); | ||||
| 
 | ||||
|         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 | ||||
|         if current_aabb.min().x < 0 | ||||
|             || current_aabb.min().y < 0 | ||||
|             || current_aabb.max().x >= layout.problem.size.x | ||||
|             || current_aabb.max().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; | ||||
|         if layout | ||||
|             .blocks | ||||
|             .iter() | ||||
|             .enumerate() | ||||
|             .all(|(j, b)| j == i || !AABB::collision(b.get_aabb(), current_aabb)) | ||||
|         { | ||||
|             layout.blocks[i] = current; | ||||
|             true | ||||
|         } else { | ||||
|             false | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn collision( | ||||
|         block1: (&Block, Position, Direction), | ||||
|         block2: (&Block, Position, Direction), | ||||
|     ) -> bool { | ||||
|         let (npos1, nsize1) = Self::normalize_pos(block1); | ||||
|         let (npos2, nsize2) = Self::normalize_pos(block2); | ||||
| 
 | ||||
|         npos1.x < npos2.x + nsize2.x | ||||
|             && npos1.x + nsize1.x > npos2.x | ||||
|             && npos1.y < npos2.y + nsize2.y | ||||
|             && npos1.y + nsize1.y > npos2.y | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn normalize_pos(block: (&Block, Position, Direction)) -> (Position, Position) { | ||||
|         let npos = match block.2 { | ||||
|             Direction::Up => block.1, | ||||
|             Direction::Right => block.1.in_direction(&Direction::Left, block.0.size.y - 1), | ||||
|             Direction::Down => block.1 - (block.0.size - Position::new(1, 1)), | ||||
|             Direction::Left => block.1.in_direction(&Direction::Up, block.0.size.x - 1), | ||||
|         }; | ||||
|         let nsize = match block.2 { | ||||
|             Direction::Up | Direction::Down => block.0.size, | ||||
|             Direction::Right | Direction::Left => Position { | ||||
|                 x: block.0.size.y, | ||||
|                 y: block.0.size.x, | ||||
|             }, | ||||
|         }; | ||||
| 
 | ||||
|         (npos, nsize) | ||||
|     } | ||||
| 
 | ||||
|     pub fn score(&self) -> i32 { | ||||
|         let mut sum = 0; | ||||
| 
 | ||||
|         for c in &self.problem.connections { | ||||
|             let startpos = Self::transform( | ||||
|                 self.blocks[c.startblock].0, | ||||
|                 self.blocks[c.startblock].1, | ||||
|                 self.problem.blocks[c.startblock].output[c.startpoint].offset, | ||||
|             ); | ||||
|             let endpos = Self::transform( | ||||
|                 self.blocks[c.endblock].0, | ||||
|                 self.blocks[c.endblock].1, | ||||
|                 self.problem.blocks[c.endblock].input[c.endpoint].offset, | ||||
|             ); | ||||
| 
 | ||||
|             sum += (startpos.x - endpos.x).abs() + (startpos.y - endpos.y).abs(); | ||||
|         } | ||||
| 
 | ||||
|         sum | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn transform(pos: Position, dir: Direction, offset: Position) -> Position { | ||||
|         match dir { | ||||
|             Direction::Up => pos + offset, | ||||
|             Direction::Right => pos + Position::new(-offset.y, offset.x), | ||||
|             Direction::Down => pos - offset, | ||||
|             Direction::Left => pos + Position::new(offset.y, -offset.x), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub(crate) fn rotate(dir: Direction, rot: Direction) -> Direction { | ||||
|         match (rot, dir) { | ||||
|             (Direction::Up, _) => dir, | ||||
|             (Direction::Right, Direction::Up) => Direction::Right, | ||||
|             (Direction::Right, Direction::Right) => Direction::Down, | ||||
|             (Direction::Right, Direction::Down) => Direction::Left, | ||||
|             (Direction::Right, Direction::Left) => Direction::Up, | ||||
|             (Direction::Down, Direction::Up) => Direction::Down, | ||||
|             (Direction::Down, Direction::Right) => Direction::Left, | ||||
|             (Direction::Down, Direction::Down) => Direction::Up, | ||||
|             (Direction::Down, Direction::Left) => Direction::Right, | ||||
|             (Direction::Left, Direction::Up) => Direction::Left, | ||||
|             (Direction::Left, Direction::Right) => Direction::Up, | ||||
|             (Direction::Left, Direction::Down) => Direction::Right, | ||||
|             (Direction::Left, Direction::Left) => Direction::Down, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<'a> Visualize for Layout<'a> { | ||||
|     fn visualize(&self) -> Visualization { | ||||
|         let mut v = Visualization::new(self.problem.size); | ||||
| 
 | ||||
|         for (i, ((p, d), b)) in self | ||||
|         for (i, (b, mb)) in self | ||||
|             .blocks | ||||
|             .iter() | ||||
|             .zip(self.problem.blocks.iter()) | ||||
|  | @ -582,28 +511,34 @@ impl<'a> Visualize for Layout<'a> { | |||
|         { | ||||
|             let c = Color::index(i); | ||||
| 
 | ||||
|             let (npos, nsize) = Self::normalize_pos((b, *p, *d)); | ||||
|             let aabb = b.get_aabb(); | ||||
| 
 | ||||
|             for x in npos.x..(npos.x + nsize.x) { | ||||
|                 for y in npos.y..(npos.y + nsize.y) { | ||||
|             for x in aabb.min().x..=aabb.max().x { | ||||
|                 for y in aabb.min().y..=aabb.max().y { | ||||
|                     v.add_symbol(Position::new(x, y), Symbol::Block, Some(c), None); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             let pos = Self::transform(*p, *d, Position::new(0, 0)); | ||||
|             v.add_symbol(b.pos(), Symbol::Char('X'), Some(c), None); | ||||
| 
 | ||||
|             v.add_symbol(pos, Symbol::Char('X'), Some(c), None); | ||||
|             let transform = b.block_to_world(); | ||||
| 
 | ||||
|             for input in &b.input { | ||||
|                 let pos = Self::transform(*p, *d, input.offset); | ||||
| 
 | ||||
|                 v.add_symbol(pos, Symbol::Char('i'), Some(c), None); | ||||
|             for input in &mb.input { | ||||
|                 v.add_symbol( | ||||
|                     input.offset.transform(transform), | ||||
|                     Symbol::Char('i'), | ||||
|                     Some(c), | ||||
|                     None, | ||||
|                 ); | ||||
|             } | ||||
| 
 | ||||
|             for output in &b.output { | ||||
|                 let pos = Self::transform(*p, *d, output.offset); | ||||
| 
 | ||||
|                 v.add_symbol(pos, Symbol::Char('o'), Some(c), None); | ||||
|             for output in &mb.output { | ||||
|                 v.add_symbol( | ||||
|                     output.offset.transform(transform), | ||||
|                     Symbol::Char('o'), | ||||
|                     Some(c), | ||||
|                     None, | ||||
|                 ); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue