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(
|
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
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 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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue