Refactoring layout.

This commit is contained in:
hal8174 2024-09-23 01:02:50 +02:00
parent 1c44d7aec1
commit e9377de01f
11 changed files with 407 additions and 320 deletions

View file

@ -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,
);
}
}