Multipath brute force
This commit is contained in:
parent
20073b88ce
commit
5d9926fba7
4 changed files with 165 additions and 52 deletions
|
|
@ -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
48
examples/brute_force2.rs
Normal 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());
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue