Use visualization for all printing.

This commit is contained in:
hal8174 2024-09-19 16:03:52 +02:00
parent 7d412ce610
commit 1c44d7aec1
10 changed files with 216 additions and 299 deletions

View file

@ -1,7 +1,10 @@
use std::io;
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)]
enum Mode {
@ -44,20 +47,20 @@ fn main() {
let mut b = args.problem.get_problem();
b.print();
b.print_visualization();
match args.mode {
Mode::Solutions => {
while b.next_finish_state(None) {
println!("{}\n{}\n{}", b.count(), b.solution_count(), b.cost());
b.print();
b.print_visualization();
}
println!("Solutions: {}\nStates: {}", b.solution_count(), b.count());
}
Mode::Step => {
while b.next_state() {
b.print();
b.print_visualization();
let mut s = String::new();
let _ = io::stdin().read_line(&mut s);
}

View file

@ -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);
}
}
}
}

View file

@ -1,12 +1,7 @@
use std::time::Instant;
use super::{
common::{print_map, PathField},
Position,
};
use crate::misc::Map;
use super::{common::PathField, Position};
use crate::prelude::*;
use termcolor::ColorSpec;
use crate::{common::visualize::Visualize, misc::Map};
use std::time::Instant;
#[derive(Default, Debug, Clone)]
pub struct BruteforceField {
@ -592,83 +587,67 @@ impl Bruteforce {
pub fn solution_count(&self) -> u128 {
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() {
if problem.finished {
m.set(
problem.end_pos.x as usize,
problem.end_pos.y as usize,
Some((i, "T")),
);
} else {
m.set(
problem.end_pos.x as usize,
problem.end_pos.y as usize,
Some((i, "t")),
);
}
for p in &problem.path {
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, "")))
}
};
}
impl Visualize for Bruteforce {
fn visualize(&self) -> crate::common::visualize::Visualization {
let mut v = crate::common::visualize::Visualization::new(Position::new(
self.map.width as i32,
self.map.height as i32,
));
for x in 0..self.map.width {
for y in 0..self.map.height {
if self.map.get(x, y).blocked {
v.add_symbol(
Position::new(x as i32, y as i32),
crate::common::visualize::Symbol::Block,
Some(crate::common::visualize::Color::white()),
None,
);
}
}
}
// Print body
let _ = print_map(self.map.width as i32, self.map.height as i32, |x, y| {
if let Some((i, c)) = m.get(x as usize, y as usize) {
let mut color = ColorSpec::new();
color.set_fg(Some(crate::common::color::COLORS[*i]));
(color, *c)
} else if self.map.get(x as usize, y as usize).blocked {
(ColorSpec::new(), "#")
} 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 {
(ColorSpec::new(), "|")
} else if x % 8 == 0 || y % 8 == 0 {
(ColorSpec::new(), "")
} else {
(ColorSpec::new(), " ")
for (i, problem) in self.problems.iter().enumerate() {
for p in &problem.path {
match p {
PathField::Belt { pos, dir } => {
v.add_symbol(
*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,
);
}
}
}
});
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
}
}

View file

@ -1,14 +1,10 @@
use super::{
common::{print_map, PathField},
Problem,
};
use crate::prelude::*;
use super::{common::PathField, Problem};
use crate::{belt_finding::brute_force::BruteforceBuilder, misc::Map};
use crate::{common::visualize::Visualize, prelude::*};
use std::{
ops::RangeInclusive,
time::{Duration, Instant},
};
use termcolor::ColorSpec;
#[derive(Default)]
struct Field {
@ -354,7 +350,7 @@ impl ConflictAvoidance {
}
// 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());
// dbg!(&candidates);
let c = match candidates.pop() {
@ -499,53 +495,14 @@ impl ConflictAvoidance {
}
true
}
}
pub fn print(&self) {
let mut m: Map<Option<(usize, &str)>> = Map::new(self.map.width, self.map.height);
for (i, problem) in self.belts.iter().enumerate() {
for p in problem {
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")));
}
impl Visualize for ConflictAvoidance {
fn visualize(&self) -> crate::common::visualize::Visualization {
let mut v = crate::common::visualize::Visualization::new(Position::new(
self.map.width as i32,
self.map.height as i32,
));
// create conflict map
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 {
if self.map.get(x, y).blocked {
*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| {
let mut color = ColorSpec::new();
if let Some((xrange, yrange)) = &self.range {
if xrange.contains(&x) && yrange.contains(&y) {
color.set_bg(Some(termcolor::Color::Rgb(96, 96, 0)));
for (i, path) in self.belts.iter().enumerate() {
for p in path {
match p {
PathField::Belt { pos, dir } => {
v.add_symbol(
*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 {
color.set_bg(Some(termcolor::Color::Black));
for x in 0..self.map.width {
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) {
color.set_fg(Some(crate::common::color::COLORS[*i]));
(color, c)
} 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 path in &self.belts {
for p in &path[1..] {
match p {
PathField::Belt { pos, dir: _ } => {
*conflicts.get_mut(pos.x as usize, pos.y as usize) += 1
}
PathField::Underground { pos, dir, len } => {
*conflicts.get_mut(pos.x as usize, pos.y as usize) += 1;
let end = pos.in_direction(dir, *len as PositionType);
*conflicts.get_mut(end.x as usize, end.y as usize) += 1;
}
}
}
});
}
v
}
}

View file

@ -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::WheightedGraph;
use crate::layout::Layout;
use crate::misc::Map;
use crate::prelude::*;
use crate::priority_queue::BinaryHeap;
use serde::{Deserialize, Serialize};
use termcolor::ColorSpec;
use self::common::print_map;
use crate::prelude::*;
pub mod brute_force;
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;
// }
}
}
pub fn print(&self) {
let _ = print_map(self.map.width as i32, self.map.height as i32, |x, y| {
let mut color = ColorSpec::new();
if let Some(i) = self
.start
.iter()
.position(|p| p.0 == Position::new(x as PositionType, y as PositionType))
{
color.set_fg(Some(COLORS[i]));
(color, "s")
} else if let Some(i) = self
.end
.iter()
.position(|p| p.0 == Position::new(x as PositionType, y as PositionType))
{
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, ""),
impl Visualize for Problem {
fn visualize(&self) -> crate::common::visualize::Visualization {
let mut v = crate::common::visualize::Visualization::new(Position::new(
self.map.width as i32,
self.map.height as i32,
));
for x in 0..self.map.width {
for y in 0..self.map.height {
if self.map.get(x, y).blocked {
v.add_symbol(
Position::new(x as i32, y as i32),
crate::common::visualize::Symbol::Block,
Some(crate::common::visualize::Color::white()),
None,
)
}
} 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
}
}

View file

@ -1,5 +1,8 @@
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};
#[derive(ValueEnum, Clone)]
@ -50,28 +53,28 @@ fn main() {
match args.mode {
Mode::Solve => {
p.print();
p.print_visualization();
p.find_path();
p.print();
p.print_visualization();
}
Mode::ConflictAvoidance => {
p.print();
p.print_visualization();
p.find_path();
p.print();
p.print_visualization();
let mut c = ConflictAvoidance::new(&p);
c.print();
c.print_visualization();
while c.remove_conflict(None) {
c.print();
c.print_visualization();
}
}
Mode::ConflictStep => {
p.print();
p.print_visualization();
p.find_path();
p.print();
p.print_visualization();
let mut c = ConflictAvoidance::new(&p);
c.print();
c.print_visualization();
while c.remove_conflict(None) {
c.print();
c.print_visualization();
let mut s = String::new();
let _ = io::stdin().read_line(&mut s);
}

View file

@ -1,8 +1,6 @@
use crate::prelude::*;
use serde::{Deserialize, Serialize};
use super::transformation;
pub type PositionType = i32;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]

View file

@ -1,6 +1,6 @@
use super::Visualization;
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) {
assert_eq!(

View file

@ -80,6 +80,10 @@ impl Color {
Self { r, g, b }
}
pub fn white() -> Self {
Self::new(255, 255, 255)
}
pub fn index(i: usize) -> Self {
let c = [
Color::new(0xe6, 0x00, 0x49),
@ -112,7 +116,19 @@ impl Visualization {
fg: 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 {

View file

@ -209,7 +209,7 @@ impl<'a> PathLayout<'a> {
if !c.remove_all_conflicts(Some(std::time::Duration::from_secs(2))) {
if start.elapsed().as_secs_f32() > 0.5 {
println!("Conflict avoidance: {:.2}", start.elapsed().as_secs_f32());
c.print();
c.print_visualization();
let file = std::fs::File::create(format!(
"out/{}.json",
OUTFILEINDEX.fetch_add(1, std::sync::atomic::Ordering::Relaxed)