Use visualization for all printing.
This commit is contained in:
parent
7d412ce610
commit
1c44d7aec1
10 changed files with 216 additions and 299 deletions
|
|
@ -1,7 +1,10 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use clap::{Parser, ValueEnum};
|
use clap::{Parser, ValueEnum};
|
||||||
use factorio_blueprint::belt_finding::brute_force::{problems, Bruteforce};
|
use factorio_blueprint::{
|
||||||
|
belt_finding::brute_force::{problems, Bruteforce},
|
||||||
|
common::visualize::Visualize,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(ValueEnum, Clone)]
|
#[derive(ValueEnum, Clone)]
|
||||||
enum Mode {
|
enum Mode {
|
||||||
|
|
@ -44,20 +47,20 @@ fn main() {
|
||||||
|
|
||||||
let mut b = args.problem.get_problem();
|
let mut b = args.problem.get_problem();
|
||||||
|
|
||||||
b.print();
|
b.print_visualization();
|
||||||
|
|
||||||
match args.mode {
|
match args.mode {
|
||||||
Mode::Solutions => {
|
Mode::Solutions => {
|
||||||
while b.next_finish_state(None) {
|
while b.next_finish_state(None) {
|
||||||
println!("{}\n{}\n{}", b.count(), b.solution_count(), b.cost());
|
println!("{}\n{}\n{}", b.count(), b.solution_count(), b.cost());
|
||||||
b.print();
|
b.print_visualization();
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Solutions: {}\nStates: {}", b.solution_count(), b.count());
|
println!("Solutions: {}\nStates: {}", b.solution_count(), b.count());
|
||||||
}
|
}
|
||||||
Mode::Step => {
|
Mode::Step => {
|
||||||
while b.next_state() {
|
while b.next_state() {
|
||||||
b.print();
|
b.print_visualization();
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
let _ = io::stdin().read_line(&mut s);
|
let _ = io::stdin().read_line(&mut s);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
use clap::{Parser, ValueEnum};
|
|
||||||
use factorio_blueprint::belt_finding::{conflict_avoidance::ConflictAvoidance, problems, Problem};
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
#[derive(ValueEnum, Clone)]
|
|
||||||
enum Mode {
|
|
||||||
Solve,
|
|
||||||
ConflictAvoidance,
|
|
||||||
ConflictStep,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(ValueEnum, Clone)]
|
|
||||||
enum ProblemCase {
|
|
||||||
Simple,
|
|
||||||
Level1,
|
|
||||||
Level2,
|
|
||||||
Level3,
|
|
||||||
Level5,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProblemCase {
|
|
||||||
fn get_problem(&self) -> Problem {
|
|
||||||
match self {
|
|
||||||
ProblemCase::Simple => problems::simple(),
|
|
||||||
ProblemCase::Level1 => problems::belt_madness_level_1(),
|
|
||||||
ProblemCase::Level2 => problems::belt_madness_level_2(),
|
|
||||||
ProblemCase::Level3 => problems::belt_madness_level_3(),
|
|
||||||
ProblemCase::Level5 => problems::belt_madness_level_5(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Parser)]
|
|
||||||
struct Args {
|
|
||||||
#[arg(value_enum, default_value = "level1")]
|
|
||||||
problem: ProblemCase,
|
|
||||||
#[arg(value_enum, default_value = "conflict-avoidance")]
|
|
||||||
mode: Mode,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let args = Args::parse();
|
|
||||||
|
|
||||||
let mut p = args.problem.get_problem();
|
|
||||||
|
|
||||||
match args.mode {
|
|
||||||
Mode::Solve => {
|
|
||||||
p.print();
|
|
||||||
p.find_path();
|
|
||||||
p.print();
|
|
||||||
}
|
|
||||||
Mode::ConflictAvoidance => {
|
|
||||||
p.print();
|
|
||||||
p.find_path();
|
|
||||||
p.print();
|
|
||||||
p.find_path();
|
|
||||||
p.print();
|
|
||||||
p.find_path();
|
|
||||||
p.print();
|
|
||||||
p.find_path();
|
|
||||||
p.print();
|
|
||||||
let mut c = ConflictAvoidance::new(&p);
|
|
||||||
c.print();
|
|
||||||
while c.remove_conflict(None) {
|
|
||||||
c.print();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Mode::ConflictStep => {
|
|
||||||
p.print();
|
|
||||||
p.find_path();
|
|
||||||
p.print();
|
|
||||||
p.find_path();
|
|
||||||
p.print();
|
|
||||||
p.find_path();
|
|
||||||
p.print();
|
|
||||||
p.find_path();
|
|
||||||
p.print();
|
|
||||||
let mut c = ConflictAvoidance::new(&p);
|
|
||||||
c.print();
|
|
||||||
while c.remove_conflict(None) {
|
|
||||||
c.print();
|
|
||||||
let mut s = String::new();
|
|
||||||
let _ = io::stdin().read_line(&mut s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +1,7 @@
|
||||||
use std::time::Instant;
|
use super::{common::PathField, Position};
|
||||||
|
|
||||||
use super::{
|
|
||||||
common::{print_map, PathField},
|
|
||||||
Position,
|
|
||||||
};
|
|
||||||
use crate::misc::Map;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use termcolor::ColorSpec;
|
use crate::{common::visualize::Visualize, misc::Map};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub struct BruteforceField {
|
pub struct BruteforceField {
|
||||||
|
|
@ -592,83 +587,67 @@ impl Bruteforce {
|
||||||
pub fn solution_count(&self) -> u128 {
|
pub fn solution_count(&self) -> u128 {
|
||||||
self.solution_count
|
self.solution_count
|
||||||
}
|
}
|
||||||
pub fn print(&self) {
|
}
|
||||||
let mut m: Map<Option<(usize, &str)>> = Map::new(self.map.width, self.map.height);
|
|
||||||
|
|
||||||
for (i, problem) in self.problems.iter().enumerate() {
|
impl Visualize for Bruteforce {
|
||||||
if problem.finished {
|
fn visualize(&self) -> crate::common::visualize::Visualization {
|
||||||
m.set(
|
let mut v = crate::common::visualize::Visualization::new(Position::new(
|
||||||
problem.end_pos.x as usize,
|
self.map.width as i32,
|
||||||
problem.end_pos.y as usize,
|
self.map.height as i32,
|
||||||
Some((i, "T")),
|
));
|
||||||
);
|
|
||||||
} else {
|
for x in 0..self.map.width {
|
||||||
m.set(
|
for y in 0..self.map.height {
|
||||||
problem.end_pos.x as usize,
|
if self.map.get(x, y).blocked {
|
||||||
problem.end_pos.y as usize,
|
v.add_symbol(
|
||||||
Some((i, "t")),
|
Position::new(x as i32, y as i32),
|
||||||
);
|
crate::common::visualize::Symbol::Block,
|
||||||
}
|
Some(crate::common::visualize::Color::white()),
|
||||||
for p in &problem.path {
|
None,
|
||||||
match p {
|
);
|
||||||
PathField::Belt { pos, dir } => match dir {
|
|
||||||
Direction::Up => m.set(pos.x as usize, pos.y as usize, Some((i, "↑"))),
|
|
||||||
Direction::Right => m.set(pos.x as usize, pos.y as usize, Some((i, "→"))),
|
|
||||||
Direction::Down => m.set(pos.x as usize, pos.y as usize, Some((i, "↓"))),
|
|
||||||
Direction::Left => m.set(pos.x as usize, pos.y as usize, Some((i, "←"))),
|
|
||||||
},
|
|
||||||
PathField::Underground { pos, dir, len } => {
|
|
||||||
match dir {
|
|
||||||
Direction::Up => m.set(pos.x as usize, pos.y as usize, Some((i, "↟"))),
|
|
||||||
Direction::Right => {
|
|
||||||
m.set(pos.x as usize, pos.y as usize, Some((i, "↠")))
|
|
||||||
}
|
|
||||||
Direction::Down => {
|
|
||||||
m.set(pos.x as usize, pos.y as usize, Some((i, "↡")))
|
|
||||||
}
|
|
||||||
Direction::Left => {
|
|
||||||
m.set(pos.x as usize, pos.y as usize, Some((i, "↞")))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let end_pos = pos.in_direction(dir, *len as PositionType);
|
|
||||||
match dir {
|
|
||||||
Direction::Up => {
|
|
||||||
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↥")))
|
|
||||||
}
|
|
||||||
Direction::Right => {
|
|
||||||
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↦")))
|
|
||||||
}
|
|
||||||
Direction::Down => {
|
|
||||||
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↧")))
|
|
||||||
}
|
|
||||||
Direction::Left => {
|
|
||||||
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↤")))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print body
|
for (i, problem) in self.problems.iter().enumerate() {
|
||||||
|
for p in &problem.path {
|
||||||
let _ = print_map(self.map.width as i32, self.map.height as i32, |x, y| {
|
match p {
|
||||||
if let Some((i, c)) = m.get(x as usize, y as usize) {
|
PathField::Belt { pos, dir } => {
|
||||||
let mut color = ColorSpec::new();
|
v.add_symbol(
|
||||||
color.set_fg(Some(crate::common::color::COLORS[*i]));
|
*pos,
|
||||||
(color, *c)
|
crate::common::visualize::Symbol::Arrow(*dir),
|
||||||
} else if self.map.get(x as usize, y as usize).blocked {
|
Some(crate::common::visualize::Color::index(i)),
|
||||||
(ColorSpec::new(), "#")
|
None,
|
||||||
} else if self.map.get(x as usize, y as usize).underground_horizontal {
|
);
|
||||||
(ColorSpec::new(), "_")
|
}
|
||||||
} else if self.map.get(x as usize, y as usize).underground_vertical {
|
PathField::Underground { pos, dir, len } => {
|
||||||
(ColorSpec::new(), "|")
|
v.add_symbol(
|
||||||
} else if x % 8 == 0 || y % 8 == 0 {
|
*pos,
|
||||||
(ColorSpec::new(), "∙")
|
crate::common::visualize::Symbol::ArrowEnter(*dir),
|
||||||
} else {
|
Some(crate::common::visualize::Color::index(i)),
|
||||||
(ColorSpec::new(), " ")
|
None,
|
||||||
|
);
|
||||||
|
v.add_symbol(
|
||||||
|
pos.in_direction(dir, *len as i32),
|
||||||
|
crate::common::visualize::Symbol::ArrowExit(*dir),
|
||||||
|
Some(crate::common::visualize::Color::index(i)),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
v.add_symbol(
|
||||||
|
problem.end_pos,
|
||||||
|
crate::common::visualize::Symbol::Char(match problem.finished {
|
||||||
|
true => 'T',
|
||||||
|
false => 't',
|
||||||
|
}),
|
||||||
|
Some(crate::common::visualize::Color::index(i)),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,10 @@
|
||||||
use super::{
|
use super::{common::PathField, Problem};
|
||||||
common::{print_map, PathField},
|
|
||||||
Problem,
|
|
||||||
};
|
|
||||||
use crate::prelude::*;
|
|
||||||
use crate::{belt_finding::brute_force::BruteforceBuilder, misc::Map};
|
use crate::{belt_finding::brute_force::BruteforceBuilder, misc::Map};
|
||||||
|
use crate::{common::visualize::Visualize, prelude::*};
|
||||||
use std::{
|
use std::{
|
||||||
ops::RangeInclusive,
|
ops::RangeInclusive,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use termcolor::ColorSpec;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Field {
|
struct Field {
|
||||||
|
|
@ -354,7 +350,7 @@ impl ConflictAvoidance {
|
||||||
}
|
}
|
||||||
// dbg!(&candidates);
|
// dbg!(&candidates);
|
||||||
|
|
||||||
while timeout.is_some_and(|t| t < Instant::now()) {
|
while timeout.is_none_or(|t| t > Instant::now()) {
|
||||||
candidates.sort_by_key(|c| -c.area());
|
candidates.sort_by_key(|c| -c.area());
|
||||||
// dbg!(&candidates);
|
// dbg!(&candidates);
|
||||||
let c = match candidates.pop() {
|
let c = match candidates.pop() {
|
||||||
|
|
@ -499,53 +495,14 @@ impl ConflictAvoidance {
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn print(&self) {
|
impl Visualize for ConflictAvoidance {
|
||||||
let mut m: Map<Option<(usize, &str)>> = Map::new(self.map.width, self.map.height);
|
fn visualize(&self) -> crate::common::visualize::Visualization {
|
||||||
|
let mut v = crate::common::visualize::Visualization::new(Position::new(
|
||||||
for (i, problem) in self.belts.iter().enumerate() {
|
self.map.width as i32,
|
||||||
for p in problem {
|
self.map.height as i32,
|
||||||
match p {
|
));
|
||||||
PathField::Belt { pos, dir } => match dir {
|
|
||||||
Direction::Up => m.set(pos.x as usize, pos.y as usize, Some((i, "↑"))),
|
|
||||||
Direction::Right => m.set(pos.x as usize, pos.y as usize, Some((i, "→"))),
|
|
||||||
Direction::Down => m.set(pos.x as usize, pos.y as usize, Some((i, "↓"))),
|
|
||||||
Direction::Left => m.set(pos.x as usize, pos.y as usize, Some((i, "←"))),
|
|
||||||
},
|
|
||||||
PathField::Underground { pos, dir, len } => {
|
|
||||||
match dir {
|
|
||||||
Direction::Up => m.set(pos.x as usize, pos.y as usize, Some((i, "↟"))),
|
|
||||||
Direction::Right => {
|
|
||||||
m.set(pos.x as usize, pos.y as usize, Some((i, "↠")))
|
|
||||||
}
|
|
||||||
Direction::Down => {
|
|
||||||
m.set(pos.x as usize, pos.y as usize, Some((i, "↡")))
|
|
||||||
}
|
|
||||||
Direction::Left => {
|
|
||||||
m.set(pos.x as usize, pos.y as usize, Some((i, "↞")))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let end_pos = pos.in_direction(dir, *len as PositionType);
|
|
||||||
match dir {
|
|
||||||
Direction::Up => {
|
|
||||||
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↥")))
|
|
||||||
}
|
|
||||||
Direction::Right => {
|
|
||||||
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↦")))
|
|
||||||
}
|
|
||||||
Direction::Down => {
|
|
||||||
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↧")))
|
|
||||||
}
|
|
||||||
Direction::Left => {
|
|
||||||
m.set(end_pos.x as usize, end_pos.y as usize, Some((i, "↤")))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let last_pos = problem.last().unwrap().pos();
|
|
||||||
m.set(last_pos.x as usize, last_pos.y as usize, Some((i, "T")));
|
|
||||||
}
|
|
||||||
|
|
||||||
// create conflict map
|
// create conflict map
|
||||||
let mut conflicts: Map<usize> = Map::new(self.map.width, self.map.height);
|
let mut conflicts: Map<usize> = Map::new(self.map.width, self.map.height);
|
||||||
|
|
@ -554,6 +511,13 @@ impl ConflictAvoidance {
|
||||||
for y in 0..self.map.height {
|
for y in 0..self.map.height {
|
||||||
if self.map.get(x, y).blocked {
|
if self.map.get(x, y).blocked {
|
||||||
*conflicts.get_mut(x, y) += 1;
|
*conflicts.get_mut(x, y) += 1;
|
||||||
|
|
||||||
|
v.add_symbol(
|
||||||
|
Position::new(x as i32, y as i32),
|
||||||
|
crate::common::visualize::Symbol::Block,
|
||||||
|
Some(crate::common::visualize::Color::white()),
|
||||||
|
None,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -572,31 +536,62 @@ impl ConflictAvoidance {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Print body
|
|
||||||
|
|
||||||
let _ = print_map(self.map.width as i32, self.map.height as i32, |x, y| {
|
for (i, path) in self.belts.iter().enumerate() {
|
||||||
let mut color = ColorSpec::new();
|
for p in path {
|
||||||
|
match p {
|
||||||
if let Some((xrange, yrange)) = &self.range {
|
PathField::Belt { pos, dir } => {
|
||||||
if xrange.contains(&x) && yrange.contains(&y) {
|
v.add_symbol(
|
||||||
color.set_bg(Some(termcolor::Color::Rgb(96, 96, 0)));
|
*pos,
|
||||||
|
crate::common::visualize::Symbol::Arrow(*dir),
|
||||||
|
Some(crate::common::visualize::Color::index(i)),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
PathField::Underground { pos, dir, len } => {
|
||||||
|
v.add_symbol(
|
||||||
|
*pos,
|
||||||
|
crate::common::visualize::Symbol::ArrowEnter(*dir),
|
||||||
|
Some(crate::common::visualize::Color::index(i)),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
v.add_symbol(
|
||||||
|
pos.in_direction(dir, *len as i32),
|
||||||
|
crate::common::visualize::Symbol::ArrowExit(*dir),
|
||||||
|
Some(crate::common::visualize::Color::index(i)),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if conflicts.get(x as usize, y as usize) > &1 {
|
for x in 0..self.map.width {
|
||||||
color.set_bg(Some(termcolor::Color::Black));
|
for y in 0..self.map.height {
|
||||||
|
if conflicts.get(x, y) > &1 {
|
||||||
|
v.overwrite_background(
|
||||||
|
Position::new(x as i32, y as i32),
|
||||||
|
Some(crate::common::visualize::Color::new(100, 80, 80)),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some((i, c)) = m.get(x as usize, y as usize) {
|
for path in &self.belts {
|
||||||
color.set_fg(Some(crate::common::color::COLORS[*i]));
|
for p in &path[1..] {
|
||||||
(color, c)
|
match p {
|
||||||
} else if self.map.get(x as usize, y as usize).blocked {
|
PathField::Belt { pos, dir: _ } => {
|
||||||
(color, "#")
|
*conflicts.get_mut(pos.x as usize, pos.y as usize) += 1
|
||||||
} else if x % 8 == 0 || y % 8 == 0 {
|
}
|
||||||
(color, "∙")
|
PathField::Underground { pos, dir, len } => {
|
||||||
} else {
|
*conflicts.get_mut(pos.x as usize, pos.y as usize) += 1;
|
||||||
(color, " ")
|
let end = pos.in_direction(dir, *len as PositionType);
|
||||||
|
*conflicts.get_mut(end.x as usize, end.y as usize) += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,11 @@
|
||||||
use crate::common::color::COLORS;
|
use crate::common::visualize::Visualize;
|
||||||
use crate::graph::wheighted_graph::shortest_path::dijkstra;
|
use crate::graph::wheighted_graph::shortest_path::dijkstra;
|
||||||
use crate::graph::wheighted_graph::WheightedGraph;
|
use crate::graph::wheighted_graph::WheightedGraph;
|
||||||
use crate::layout::Layout;
|
use crate::layout::Layout;
|
||||||
use crate::misc::Map;
|
use crate::misc::Map;
|
||||||
|
use crate::prelude::*;
|
||||||
use crate::priority_queue::BinaryHeap;
|
use crate::priority_queue::BinaryHeap;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use termcolor::ColorSpec;
|
|
||||||
|
|
||||||
use self::common::print_map;
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
pub mod brute_force;
|
pub mod brute_force;
|
||||||
pub mod common;
|
pub mod common;
|
||||||
|
|
@ -132,45 +129,58 @@ impl Problem {
|
||||||
// self.map.get_mut(p.0.x as usize, p.0.y as usize).weight = f64::INFINITY;
|
// self.map.get_mut(p.0.x as usize, p.0.y as usize).weight = f64::INFINITY;
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn print(&self) {
|
impl Visualize for Problem {
|
||||||
let _ = print_map(self.map.width as i32, self.map.height as i32, |x, y| {
|
fn visualize(&self) -> crate::common::visualize::Visualization {
|
||||||
let mut color = ColorSpec::new();
|
let mut v = crate::common::visualize::Visualization::new(Position::new(
|
||||||
if let Some(i) = self
|
self.map.width as i32,
|
||||||
.start
|
self.map.height as i32,
|
||||||
.iter()
|
));
|
||||||
.position(|p| p.0 == Position::new(x as PositionType, y as PositionType))
|
|
||||||
{
|
for x in 0..self.map.width {
|
||||||
color.set_fg(Some(COLORS[i]));
|
for y in 0..self.map.height {
|
||||||
(color, "s")
|
if self.map.get(x, y).blocked {
|
||||||
} else if let Some(i) = self
|
v.add_symbol(
|
||||||
.end
|
Position::new(x as i32, y as i32),
|
||||||
.iter()
|
crate::common::visualize::Symbol::Block,
|
||||||
.position(|p| p.0 == Position::new(x as PositionType, y as PositionType))
|
Some(crate::common::visualize::Color::white()),
|
||||||
{
|
None,
|
||||||
color.set_fg(Some(COLORS[i]));
|
)
|
||||||
(color, "t")
|
|
||||||
} else if let Some((i, p)) = self.path.iter().enumerate().find_map(|(i, v)| {
|
|
||||||
v.iter()
|
|
||||||
.position(|p| p.0 == Position::new(x as PositionType, y as PositionType))
|
|
||||||
.map(|j| (i, j))
|
|
||||||
}) {
|
|
||||||
color.set_fg(Some(COLORS[i]));
|
|
||||||
let c = &self.path[i][p];
|
|
||||||
match c.1 {
|
|
||||||
Direction::Up => (color, "↑"),
|
|
||||||
Direction::Right => (color, "→"),
|
|
||||||
Direction::Down => (color, "↓"),
|
|
||||||
Direction::Left => (color, "←"),
|
|
||||||
}
|
}
|
||||||
} else if self.map.get(x as usize, y as usize).blocked {
|
|
||||||
(color, "#")
|
|
||||||
} else if x % 8 == 0 || y % 8 == 0 {
|
|
||||||
(color, "∙")
|
|
||||||
} else {
|
|
||||||
(color, " ")
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
for (i, (p, _d)) in self.start.iter().enumerate() {
|
||||||
|
v.add_symbol(
|
||||||
|
*p,
|
||||||
|
crate::common::visualize::Symbol::Char('S'),
|
||||||
|
Some(crate::common::visualize::Color::index(i)),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, (p, _d)) in self.end.iter().enumerate() {
|
||||||
|
v.add_symbol(
|
||||||
|
*p,
|
||||||
|
crate::common::visualize::Symbol::Char('T'),
|
||||||
|
Some(crate::common::visualize::Color::index(i)),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, p) in self.path.iter().enumerate() {
|
||||||
|
for (pos, dir) in p {
|
||||||
|
v.add_symbol(
|
||||||
|
*pos,
|
||||||
|
crate::common::visualize::Symbol::Arrow(*dir),
|
||||||
|
Some(crate::common::visualize::Color::index(i)),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
use clap::{Parser, Subcommand, ValueEnum};
|
use clap::{Parser, Subcommand, ValueEnum};
|
||||||
use factorio_blueprint::belt_finding::{conflict_avoidance::ConflictAvoidance, problems, Problem};
|
use factorio_blueprint::{
|
||||||
|
belt_finding::{conflict_avoidance::ConflictAvoidance, problems, Problem},
|
||||||
|
common::visualize::Visualize,
|
||||||
|
};
|
||||||
use std::{io, path::PathBuf};
|
use std::{io, path::PathBuf};
|
||||||
|
|
||||||
#[derive(ValueEnum, Clone)]
|
#[derive(ValueEnum, Clone)]
|
||||||
|
|
@ -50,28 +53,28 @@ fn main() {
|
||||||
|
|
||||||
match args.mode {
|
match args.mode {
|
||||||
Mode::Solve => {
|
Mode::Solve => {
|
||||||
p.print();
|
p.print_visualization();
|
||||||
p.find_path();
|
p.find_path();
|
||||||
p.print();
|
p.print_visualization();
|
||||||
}
|
}
|
||||||
Mode::ConflictAvoidance => {
|
Mode::ConflictAvoidance => {
|
||||||
p.print();
|
p.print_visualization();
|
||||||
p.find_path();
|
p.find_path();
|
||||||
p.print();
|
p.print_visualization();
|
||||||
let mut c = ConflictAvoidance::new(&p);
|
let mut c = ConflictAvoidance::new(&p);
|
||||||
c.print();
|
c.print_visualization();
|
||||||
while c.remove_conflict(None) {
|
while c.remove_conflict(None) {
|
||||||
c.print();
|
c.print_visualization();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Mode::ConflictStep => {
|
Mode::ConflictStep => {
|
||||||
p.print();
|
p.print_visualization();
|
||||||
p.find_path();
|
p.find_path();
|
||||||
p.print();
|
p.print_visualization();
|
||||||
let mut c = ConflictAvoidance::new(&p);
|
let mut c = ConflictAvoidance::new(&p);
|
||||||
c.print();
|
c.print_visualization();
|
||||||
while c.remove_conflict(None) {
|
while c.remove_conflict(None) {
|
||||||
c.print();
|
c.print_visualization();
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
let _ = io::stdin().read_line(&mut s);
|
let _ = io::stdin().read_line(&mut s);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::transformation;
|
|
||||||
|
|
||||||
pub type PositionType = i32;
|
pub type PositionType = i32;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use super::Visualization;
|
use super::Visualization;
|
||||||
use crate::{common::visualize::Symbol, prelude::Direction};
|
use crate::{common::visualize::Symbol, prelude::Direction};
|
||||||
use image::{GenericImage, Pixel, Rgba, RgbaImage};
|
use image::{GenericImage, Rgba, RgbaImage};
|
||||||
|
|
||||||
pub(super) fn draw<I: GenericImage<Pixel = Rgba<u8>>>(v: &Visualization, image: &mut I) {
|
pub(super) fn draw<I: GenericImage<Pixel = Rgba<u8>>>(v: &Visualization, image: &mut I) {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,10 @@ impl Color {
|
||||||
Self { r, g, b }
|
Self { r, g, b }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn white() -> Self {
|
||||||
|
Self::new(255, 255, 255)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn index(i: usize) -> Self {
|
pub fn index(i: usize) -> Self {
|
||||||
let c = [
|
let c = [
|
||||||
Color::new(0xe6, 0x00, 0x49),
|
Color::new(0xe6, 0x00, 0x49),
|
||||||
|
|
@ -112,7 +116,19 @@ impl Visualization {
|
||||||
fg: Option<Color>,
|
fg: Option<Color>,
|
||||||
bg: Option<Color>,
|
bg: Option<Color>,
|
||||||
) {
|
) {
|
||||||
self.symbols.insert(pos, (symbol, fg, bg));
|
if let Some(s) = self.symbols.get_mut(&pos) {
|
||||||
|
*s = (symbol, fg, bg);
|
||||||
|
} else {
|
||||||
|
self.symbols.insert(pos, (symbol, fg, bg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn overwrite_background(&mut self, pos: Position, bg: Option<Color>) {
|
||||||
|
if let Some(s) = self.symbols.get_mut(&pos) {
|
||||||
|
s.2 = bg;
|
||||||
|
} else {
|
||||||
|
self.symbols.insert(pos, (Symbol::Space, None, bg));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> Position {
|
pub fn size(&self) -> Position {
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,7 @@ impl<'a> PathLayout<'a> {
|
||||||
if !c.remove_all_conflicts(Some(std::time::Duration::from_secs(2))) {
|
if !c.remove_all_conflicts(Some(std::time::Duration::from_secs(2))) {
|
||||||
if start.elapsed().as_secs_f32() > 0.5 {
|
if start.elapsed().as_secs_f32() > 0.5 {
|
||||||
println!("Conflict avoidance: {:.2}", start.elapsed().as_secs_f32());
|
println!("Conflict avoidance: {:.2}", start.elapsed().as_secs_f32());
|
||||||
c.print();
|
c.print_visualization();
|
||||||
let file = std::fs::File::create(format!(
|
let file = std::fs::File::create(format!(
|
||||||
"out/{}.json",
|
"out/{}.json",
|
||||||
OUTFILEINDEX.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
|
OUTFILEINDEX.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue