From 9cb7e25149b16cfff2a59a21968872e8ee498a08 Mon Sep 17 00:00:00 2001 From: hal8174 Date: Sun, 31 Dec 2023 15:54:54 +0100 Subject: [PATCH] brute force round robin. --- Cargo.toml | 3 + examples/brute_force.rs | 39 +++-- examples/brute_force2.rs | 32 ++-- src/belt_finding/brute_force.rs | 291 +++++++++++++++++++++++--------- 4 files changed, 250 insertions(+), 115 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a0c2c6d..0326de8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] } diff --git a/examples/brute_force.rs b/examples/brute_force.rs index ad0a03f..8ffac73 100644 --- a/examples/brute_force.rs +++ b/examples/brute_force.rs @@ -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); - // 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 + // ); + + // for i in 0..20 { + // b.next_state(); + // println!( + // "{}\n{}\n{}\n{}", + // b.count(), + // b.solution_count(), + // b.modify_pointer(), + // b + // ); + // } } diff --git a/examples/brute_force2.rs b/examples/brute_force2.rs index 91601ba..91e56ab 100644 --- a/examples/brute_force2.rs +++ b/examples/brute_force2.rs @@ -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); + // } } diff --git a/src/belt_finding/brute_force.rs b/src/belt_finding/brute_force.rs index 408aab3..7099aaa 100644 --- a/src/belt_finding/brute_force.rs +++ b/src/belt_finding/brute_force.rs @@ -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 { - pos: start.0, - dir: start.1, - }]); + 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, + end_pos: Position, + end_dir: Direction, + finished: bool, +} + pub struct Bruteforce { map: Map, - path: Vec>, - end: Vec<(Position, Direction)>, - current: usize, + problems: Vec, + pointer_stack: Vec, + 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 { - return false; - } - } - } + if len >= MAX_UNDERGROUND_LENGTH { + 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 { - 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 { - self.path.get(self.current).unwrap() + fn modify_path(&self) -> &Vec { + &self.problems[self.modify_pointer()].path + } + + fn add_path(&self) -> &Vec { + &self.problems[self.add_pointer()].path + } + + // fn modify_path_mut(&mut self) -> &mut Vec { + // 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> = 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 {