brute force round robin.

This commit is contained in:
hal8174 2023-12-31 15:54:54 +01:00
parent 5d9926fba7
commit 9cb7e25149
4 changed files with 250 additions and 115 deletions

View file

@ -5,6 +5,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[profile.release]
debug = true
[dependencies] [dependencies]
base64 = "0.21.5" base64 = "0.21.5"
clap = { version = "4.4.8", features = ["derive"] } clap = { version = "4.4.8", features = ["derive"] }

View file

@ -19,7 +19,7 @@ fn main() {
(Position::new(1, 7), Direction::Up), (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); // b.set_blocked_range(2, 0, 2, 2, true);
let mut b = b.build(); 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{}", b.count(), b.solution_count(), b); // println!(
// b.next_state(); // "{}\n{}\n{}\n{}",
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b); // b.count(),
// b.next_state(); // b.solution_count(),
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b); // b.modify_pointer(),
// b.next_state(); // b
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b); // );
// b.next_state();
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b); // for i in 0..20 {
// b.next_state(); // b.next_state();
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b); // println!(
// b.next_state(); // "{}\n{}\n{}\n{}",
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b); // b.count(),
// b.next_state(); // b.solution_count(),
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b); // b.modify_pointer(),
// b.next_state(); // b
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b); // );
// b.next_state(); // }
// println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
} }

View file

@ -1,42 +1,42 @@
use factorio_blueprint::belt_finding::{brute_force::BruteforceBuilder, Direction, Position}; use factorio_blueprint::belt_finding::{brute_force::BruteforceBuilder, Direction, Position};
fn main() { fn main() {
let mut b = BruteforceBuilder::new(20, 5); let mut b = BruteforceBuilder::new(14, 6);
b.add_path( b.add_path(
(Position::new(0, 0), Direction::Right), (Position::new(0, 0), Direction::Right),
(Position::new(19, 0), Direction::Right), (Position::new(13, 0), Direction::Right),
); );
b.add_path( b.add_path(
(Position::new(0, 1), Direction::Right), (Position::new(0, 1), Direction::Right),
(Position::new(19, 1), Direction::Right), (Position::new(13, 1), Direction::Right),
); );
b.add_path( b.add_path(
(Position::new(0, 2), Direction::Right), (Position::new(0, 2), Direction::Right),
(Position::new(19, 2), Direction::Right), (Position::new(13, 2), Direction::Right),
); );
b.add_path( b.add_path(
(Position::new(0, 3), Direction::Right), (Position::new(0, 3), Direction::Right),
(Position::new(19, 3), Direction::Right), (Position::new(13, 3), Direction::Right),
); );
b.add_path( b.add_path(
(Position::new(0, 4), Direction::Right), (Position::new(0, 4), Direction::Right),
(Position::new(19, 4), Direction::Right), (Position::new(13, 4), Direction::Right),
); );
// b.add_path( b.add_path(
// (Position::new(0, 5), Direction::Right), (Position::new(0, 5), Direction::Right),
// (Position::new(19, 5), Direction::Right), (Position::new(13, 5), Direction::Right),
// ); );
b.set_blocked_range(4, 2, 16, 2, true); // b.set_blocked_range(7, 2, 10, 2, true);
b.set_blocked_range(7, 3, 10, 4, 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(); let mut b = b.build();
@ -45,4 +45,10 @@ fn main() {
println!("{}\n{}\n{}", b.count(), b.solution_count(), b); println!("{}\n{}\n{}", b.count(), b.solution_count(), b);
} }
println!("{}\n{}", b.count(), b.solution_count()); println!("{}\n{}", b.count(), b.solution_count());
// println!("{}\n{}", b.count(), b);
// while b.next_state() {
// println!("{}\n{}", b.count(), b);
// }
} }

View file

@ -85,45 +85,66 @@ impl BruteforceBuilder {
pub fn build(self) -> Bruteforce { pub fn build(self) -> Bruteforce {
let mut b = Bruteforce { let mut b = Bruteforce {
map: self.map, map: self.map,
path: Vec::new(), problems: Vec::new(),
end: Vec::new(), pointer_stack: vec![0],
current: 0,
solution_count: 0, solution_count: 0,
count: 0, count: 0,
depth: 1,
}; };
for [start, end] in self.path { for [start, end] in self.path {
b.map.get_mut(start.0.x, start.0.y).blocked = true; 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.map.get_mut(end.0.x, end.0.y).blocked = true;
b.end.push(end); b.problems.push(Problem {
path: vec![PathField::Belt {
b.path.push(vec![PathField::Belt { pos: start.0,
pos: start.0, dir: start.1,
dir: start.1, }],
}]); end_pos: end.0,
end_dir: end.1,
finished: false,
})
} }
b b
} }
} }
struct Problem {
path: Vec<PathField>,
end_pos: Position,
end_dir: Direction,
finished: bool,
}
pub struct Bruteforce { pub struct Bruteforce {
map: Map<BruteforceField>, map: Map<BruteforceField>,
path: Vec<Vec<PathField>>, problems: Vec<Problem>,
end: Vec<(Position, Direction)>, pointer_stack: Vec<usize>,
current: usize, depth: usize,
solution_count: u128, solution_count: u128,
count: u128, count: u128,
} }
impl Bruteforce { 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 { match &path_field {
PathField::Belt { pos, dir: _ } => self.map.get_mut(pos.x, pos.y).blocked = true, PathField::Belt { pos, dir: _ } => self.map.get_mut(pos.x, pos.y).blocked = true,
PathField::Underground { pos, dir, len } => { PathField::Underground { pos, dir, len } => {
self.map.get_mut(pos.x, pos.y).blocked = true; 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(); let mid_pos = self.pos_in_direction(pos, dir, i.into()).unwrap();
if dir.vertical() { if dir.vertical() {
self.map.get_mut(mid_pos.x, mid_pos.y).underground_vertical = true; 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.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) { fn internal_remove_path_field(&mut self, i: usize) {
match self.path[self.current].pop().unwrap() { match self.problems[i].path.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;
for i in 1..len { for i in 0..=len {
let mid_pos = self.pos_in_direction(&pos, &dir, i.into()).unwrap(); let mid_pos = self.pos_in_direction(&pos, &dir, i.into()).unwrap();
if dir.vertical() { if dir.vertical() {
self.map.get_mut(mid_pos.x, mid_pos.y).underground_vertical = false; 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 { fn apply_path_field(&mut self, path_field: PathField) {
match self.current_path().last().unwrap() { 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 PathField::Belt { pos, dir } => self
.pos_in_direction(pos, dir, 1) .pos_in_direction(pos, dir, 1)
.filter(|p| { .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(), .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| { .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(), .is_some(),
} }
@ -192,43 +256,92 @@ impl Bruteforce {
} }
fn modify_underground(&mut self, pos: &Position, dir: &Direction, len: u8) -> bool { fn modify_underground(&mut self, pos: &Position, dir: &Direction, len: u8) -> bool {
for l in len..MAX_UNDERGROUND_LENGTH { if len >= MAX_UNDERGROUND_LENGTH {
if let Some(p) = self.pos_in_direction(pos, dir, l as usize) { return false;
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 {
return false;
}
}
}
} }
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;
}
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 { 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 { match last {
PathField::Belt { pos, dir } => { PathField::Belt { pos, dir } => {
if second_last.dir() == &dir { if second_last.dir() == &dir {
self.apply_path_field_remove(); self.modify_path_field(PathField::Belt {
self.apply_path_field(PathField::Belt {
pos, pos,
dir: second_last.dir().clockwise(), dir: second_last.dir().clockwise(),
}); });
@ -236,8 +349,7 @@ impl Bruteforce {
} }
if second_last.dir().clockwise() == dir { if second_last.dir().clockwise() == dir {
self.apply_path_field_remove(); self.modify_path_field(PathField::Belt {
self.apply_path_field(PathField::Belt {
pos, pos,
dir: second_last.dir().counter_clockwise(), dir: second_last.dir().counter_clockwise(),
}); });
@ -245,7 +357,7 @@ impl Bruteforce {
} }
if second_last.dir().counter_clockwise() == dir 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; return true;
} }
@ -257,47 +369,57 @@ impl Bruteforce {
} }
} }
self.apply_path_field_remove(); self.remove_path_field();
self.modify_remove()
} else if self.current > 0 {
self.current -= 1;
self.modify_remove() self.modify_remove()
} else { } else {
false false
} }
} }
fn current_path(&self) -> &Vec<PathField> { fn modify_path(&self) -> &Vec<PathField> {
self.path.get(self.current).unwrap() &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 { pub fn next_state(&mut self) -> bool {
self.count += 1; self.count += 1;
// check finish if self.add() {
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 });
return true; return true;
} }
// modify and remove
self.modify_remove() self.modify_remove()
} }
pub fn next_finish_state(&mut self) -> bool { pub fn next_finish_state(&mut self) -> bool {
self.solution_count += 1;
while self.next_state() { 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; 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); let mut m: Map<Option<(usize, &str)>> = Map::new(self.map.width, self.map.height);
for (i, path) in self.path.iter().enumerate() { for (i, problem) in self.problems.iter().enumerate() {
for p in path { 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 { match p {
PathField::Belt { pos, dir } => match dir { PathField::Belt { pos, dir } => match dir {
Direction::Up => m.set(pos.x, pos.y, Some((i, ""))), 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 // Print body
for y in 0..self.map.height { for y in 0..self.map.height {
@ -396,6 +519,10 @@ impl Display for Bruteforce {
write!(f, "{}", c.color(COLORS[*i]))?; write!(f, "{}", c.color(COLORS[*i]))?;
} else if self.map.get(x, y).blocked { } else if self.map.get(x, y).blocked {
write!(f, "#")?; 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 { } else if x % 8 == 0 || y % 8 == 0 {
write!(f, "")?; write!(f, "")?;
} else { } else {