diff --git a/examples/brute_force.rs b/examples/brute_force.rs index b78fdfa..ad0a03f 100644 --- a/examples/brute_force.rs +++ b/examples/brute_force.rs @@ -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); } diff --git a/examples/brute_force2.rs b/examples/brute_force2.rs new file mode 100644 index 0000000..91601ba --- /dev/null +++ b/examples/brute_force2.rs @@ -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()); +} diff --git a/src/belt_finding/brute_force.rs b/src/belt_finding/brute_force.rs index ff82a6f..408aab3 100644 --- a/src/belt_finding/brute_force.rs +++ b/src/belt_finding/brute_force.rs @@ -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, - path: Vec, - end: (Position, Direction), + path: Vec>, + 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 { + 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> = 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 diff --git a/src/belt_finding/mod.rs b/src/belt_finding/mod.rs index 52c0b39..b2a96da 100644 --- a/src/belt_finding/mod.rs +++ b/src/belt_finding/mod.rs @@ -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,