Multipath brute force

This commit is contained in:
hal8174 2023-12-15 21:26:53 +01:00
parent 20073b88ce
commit 5d9926fba7
4 changed files with 165 additions and 52 deletions

View file

@ -11,14 +11,40 @@ fn main() {
b.add_path(
(Position::new(1, 0), Direction::Down),
(Position::new(4, 6), Direction::Up),
(Position::new(0, 0), Direction::Up),
);
b.set_blocked_range(0, 2, 5, 5, true);
b.add_path(
(Position::new(4, 0), Direction::Down),
(Position::new(1, 7), Direction::Up),
);
b.set_blocked_range(0, 2, 5, 4, true);
// b.set_blocked_range(2, 0, 2, 2, true);
let mut b = b.build();
while b.next_finish_state() {
println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
}
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
// b.next_state();
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
// b.next_state();
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
// b.next_state();
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
// b.next_state();
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
// b.next_state();
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
// b.next_state();
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
// b.next_state();
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
// b.next_state();
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
// b.next_state();
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
}

48
examples/brute_force2.rs Normal file
View file

@ -0,0 +1,48 @@
use factorio_blueprint::belt_finding::{brute_force::BruteforceBuilder, Direction, Position};
fn main() {
let mut b = BruteforceBuilder::new(20, 5);
b.add_path(
(Position::new(0, 0), Direction::Right),
(Position::new(19, 0), Direction::Right),
);
b.add_path(
(Position::new(0, 1), Direction::Right),
(Position::new(19, 1), Direction::Right),
);
b.add_path(
(Position::new(0, 2), Direction::Right),
(Position::new(19, 2), Direction::Right),
);
b.add_path(
(Position::new(0, 3), Direction::Right),
(Position::new(19, 3), Direction::Right),
);
b.add_path(
(Position::new(0, 4), Direction::Right),
(Position::new(19, 4), Direction::Right),
);
// b.add_path(
// (Position::new(0, 5), Direction::Right),
// (Position::new(19, 5), Direction::Right),
// );
b.set_blocked_range(4, 2, 16, 2, true);
b.set_blocked_range(7, 3, 10, 4, true);
// b.set_blocked_range(4, 0, 7, 2, true);
let mut b = b.build();
println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
while b.next_finish_state() {
println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
}
println!("{}\n{}", b.count(), b.solution_count());
}

View file

@ -1,5 +1,6 @@
use std::fmt::Display;
use clap::builder::PathBufValueParser;
use colored::Colorize;
use crate::misc::Map;
@ -13,7 +14,7 @@ pub struct BruteforceField {
underground_horizontal: bool,
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum PathField {
Belt {
pos: Position,
@ -85,17 +86,22 @@ impl BruteforceBuilder {
let mut b = Bruteforce {
map: self.map,
path: Vec::new(),
end: self.path[0][1],
end: Vec::new(),
current: 0,
solution_count: 0,
count: 0,
};
b.apply_path_field(PathField::Belt {
pos: self.path[0][0].0,
dir: self.path[0][0].1,
});
for [start, end] in self.path {
b.map.get_mut(start.0.x, start.0.y).blocked = true;
b.map.get_mut(end.0.x, end.0.y).blocked = true;
b.end.push(end);
b.map.get_mut(self.path[0][1].0.x, self.path[0][1].0.y);
b.path.push(vec![PathField::Belt {
pos: start.0,
dir: start.1,
}]);
}
b
}
@ -103,8 +109,9 @@ impl BruteforceBuilder {
pub struct Bruteforce {
map: Map<BruteforceField>,
path: Vec<PathField>,
end: (Position, Direction),
path: Vec<Vec<PathField>>,
end: Vec<(Position, Direction)>,
current: usize,
solution_count: u128,
count: u128,
}
@ -131,11 +138,11 @@ impl Bruteforce {
self.map.get_mut(end_pos.x, end_pos.y).blocked = true;
}
}
self.path.push(path_field);
self.path[self.current].push(path_field);
}
fn apply_path_field_remove(&mut self) {
match self.path.pop().unwrap() {
match self.path[self.current].pop().unwrap() {
PathField::Belt { pos, dir: _ } => self.map.get_mut(pos.x, pos.y).blocked = false,
PathField::Underground { pos, dir, len } => {
self.map.get_mut(pos.x, pos.y).blocked = false;
@ -157,15 +164,19 @@ impl Bruteforce {
}
}
fn check_finish(&self) -> bool {
match self.path.last().unwrap() {
fn check_finish_current(&self) -> bool {
match self.current_path().last().unwrap() {
PathField::Belt { pos, dir } => self
.pos_in_direction(pos, dir, 1)
.filter(|p| p == &self.end.0 && dir != &self.end.1.reverse())
.filter(|p| {
p == &self.end[self.current].0 && dir != &self.end[self.current].1.reverse()
})
.is_some(),
PathField::Underground { pos, dir, len } => self
.pos_in_direction(pos, dir, *len as usize + 1)
.filter(|p| p == &self.end.0 && dir != &self.end.1.reverse())
.filter(|p| {
p == &self.end[self.current].0 && dir != &self.end[self.current].1.reverse()
})
.is_some(),
}
}
@ -184,13 +195,26 @@ impl Bruteforce {
for l in len..MAX_UNDERGROUND_LENGTH {
if let Some(p) = self.pos_in_direction(pos, dir, l as usize) {
if !self.map.get(p.x, p.y).blocked {
self.apply_path_field_remove();
self.apply_path_field(PathField::Underground {
pos: *pos,
dir: *dir,
len: l,
});
return true;
if !(1..l)
.filter_map(|i| self.pos_in_direction(pos, dir, i as usize))
.all(|local_p| {
if dir.vertical() {
self.map.get(local_p.x, local_p.y).underground_vertical
} else {
self.map.get(local_p.x, local_p.y).underground_horizontal
}
})
{
self.apply_path_field_remove();
self.apply_path_field(PathField::Underground {
pos: *pos,
dir: *dir,
len: l,
});
return true;
} else {
return false;
}
}
}
}
@ -199,7 +223,7 @@ impl Bruteforce {
}
fn modify_remove(&mut self) -> bool {
if let Some([second_last, last]) = self.path.last_chunk().cloned() {
if let Some([second_last, last]) = self.current_path().last_chunk().cloned() {
match last {
PathField::Belt { pos, dir } => {
if second_last.dir() == &dir {
@ -235,17 +259,28 @@ impl Bruteforce {
self.apply_path_field_remove();
self.modify_remove()
} else if self.current > 0 {
self.current -= 1;
self.modify_remove()
} else {
false
}
}
fn current_path(&self) -> &Vec<PathField> {
self.path.get(self.current).unwrap()
}
pub fn next_state(&mut self) -> bool {
self.count += 1;
let (pos, dir) = self.path_field_end(self.path.last().unwrap());
// check finish
if self.current + 1 < self.path.len() && self.check_finish_current() {
self.current += 1;
}
// try add
let (pos, dir) = self.path_field_end(self.current_path().last().unwrap());
if let Some(next_pos) = self
.pos_in_direction(&pos, &dir, 1)
.filter(|p| !self.map.get(p.x, p.y).blocked)
@ -262,7 +297,7 @@ impl Bruteforce {
pub fn next_finish_state(&mut self) -> bool {
self.solution_count += 1;
while self.next_state() {
if self.check_finish() {
if self.current == self.path.len() - 1 && self.check_finish_current() {
return true;
}
}
@ -319,33 +354,37 @@ impl Display for Bruteforce {
let mut m: Map<Option<(usize, &str)>> = Map::new(self.map.width, self.map.height);
for p in &self.path {
match p {
PathField::Belt { pos, dir } => match dir {
Direction::Up => m.set(pos.x, pos.y, Some((0, ""))),
Direction::Right => m.set(pos.x, pos.y, Some((0, ""))),
Direction::Down => m.set(pos.x, pos.y, Some((0, ""))),
Direction::Left => m.set(pos.x, pos.y, Some((0, ""))),
},
PathField::Underground { pos, dir, len } => {
match dir {
Direction::Up => m.set(pos.x, pos.y, Some((0, ""))),
Direction::Right => m.set(pos.x, pos.y, Some((0, ""))),
Direction::Down => m.set(pos.x, pos.y, Some((0, ""))),
Direction::Left => m.set(pos.x, pos.y, Some((0, ""))),
};
let end_pos = self.pos_in_direction(pos, dir, *len as usize).unwrap();
match dir {
Direction::Up => m.set(end_pos.x, end_pos.y, Some((0, ""))),
Direction::Right => m.set(end_pos.x, end_pos.y, Some((0, ""))),
Direction::Down => m.set(end_pos.x, end_pos.y, Some((0, ""))),
Direction::Left => m.set(end_pos.x, end_pos.y, Some((0, ""))),
};
for (i, path) in self.path.iter().enumerate() {
for p in path {
match p {
PathField::Belt { pos, dir } => match dir {
Direction::Up => m.set(pos.x, pos.y, Some((i, ""))),
Direction::Right => m.set(pos.x, pos.y, Some((i, ""))),
Direction::Down => m.set(pos.x, pos.y, Some((i, ""))),
Direction::Left => m.set(pos.x, pos.y, Some((i, ""))),
},
PathField::Underground { pos, dir, len } => {
match dir {
Direction::Up => m.set(pos.x, pos.y, Some((i, ""))),
Direction::Right => m.set(pos.x, pos.y, Some((i, ""))),
Direction::Down => m.set(pos.x, pos.y, Some((i, ""))),
Direction::Left => m.set(pos.x, pos.y, Some((i, ""))),
};
let end_pos = self.pos_in_direction(pos, dir, *len as usize).unwrap();
match dir {
Direction::Up => m.set(end_pos.x, end_pos.y, Some((i, ""))),
Direction::Right => m.set(end_pos.x, end_pos.y, Some((i, ""))),
Direction::Down => m.set(end_pos.x, end_pos.y, Some((i, ""))),
Direction::Left => m.set(end_pos.x, end_pos.y, Some((i, ""))),
};
}
}
}
}
m.set(self.end.0.x, self.end.0.y, Some((0, "t")));
for (i, (end_pos, end_dir)) in self.end.iter().enumerate() {
m.set(end_pos.x, end_pos.y, Some((i, "t")));
}
// Print body

View file

@ -8,7 +8,7 @@ use std::io::Write;
pub mod brute_force;
#[derive(Clone, Copy, PartialEq, Eq)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Direction {
Up,
Right,