Add grid layout for images.

This commit is contained in:
hal8174 2024-09-18 13:55:03 +02:00
parent 65c0a85889
commit 812f246706
4 changed files with 89 additions and 31 deletions

View file

@ -1,7 +1,7 @@
use clap::Parser; use clap::Parser;
use factorio_blueprint::{ use factorio_blueprint::{
common::visualize::Visualize, common::visualize::Visualize,
layout::{genetic_algorithm2, PathLayout}, layout::{genetic_algorithm2, GeneticAlgorithm, PathLayout},
}; };
use rand::{rngs::SmallRng, SeedableRng}; use rand::{rngs::SmallRng, SeedableRng};
@ -22,25 +22,25 @@ fn main() {
dbg!(&p); dbg!(&p);
// let mut g = GeneticAlgorithm::new(&p, 20, 2, 0, &mut rng); let mut g = GeneticAlgorithm::new(&p, 20, 2, 0, &mut rng);
// for i in 0..100 { for i in 0..100 {
// println!("Generatrion {i}"); println!("Generatrion {i}");
// g.generation(&mut rng); g.generation(&mut rng);
// }
// g.output_population();
let mut m: Option<PathLayout> = None;
for _ in 0..20 {
let g = genetic_algorithm2(&p, 10, 320, &mut rng);
g.print_visualization();
g.png_visualization("test.png");
if m.as_ref().is_none_or(|m| g.score() < m.score()) {
m = Some(g);
}
} }
m.unwrap().print_visualization(); g.output_population();
// let mut m: Option<PathLayout> = None;
// for _ in 0..20 {
// let g = genetic_algorithm2(&p, 10, 320, &mut rng);
// g.print_visualization();
// g.png_visualization("test.png");
// if m.as_ref().is_none_or(|m| g.score() < m.score()) {
// m = Some(g);
// }
// }
// m.unwrap().print_visualization();
} }

View file

@ -1,8 +1,8 @@
use super::Visualization; use super::Visualization;
use crate::{common::visualize::Symbol, prelude::Direction}; use crate::{common::visualize::Symbol, prelude::Direction};
use image::{GenericImage, Rgba}; use image::{GenericImage, Pixel, 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!(
(v.size.x as u32 * 10, v.size.y as u32 * 10), (v.size.x as u32 * 10, v.size.y as u32 * 10),
image.dimensions() image.dimensions()
@ -110,6 +110,61 @@ pub(super) fn draw<I: GenericImage<Pixel = Rgba<u8>>>(v: Visualization, image: &
} }
} }
pub fn image_grid(
visualizations: &[Visualization],
width: u32,
height: u32,
columns: u32,
) -> RgbaImage {
let border_color = Rgba::from([255, 255, 255, 255]);
let rows = visualizations.len().div_ceil(columns as usize) as u32;
let mut img = RgbaImage::new((width * 10 + 2) * columns, (height * 10 + 2) * rows);
for (i, v) in visualizations.iter().enumerate() {
let i = i as u32;
let r = i / columns;
let c = i % columns;
let size = v.size();
let mut sub_img = img.sub_image(
1 + c * (width * 10 + 2),
1 + r * (height * 10 + 2),
(size.x as u32) * 10,
(size.y as u32) * 10,
);
draw(v, &mut *sub_img);
for x in 0..(size.x as u32 * 10 + 2) {
img.put_pixel(
c * (width * 10 + 2) + x,
r * (height * 10 + 2),
border_color,
);
img.put_pixel(
c * (width * 10 + 2) + x,
r * (height * 10 + 2) + (size.y as u32) * 10 + 1,
border_color,
);
}
for y in 0..(size.y as u32 * 10 + 2) {
img.put_pixel(
c * (width * 10 + 2),
r * (height * 10 + 2) + y,
border_color,
);
img.put_pixel(
c * (width * 10 + 2) + (size.x as u32) * 10 + 1,
r * (height * 10 + 2) + y,
border_color,
);
}
}
img
}
fn rotate(dir: Direction, pos: (u32, u32)) -> (u32, u32) { fn rotate(dir: Direction, pos: (u32, u32)) -> (u32, u32) {
match dir { match dir {
Direction::Up => pos, Direction::Up => pos,

View file

@ -1,11 +1,10 @@
mod image; mod image;
mod print; mod print;
use std::collections::HashMap;
use ::image::RgbaImage;
use crate::prelude::*; use crate::prelude::*;
use ::image::RgbaImage;
pub use image::image_grid;
use std::collections::HashMap;
pub trait Visualize { pub trait Visualize {
fn visualize(&self) -> Visualization; fn visualize(&self) -> Visualization;
@ -20,7 +19,7 @@ pub trait Visualize {
let mut img = RgbaImage::new((v.size.x * 10) as u32, (v.size.y * 10) as u32); let mut img = RgbaImage::new((v.size.x * 10) as u32, (v.size.y * 10) as u32);
image::draw(v, &mut img); image::draw(&v, &mut img);
let mut f = std::fs::File::create(file).unwrap(); let mut f = std::fs::File::create(file).unwrap();
let _ = img.write_to(&mut f, ::image::ImageFormat::Png); let _ = img.write_to(&mut f, ::image::ImageFormat::Png);
@ -62,10 +61,6 @@ impl Symbol {
Symbol::Space => ' ', Symbol::Space => ' ',
} }
} }
// fn get_char(&self) -> char {
// self.get_str().chars().next().unwrap()
// }
} }
pub struct Visualization { pub struct Visualization {
@ -119,4 +114,8 @@ impl Visualization {
) { ) {
self.symbols.insert(pos, (symbol, fg, bg)); self.symbols.insert(pos, (symbol, fg, bg));
} }
pub fn size(&self) -> Position {
self.size
}
} }

View file

@ -3,7 +3,7 @@ use std::time::Instant;
use crate::belt_finding::common::PathField; use crate::belt_finding::common::PathField;
use crate::belt_finding::conflict_avoidance::ConflictAvoidance; use crate::belt_finding::conflict_avoidance::ConflictAvoidance;
use crate::common::visualize::{Color, Symbol, Visualization, Visualize}; use crate::common::visualize::{image_grid, Color, Symbol, Visualization, Visualize};
use crate::prelude::*; use crate::prelude::*;
use rand::{seq::SliceRandom, Rng}; use rand::{seq::SliceRandom, Rng};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -94,6 +94,10 @@ impl<'a> GeneticAlgorithm<'a> {
duration_mutate.as_secs_f32() duration_mutate.as_secs_f32()
); );
self.population[0].print_visualization(); self.population[0].print_visualization();
let v: Vec<_> = self.population.iter().map(|p| p.visualize()).collect();
let img = image_grid(&v, v[0].size().x as u32, v[0].size().y as u32, 5);
let mut file = std::fs::File::create("generation.png").unwrap();
img.write_to(&mut file, image::ImageFormat::Png).unwrap();
} }
pub fn output_population(&self) { pub fn output_population(&self) {