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

View file

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