Bug fixes

This commit is contained in:
hal8174 2024-08-27 13:53:31 +02:00
parent be1d26ebd0
commit a11b39cf9f
8 changed files with 336 additions and 70 deletions

View file

@ -1,64 +1,34 @@
use clap::Parser;
use factorio_blueprint::{
belt_finding::{conflict_avoidance::ConflictAvoidance, Problem},
common::visualize::Visualize,
layout::Layout,
layout::{GeneticAlgorithm, Layout, PathLayout},
};
use rand::SeedableRng;
use rand::{rngs::SmallRng, SeedableRng};
#[derive(Debug, Parser)]
struct Args {
#[clap(default_value_t = 0)]
seed: u64,
}
fn main() {
// let mut p = Problem::new(Position::new(10, 10));
let args = Args::parse();
// let b1 = p.add_block(Position::new(3, 2));
// let b2 = p.add_block(Position::new(5, 2));
// let b3 = p.add_block(Position::new(5, 7));
// p.add_connection(b1, Position::new(1, 0), b2, Position::new(1, 0));
// p.add_connection(b2, Position::new(3, 1), b3, Position::new(4, 6));
let file = std::fs::File::open("layout.yml").unwrap();
let file = std::fs::File::open("layout2.yml").unwrap();
let p = serde_yaml::from_reader(file).unwrap();
for i in 0..1 {
let mut rng = rand::rngs::SmallRng::seed_from_u64(5);
let mut rng = SmallRng::seed_from_u64(args.seed);
let l = Layout::new(&p, &mut rng);
dbg!(&p);
// let s = l.score();
l.print_visualization();
let mut g = GeneticAlgorithm::new(&p, 20, 4, 2, &mut rng);
let m = l.mutate(&mut rng);
m.print_visualization();
let m = m.mutate(&mut rng);
m.print_visualization();
let m = m.mutate(&mut rng);
m.print_visualization();
let m = m.mutate(&mut rng);
m.print_visualization();
let m = m.mutate(&mut rng);
m.print_visualization();
let m = m.mutate(&mut rng);
m.print_visualization();
let m = m.mutate(&mut rng);
m.print_visualization();
let m = m.mutate(&mut rng);
m.print_visualization();
// let mut p = Problem::from_layout(&l);
// p.print();
// p.find_path();
// p.print();
// let mut c = ConflictAvoidance::new(p);
// c.remove_all_conflicts();
// c.print();
// println!("Seed: {i}, Score {}", s);
// l.print_visualization();
// if s < min {
// min = s;
// min_l = Some(l);
// }
for i in 0..100 {
println!("Generatrion {i}");
g.generation(&mut rng);
}
// g.output_population();
}

View file

@ -1,6 +1,6 @@
size:
x: 10
y: 10
x: 15
y: 15
blocks:
- size:
x: 3

61
layout2.yml Normal file
View file

@ -0,0 +1,61 @@
size:
x: 30
y: 30
blocks:
- size:
x: 3
y: 2
input:
- offset:
x: 1
y: 1
dir: Up
output:
- offset:
x: 1
y: 0
dir: Up
- size:
x: 5
y: 2
input:
output:
- offset:
x: 1
y: 1
dir: Down
- size:
x: 5
y: 7
input:
- offset:
x: 0
y: 1
dir: Right
output:
- size:
x: 5
y: 5
input:
- offset:
x: 0
y: 1
dir: Right
output:
- offset:
x: 0
y: 2
dir: Left
connections:
- startblock: 1
startpoint: 0
endblock: 0
endpoint: 0
- startblock: 0
startpoint: 0
endblock: 3
endpoint: 0
- startblock: 3
startpoint: 0
endblock: 2
endpoint: 0

View file

@ -62,6 +62,17 @@ impl PathField {
},
}
}
pub fn cost(&self) -> usize {
match self {
PathField::Belt { pos: _, dir: _ } => 300,
PathField::Underground {
pos: _,
dir: _,
len: _,
} => 1750,
}
}
}
pub fn print_map<F>(width: i32, height: i32, f: F) -> io::Result<()>

View file

@ -196,7 +196,7 @@ impl ConflictAvoidance {
if let Some(PathField::Underground { pos, dir, len }) = path.get(end_index + 1) {
if xrange.contains(&(pos.x as usize)) && yrange.contains(&(pos.y as usize)) {
let p = *pos - offset;
println!("Blocked {:?}", p);
// println!("Blocked {:?}", p);
if b.get_blocked(p.x as usize, p.y as usize) {
return None;
}
@ -247,8 +247,8 @@ impl ConflictAvoidance {
let mut b = b.build();
b.print();
self.print();
// b.print();
// self.print();
let mut min_cost = f64::INFINITY;
let mut solutions = Vec::new();
@ -317,6 +317,8 @@ impl ConflictAvoidance {
// println!();
// }
// self.print();
let mut candidates = Vec::new();
for y in 0..self.map.height {
@ -337,10 +339,17 @@ impl ConflictAvoidance {
if candidates.is_empty() {
return false;
}
// dbg!(&candidates);
loop {
candidates.sort_by_key(|c| -c.area());
let c = candidates.pop().unwrap();
// dbg!(&candidates);
let c = match candidates.pop() {
Some(c) => c,
None => {
return false;
}
};
self.range = Some((c.min.x..=c.max.x, c.min.y..=c.max.y));
@ -425,12 +434,27 @@ impl ConflictAvoidance {
if candidate != c && !candidates.iter().any(|c| c == &candidate) {
candidates.push(candidate);
}
// dbg!(&candidates);
}
}
pub fn remove_all_conflicts(&mut self) {
pub fn remove_all_conflicts(&mut self) -> bool {
while self.remove_conflict() {}
let mut conflicts: Map<bool> = Map::new(self.map.width, self.map.height);
for x in 0..self.map.width {
for y in 0..self.map.height {
if self.map.get(x, y).blocked {
if conflicts.get(x, y) == &true {
return false;
} else {
conflicts.set(x, y, true);
}
}
}
}
true
}
pub fn print(&self) {

View file

@ -2,6 +2,7 @@ use crate::common::color::COLORS;
use crate::graph::wheighted_graph::WheightedGraph;
use crate::layout::Layout;
use crate::misc::Map;
use crate::priority_queue::{BinaryHeap, Trace};
use crate::{
graph::wheighted_graph::shortest_path::dijkstra, priority_queue::fibonacci_heap::FibonacciHeap,
};
@ -225,18 +226,21 @@ impl<'a> WheightedGraph for MapInternal<'a> {
}
impl Problem {
pub fn find_path(&mut self) {
pub fn find_path(&mut self) -> bool {
for i in 0..self.start.len() {
self.calculate_wheights(i);
let m = MapInternal {
map: &self.map,
end: self.end[i],
};
let p = dijkstra::<MapInternal, FibonacciHeap<_>>(&m, self.start[i], self.end[i]);
let p = dijkstra::<MapInternal, BinaryHeap<_>>(&m, self.start[i], self.end[i]);
if let Some(p) = p {
self.path[i] = p;
} else {
return false;
}
}
true
}
}

View file

@ -1,8 +1,82 @@
use crate::belt_finding::common::PathField;
use crate::belt_finding::conflict_avoidance::ConflictAvoidance;
use crate::common::visualize::{Color, Symbol, Visualization, Visualize};
use crate::prelude::*;
use rand::{seq::SliceRandom, Rng};
use serde::{Deserialize, Serialize};
pub struct GeneticAlgorithm<'a> {
problem: &'a Problem,
population: Vec<PathLayout<'a>>,
population_size: usize,
population_keep: usize,
population_new: usize,
}
impl<'a> GeneticAlgorithm<'a> {
pub fn new<R: Rng + ?Sized>(
problem: &'a Problem,
population_size: usize,
population_keep: usize,
population_new: usize,
rng: &mut R,
) -> GeneticAlgorithm<'a> {
let mut population = Vec::new();
while population.len() < population_size {
if let Some(p) = PathLayout::new(Layout::new(problem, rng)) {
population.push(p);
}
}
population.sort_by_cached_key(|p| p.score());
println!("Best score: {}", population[0].score());
population[0].print_visualization();
GeneticAlgorithm {
problem,
population,
population_size,
population_keep,
population_new,
}
}
pub fn generation<R: Rng + ?Sized>(&mut self, rng: &mut R) {
for i in self.population_keep..(self.population_keep + self.population_new) {
loop {
if let Some(p) = PathLayout::new(Layout::new(self.problem, rng)) {
self.population[i] = p;
break;
}
}
}
for i in (self.population_keep + self.population_new)..self.population_size {
let j = i - (self.population_keep + self.population_new);
loop {
if let Some(p) = PathLayout::new(self.population[j].layout.mutate(rng)) {
self.population[i] = p;
break;
}
}
}
self.population.sort_by_cached_key(|p| p.score());
println!("Best score: {}", self.population[0].score());
self.population[0].print_visualization();
}
pub fn output_population(&self) {
println!("Population:");
for (i, p) in self.population.iter().enumerate() {
println!("{i:3}: {}", p.score());
p.print_visualization();
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub(crate) struct Block {
pub(crate) size: Position,
@ -40,6 +114,85 @@ pub struct Layout<'a> {
pub(crate) blocks: Vec<(Position, Direction)>,
}
pub struct PathLayout<'a> {
layout: Layout<'a>,
paths: Vec<Vec<PathField>>,
score: usize,
}
impl<'a> PathLayout<'a> {
pub fn new(layout: Layout<'a>) -> Option<PathLayout<'a>> {
layout.print_visualization();
let mut p = crate::belt_finding::Problem::from_layout(&layout);
if !p.find_path() {
return None;
}
p.print();
let mut c = ConflictAvoidance::new(p);
if !c.remove_all_conflicts() {
return None;
}
let paths = c.get_paths().to_vec();
let score = paths
.iter()
.map(|path| path.iter().skip(1).map(|p| p.cost()).sum::<usize>())
.sum();
Some(PathLayout {
layout,
paths,
score,
})
}
fn score(&self) -> usize {
self.score
}
}
impl<'a> Visualize for PathLayout<'a> {
fn visualize(&self) -> Visualization {
let mut v = self.layout.visualize();
let offset = self.layout.blocks.len();
for (i, path) in self.paths.iter().enumerate() {
for p in &path[1..] {
match p {
PathField::Belt { pos, dir } => {
v.add_symbol(
*pos,
Symbol::Arrow(*dir),
Some(Color::index(i + offset)),
None,
);
}
PathField::Underground { pos, dir, len } => {
v.add_symbol(
*pos,
Symbol::ArrowEnter(*dir),
Some(Color::index(i + offset)),
None,
);
v.add_symbol(
pos.in_direction(dir, *len as i32),
Symbol::ArrowEnter(*dir),
Some(Color::index(i + offset)),
None,
);
}
}
}
}
v
}
}
impl Problem {
pub fn new(size: Position) -> Self {
Self {

View file

@ -1,3 +1,4 @@
use std::fmt::Debug;
pub mod fibonacci_heap;
pub trait PriorityQueue<Item>
@ -17,7 +18,8 @@ where
#[derive(Debug)]
pub struct BinaryHeap<Item> {
data: Vec<Item>,
nextfree: usize,
data: Vec<(usize, Item)>,
}
impl<Item> BinaryHeap<Item>
@ -47,16 +49,16 @@ where
fn upheap(&mut self, index: usize) {
if index > 0 {
let parent = (index - 1) / 2;
if self.data[parent] > self.data[index] {
if self.data[parent].1 > self.data[index].1 {
self.data.swap(parent, index);
self.upheap(parent);
}
}
}
fn search(&self, item: &Item) -> Option<usize> {
fn search(&self, id: usize) -> Option<usize> {
for (i, d) in self.data.iter().enumerate() {
if d == item {
if d.0 == id {
return Some(i);
}
}
@ -68,12 +70,13 @@ impl<Item> PriorityQueue<Item> for BinaryHeap<Item>
where
Item: PartialOrd + Clone,
{
type Handle = Item;
type Handle = usize;
fn insert(&mut self, item: Item) -> Self::Handle {
self.data.push(item.clone());
self.data.push((self.nextfree, item.clone()));
self.upheap(self.data.len() - 1);
item
self.nextfree += 1;
self.nextfree - 1
}
fn pop_min(&mut self) -> Option<Item> {
@ -82,19 +85,59 @@ where
} else {
let d = self.data.swap_remove(0);
self.downheap(0);
Some(d)
Some(d.1)
}
}
fn decrease_key(&mut self, handle: &Self::Handle, f: impl Fn(&mut Item)) {
if let Some(index) = self.search(handle) {
f(&mut self.data[index]);
if let Some(index) = self.search(*handle) {
f(&mut self.data[index].1);
self.upheap(index);
}
}
fn new() -> Self {
Self { data: Vec::new() }
Self {
data: Vec::new(),
nextfree: 0,
}
}
}
#[derive(Debug)]
pub struct Trace<P> {
inner: P,
}
impl<P, I> PriorityQueue<I> for Trace<P>
where
I: PartialOrd + Clone + Debug,
P: PriorityQueue<I>,
{
type Handle = P::Handle;
fn new() -> Self {
println!("New priority queue.");
Self { inner: P::new() }
}
fn insert(&mut self, item: I) -> Self::Handle {
println!("Insert: {item:?}");
self.inner.insert(item)
}
fn pop_min(&mut self) -> Option<I> {
let min = self.inner.pop_min();
println!("Pop min: {min:?}");
min
}
fn decrease_key(&mut self, handle: &Self::Handle, f: impl Fn(&mut I)) {
self.inner.decrease_key(handle, |i| {
let old_i = i.clone();
f(i);
println!("Decrease key: {old_i:?} -> {i:?}");
})
}
}