brute force round robin.
This commit is contained in:
parent
5d9926fba7
commit
9cb7e25149
4 changed files with 250 additions and 115 deletions
|
|
@ -5,6 +5,9 @@ edition = "2021"
|
|||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.21.5"
|
||||
clap = { version = "4.4.8", features = ["derive"] }
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ fn main() {
|
|||
(Position::new(1, 7), Direction::Up),
|
||||
);
|
||||
|
||||
b.set_blocked_range(0, 2, 5, 4, true);
|
||||
b.set_blocked_range(0, 2, 5, 5, true);
|
||||
// b.set_blocked_range(2, 0, 2, 2, true);
|
||||
|
||||
let mut b = b.build();
|
||||
|
|
@ -28,23 +28,22 @@ fn main() {
|
|||
println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
|
||||
}
|
||||
|
||||
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
|
||||
// println!(
|
||||
// "{}\n{}\n{}\n{}",
|
||||
// b.count(),
|
||||
// b.solution_count(),
|
||||
// b.modify_pointer(),
|
||||
// b
|
||||
// );
|
||||
|
||||
// for i in 0..20 {
|
||||
// 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);
|
||||
// println!(
|
||||
// "{}\n{}\n{}\n{}",
|
||||
// b.count(),
|
||||
// b.solution_count(),
|
||||
// b.modify_pointer(),
|
||||
// b
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,42 @@
|
|||
use factorio_blueprint::belt_finding::{brute_force::BruteforceBuilder, Direction, Position};
|
||||
|
||||
fn main() {
|
||||
let mut b = BruteforceBuilder::new(20, 5);
|
||||
let mut b = BruteforceBuilder::new(14, 6);
|
||||
|
||||
b.add_path(
|
||||
(Position::new(0, 0), Direction::Right),
|
||||
(Position::new(19, 0), Direction::Right),
|
||||
(Position::new(13, 0), Direction::Right),
|
||||
);
|
||||
|
||||
b.add_path(
|
||||
(Position::new(0, 1), Direction::Right),
|
||||
(Position::new(19, 1), Direction::Right),
|
||||
(Position::new(13, 1), Direction::Right),
|
||||
);
|
||||
|
||||
b.add_path(
|
||||
(Position::new(0, 2), Direction::Right),
|
||||
(Position::new(19, 2), Direction::Right),
|
||||
(Position::new(13, 2), Direction::Right),
|
||||
);
|
||||
|
||||
b.add_path(
|
||||
(Position::new(0, 3), Direction::Right),
|
||||
(Position::new(19, 3), Direction::Right),
|
||||
(Position::new(13, 3), Direction::Right),
|
||||
);
|
||||
|
||||
b.add_path(
|
||||
(Position::new(0, 4), Direction::Right),
|
||||
(Position::new(19, 4), Direction::Right),
|
||||
(Position::new(13, 4), Direction::Right),
|
||||
);
|
||||
|
||||
// b.add_path(
|
||||
// (Position::new(0, 5), Direction::Right),
|
||||
// (Position::new(19, 5), Direction::Right),
|
||||
// );
|
||||
b.add_path(
|
||||
(Position::new(0, 5), Direction::Right),
|
||||
(Position::new(13, 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(7, 2, 10, 2, true);
|
||||
// b.set_blocked_range(7, 3, 10, 4, true);
|
||||
|
||||
// b.set_blocked_range(4, 0, 7, 2, true);
|
||||
b.set_blocked_range(3, 2, 10, 3, true);
|
||||
|
||||
let mut b = b.build();
|
||||
|
||||
|
|
@ -45,4 +45,10 @@ fn main() {
|
|||
println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
|
||||
}
|
||||
println!("{}\n{}", b.count(), b.solution_count());
|
||||
|
||||
// println!("{}\n{}", b.count(), b);
|
||||
|
||||
// while b.next_state() {
|
||||
// println!("{}\n{}", b.count(), b);
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,45 +85,66 @@ impl BruteforceBuilder {
|
|||
pub fn build(self) -> Bruteforce {
|
||||
let mut b = Bruteforce {
|
||||
map: self.map,
|
||||
path: Vec::new(),
|
||||
end: Vec::new(),
|
||||
current: 0,
|
||||
problems: Vec::new(),
|
||||
pointer_stack: vec![0],
|
||||
solution_count: 0,
|
||||
count: 0,
|
||||
depth: 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.path.push(vec![PathField::Belt {
|
||||
b.problems.push(Problem {
|
||||
path: vec![PathField::Belt {
|
||||
pos: start.0,
|
||||
dir: start.1,
|
||||
}]);
|
||||
}],
|
||||
end_pos: end.0,
|
||||
end_dir: end.1,
|
||||
finished: false,
|
||||
})
|
||||
}
|
||||
|
||||
b
|
||||
}
|
||||
}
|
||||
|
||||
struct Problem {
|
||||
path: Vec<PathField>,
|
||||
end_pos: Position,
|
||||
end_dir: Direction,
|
||||
finished: bool,
|
||||
}
|
||||
|
||||
pub struct Bruteforce {
|
||||
map: Map<BruteforceField>,
|
||||
path: Vec<Vec<PathField>>,
|
||||
end: Vec<(Position, Direction)>,
|
||||
current: usize,
|
||||
problems: Vec<Problem>,
|
||||
pointer_stack: Vec<usize>,
|
||||
depth: usize,
|
||||
solution_count: u128,
|
||||
count: u128,
|
||||
}
|
||||
|
||||
impl Bruteforce {
|
||||
pub fn apply_path_field(&mut self, path_field: PathField) {
|
||||
pub fn modify_pointer(&self) -> usize {
|
||||
self.pointer_stack
|
||||
.get(self.pointer_stack.len() - 2)
|
||||
.copied()
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
fn add_pointer(&self) -> usize {
|
||||
self.pointer_stack.last().copied().unwrap_or(0)
|
||||
}
|
||||
|
||||
fn internal_apply_path_field(&mut self, i: usize, path_field: PathField) {
|
||||
match &path_field {
|
||||
PathField::Belt { pos, dir: _ } => self.map.get_mut(pos.x, pos.y).blocked = true,
|
||||
PathField::Underground { pos, dir, len } => {
|
||||
self.map.get_mut(pos.x, pos.y).blocked = true;
|
||||
|
||||
for i in 1..*len {
|
||||
for i in 0..=*len {
|
||||
let mid_pos = self.pos_in_direction(pos, dir, i.into()).unwrap();
|
||||
if dir.vertical() {
|
||||
self.map.get_mut(mid_pos.x, mid_pos.y).underground_vertical = true;
|
||||
|
|
@ -138,16 +159,16 @@ impl Bruteforce {
|
|||
self.map.get_mut(end_pos.x, end_pos.y).blocked = true;
|
||||
}
|
||||
}
|
||||
self.path[self.current].push(path_field);
|
||||
self.problems[i].path.push(path_field);
|
||||
}
|
||||
|
||||
fn apply_path_field_remove(&mut self) {
|
||||
match self.path[self.current].pop().unwrap() {
|
||||
fn internal_remove_path_field(&mut self, i: usize) {
|
||||
match self.problems[i].path.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;
|
||||
|
||||
for i in 1..len {
|
||||
for i in 0..=len {
|
||||
let mid_pos = self.pos_in_direction(&pos, &dir, i.into()).unwrap();
|
||||
if dir.vertical() {
|
||||
self.map.get_mut(mid_pos.x, mid_pos.y).underground_vertical = false;
|
||||
|
|
@ -164,18 +185,61 @@ impl Bruteforce {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_finish_current(&self) -> bool {
|
||||
match self.current_path().last().unwrap() {
|
||||
fn apply_path_field(&mut self, path_field: PathField) {
|
||||
self.internal_apply_path_field(self.add_pointer(), path_field);
|
||||
|
||||
// set finished
|
||||
let i = self.add_pointer();
|
||||
// dbg!(i, self.check_finish(i));
|
||||
self.problems[i].finished = self.check_finish(i);
|
||||
|
||||
// advance pointer
|
||||
|
||||
let current_pointer = self.add_pointer();
|
||||
let mut pointer = current_pointer;
|
||||
|
||||
for i in 1..self.problems.len() {
|
||||
if !self.problems[(current_pointer + i) % self.problems.len()].finished {
|
||||
pointer = (current_pointer + i) % self.problems.len();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self.pointer_stack.push(pointer);
|
||||
}
|
||||
|
||||
fn remove_path_field(&mut self) {
|
||||
self.internal_remove_path_field(self.modify_pointer());
|
||||
|
||||
// remove finish
|
||||
let i = self.modify_pointer();
|
||||
self.problems[i].finished = false;
|
||||
|
||||
// restore pointer
|
||||
self.pointer_stack.pop();
|
||||
}
|
||||
|
||||
fn modify_path_field(&mut self, path_field: PathField) {
|
||||
self.internal_remove_path_field(self.modify_pointer());
|
||||
self.internal_apply_path_field(self.modify_pointer(), path_field);
|
||||
|
||||
// set finished
|
||||
let i = self.modify_pointer();
|
||||
self.problems[i].finished = self.check_finish(i);
|
||||
}
|
||||
|
||||
fn check_finish(&self, i: usize) -> bool {
|
||||
match self.problems[i].path.last().unwrap() {
|
||||
PathField::Belt { pos, dir } => self
|
||||
.pos_in_direction(pos, dir, 1)
|
||||
.filter(|p| {
|
||||
p == &self.end[self.current].0 && dir != &self.end[self.current].1.reverse()
|
||||
p == &self.problems[i].end_pos && dir != &self.problems[i].end_dir.reverse()
|
||||
})
|
||||
.is_some(),
|
||||
PathField::Underground { pos, dir, len } => self
|
||||
.pos_in_direction(pos, dir, *len as usize + 1)
|
||||
.filter(|p| {
|
||||
p == &self.end[self.current].0 && dir != &self.end[self.current].1.reverse()
|
||||
p == &self.problems[i].end_pos && dir != &self.problems[i].end_dir.reverse()
|
||||
})
|
||||
.is_some(),
|
||||
}
|
||||
|
|
@ -192,43 +256,92 @@ impl Bruteforce {
|
|||
}
|
||||
|
||||
fn modify_underground(&mut self, pos: &Position, dir: &Direction, len: u8) -> bool {
|
||||
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 {
|
||||
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 {
|
||||
if len >= MAX_UNDERGROUND_LENGTH {
|
||||
return false;
|
||||
}
|
||||
|
||||
if len == 2
|
||||
&& match dir.vertical() {
|
||||
true => self.map.get(pos.x, pos.y).underground_vertical,
|
||||
false => self.map.get(pos.x, pos.y).underground_horizontal,
|
||||
}
|
||||
}
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
false
|
||||
let end_pos = match self.pos_in_direction(pos, dir, len as usize) {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if match dir.vertical() {
|
||||
true => self.map.get(end_pos.x, end_pos.y).underground_vertical,
|
||||
false => self.map.get(end_pos.x, end_pos.y).underground_horizontal,
|
||||
} {
|
||||
return false;
|
||||
}
|
||||
|
||||
if !self.map.get(end_pos.x, end_pos.y).blocked {
|
||||
self.modify_path_field(PathField::Underground {
|
||||
pos: *pos,
|
||||
dir: *dir,
|
||||
len,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
self.modify_underground(pos, dir, len + 1)
|
||||
}
|
||||
|
||||
// fn modify_underground(&mut self, pos: &Position, dir: &Direction, len: u8) -> bool {
|
||||
// dbg!(pos, dir, len);
|
||||
|
||||
// if match dir.vertical() {
|
||||
// true => self.map.get(pos.x, pos.y).underground_vertical,
|
||||
// false => self.map.get(pos.x, pos.y).underground_horizontal,
|
||||
// } {
|
||||
// return false;
|
||||
// }
|
||||
// for l in len..MAX_UNDERGROUND_LENGTH {
|
||||
// if let Some(p) = self.pos_in_direction(pos, dir, l as usize) {
|
||||
// dbg!(l, &p);
|
||||
// if !self.map.get(p.x, p.y).blocked {
|
||||
// if !(1..l)
|
||||
// .filter_map(|i| self.pos_in_direction(pos, dir, i as usize))
|
||||
// .any(|local_pos| !match dir.vertical() {
|
||||
// true => self.map.get(local_pos.x, local_pos.y).underground_vertical,
|
||||
// false => {
|
||||
// self.map
|
||||
// .get(local_pos.x, local_pos.y)
|
||||
// .underground_horizontal
|
||||
// }
|
||||
// })
|
||||
// {
|
||||
// dbg!(true);
|
||||
// self.modify_path_field(PathField::Underground {
|
||||
// pos: *pos,
|
||||
// dir: *dir,
|
||||
// len: l,
|
||||
// });
|
||||
// return true;
|
||||
// } else {
|
||||
// return false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// false
|
||||
// }
|
||||
|
||||
fn modify_remove(&mut self) -> bool {
|
||||
if let Some([second_last, last]) = self.current_path().last_chunk().cloned() {
|
||||
if let Some([second_last, last]) = self.modify_path().last_chunk().cloned() {
|
||||
match last {
|
||||
PathField::Belt { pos, dir } => {
|
||||
if second_last.dir() == &dir {
|
||||
self.apply_path_field_remove();
|
||||
self.apply_path_field(PathField::Belt {
|
||||
self.modify_path_field(PathField::Belt {
|
||||
pos,
|
||||
dir: second_last.dir().clockwise(),
|
||||
});
|
||||
|
|
@ -236,8 +349,7 @@ impl Bruteforce {
|
|||
}
|
||||
|
||||
if second_last.dir().clockwise() == dir {
|
||||
self.apply_path_field_remove();
|
||||
self.apply_path_field(PathField::Belt {
|
||||
self.modify_path_field(PathField::Belt {
|
||||
pos,
|
||||
dir: second_last.dir().counter_clockwise(),
|
||||
});
|
||||
|
|
@ -245,7 +357,7 @@ impl Bruteforce {
|
|||
}
|
||||
|
||||
if second_last.dir().counter_clockwise() == dir
|
||||
&& self.modify_underground(&pos, second_last.dir(), 1)
|
||||
&& self.modify_underground(&pos, second_last.dir(), 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -257,47 +369,57 @@ impl Bruteforce {
|
|||
}
|
||||
}
|
||||
|
||||
self.apply_path_field_remove();
|
||||
self.modify_remove()
|
||||
} else if self.current > 0 {
|
||||
self.current -= 1;
|
||||
self.remove_path_field();
|
||||
self.modify_remove()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn current_path(&self) -> &Vec<PathField> {
|
||||
self.path.get(self.current).unwrap()
|
||||
fn modify_path(&self) -> &Vec<PathField> {
|
||||
&self.problems[self.modify_pointer()].path
|
||||
}
|
||||
|
||||
fn add_path(&self) -> &Vec<PathField> {
|
||||
&self.problems[self.add_pointer()].path
|
||||
}
|
||||
|
||||
// fn modify_path_mut(&mut self) -> &mut Vec<PathField> {
|
||||
// let i = self.modify_pointer();
|
||||
// &mut self.problems[i].path
|
||||
// }
|
||||
|
||||
// Add an Path elemeent
|
||||
fn add(&mut self) -> bool {
|
||||
let (pos, dir) = self.path_field_end(self.add_path().last().unwrap());
|
||||
|
||||
if let Some(p) = self.pos_in_direction(&pos, &dir, 1) {
|
||||
if !self.map.get(p.x, p.y).blocked {
|
||||
self.apply_path_field(PathField::Belt { pos: p, dir });
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn next_state(&mut self) -> bool {
|
||||
self.count += 1;
|
||||
|
||||
// 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)
|
||||
{
|
||||
self.apply_path_field(PathField::Belt { pos: next_pos, dir });
|
||||
if self.add() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// modify and remove
|
||||
|
||||
self.modify_remove()
|
||||
}
|
||||
|
||||
pub fn next_finish_state(&mut self) -> bool {
|
||||
self.solution_count += 1;
|
||||
while self.next_state() {
|
||||
if self.current == self.path.len() - 1 && self.check_finish_current() {
|
||||
// if self.count % 1000000 == 0 {
|
||||
// println!("{}\n{}", self.count, self);
|
||||
// }
|
||||
if self.problems.iter().all(|p| p.finished) {
|
||||
self.solution_count += 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -354,8 +476,13 @@ impl Display for Bruteforce {
|
|||
|
||||
let mut m: Map<Option<(usize, &str)>> = Map::new(self.map.width, self.map.height);
|
||||
|
||||
for (i, path) in self.path.iter().enumerate() {
|
||||
for p in path {
|
||||
for (i, problem) in self.problems.iter().enumerate() {
|
||||
if problem.finished {
|
||||
m.set(problem.end_pos.x, problem.end_pos.y, Some((i, "T")));
|
||||
} else {
|
||||
m.set(problem.end_pos.x, problem.end_pos.y, Some((i, "t")));
|
||||
}
|
||||
for p in &problem.path {
|
||||
match p {
|
||||
PathField::Belt { pos, dir } => match dir {
|
||||
Direction::Up => m.set(pos.x, pos.y, Some((i, "↑"))),
|
||||
|
|
@ -382,10 +509,6 @@ impl Display for Bruteforce {
|
|||
}
|
||||
}
|
||||
|
||||
for (i, (end_pos, end_dir)) in self.end.iter().enumerate() {
|
||||
m.set(end_pos.x, end_pos.y, Some((i, "t")));
|
||||
}
|
||||
|
||||
// Print body
|
||||
|
||||
for y in 0..self.map.height {
|
||||
|
|
@ -396,6 +519,10 @@ impl Display for Bruteforce {
|
|||
write!(f, "{}", c.color(COLORS[*i]))?;
|
||||
} else if self.map.get(x, y).blocked {
|
||||
write!(f, "#")?;
|
||||
} else if self.map.get(x, y).underground_horizontal {
|
||||
write!(f, "_")?;
|
||||
} else if self.map.get(x, y).underground_vertical {
|
||||
write!(f, "|")?;
|
||||
} else if x % 8 == 0 || y % 8 == 0 {
|
||||
write!(f, "∙")?;
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue