Final code commit
This commit is contained in:
parent
0ab21f8d42
commit
89ad12842d
722
src/main.rs
722
src/main.rs
@ -3,14 +3,12 @@ use rand::distributions::{Bernoulli, Distribution};
|
||||
use rand::prelude::*;
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::BinaryHeap;
|
||||
use std::f32;
|
||||
use std::f32::consts::PI;
|
||||
|
||||
mod display;
|
||||
mod input;
|
||||
|
||||
type Coordinate = geo::Coordinate<f32>;
|
||||
type Triangle = geo::Triangle<f32>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -38,32 +36,7 @@ impl cmp::PartialOrd for World {
|
||||
}
|
||||
|
||||
fn random_world(rng: &mut SmallRng, tris: &mut Vec<Triangle>, angles: &mut [f32], flips: &mut Vec<bool>) -> World {
|
||||
//tris.shuffle(rng);
|
||||
*tris = vec![tris[0], tris[9], tris[12], tris[6], tris[1], tris[4], tris[5], tris[13], tris[7], tris[15], tris[12], tris[2], tris[22], tris[18], tris[20], tris[17], tris[19], tris[3], tris[21], tris[16], tris[14], tris[8], tris[10]];
|
||||
*flips = vec![true, false, true, true, false, false, false, true, false, true, false, true, false, true, true, false, true, false, false, true, false, false, false];
|
||||
angles[0] = 0.9 * PI;
|
||||
angles[1] = 1.4 * PI;
|
||||
angles[2] = 1.3 * PI;
|
||||
angles[3] = 1.4 * PI;
|
||||
angles[4] = 0.5 * PI;
|
||||
angles[5] = PI;
|
||||
angles[6] = 0.0;
|
||||
angles[7] = PI;
|
||||
angles[8] = 0.8 * PI;
|
||||
angles[9] = 0.1 * PI;
|
||||
angles[10] = 0.05 * PI;
|
||||
angles[11] = 0.0;
|
||||
angles[12] = 1.7 * PI;
|
||||
angles[13] = 0.5 * PI;
|
||||
angles[14] = 0.0;
|
||||
angles[15] = PI;
|
||||
angles[16] = 1.5 * PI;
|
||||
angles[17] = 1.1 * PI;
|
||||
angles[18] = PI;
|
||||
angles[19] = PI;
|
||||
angles[20] = 0.0;
|
||||
angles[21] = 2.0 * PI;
|
||||
angles[22] = PI;
|
||||
tris.shuffle(rng);
|
||||
let mut world = World { tris: Vec::with_capacity(tris.len()), width: 0.0 };
|
||||
for (idx, tri) in tris.iter().enumerate() {
|
||||
let mut tri = *tri;
|
||||
@ -227,13 +200,11 @@ fn optimize(iters: usize, best_all: &mut f32, best_width: &mut f32, tris: &[Tria
|
||||
for a in &mut angles {
|
||||
*a += rng.gen_range(-0.2, 0.2);
|
||||
}
|
||||
/*
|
||||
for f in &mut flips {
|
||||
if flip_choice.sample(rng) {
|
||||
*f = !*f;
|
||||
}
|
||||
}
|
||||
*/
|
||||
// construct new world
|
||||
let new = construct_world(tris, &angles, &flips);
|
||||
if new.width < *best_width {
|
||||
@ -280,661 +251,6 @@ fn optimize(iters: usize, best_all: &mut f32, best_width: &mut f32, tris: &[Tria
|
||||
best
|
||||
}
|
||||
|
||||
#[allow(clippy::cyclomatic_complexity)]
|
||||
pub fn main_old() {
|
||||
let tris = input::read_input();
|
||||
let count_tris = tris.len();
|
||||
let tris = transformations(&tris);
|
||||
|
||||
let save_prefix = "tri_";
|
||||
let mut save_counter = 0;
|
||||
let mut normalized_tris = Vec::with_capacity(tris.len() * 2);
|
||||
let mut left_tris = Vec::with_capacity(tris.len());
|
||||
for (mut idx, t) in tris.into_iter().enumerate() {
|
||||
idx /= 6;
|
||||
let prev_angle = angle_of(t, t.1);
|
||||
let mut added = false;
|
||||
let rotated = rotate(t, 0.5 * PI - prev_angle);
|
||||
if rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
let rotated = rotate(rotated, PI);
|
||||
if !added
|
||||
&& rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
let rotated = rotate(t, -0.5 * PI + prev_angle);
|
||||
if !added
|
||||
&& rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
let rotated = rotate(rotated, PI);
|
||||
if !added
|
||||
&& rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
}
|
||||
let prev_angle = angle_of(t, t.2);
|
||||
added = false;
|
||||
let rotated = rotate(t, 0.5 * PI - prev_angle);
|
||||
if rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
let rotated = rotate(rotated, PI);
|
||||
if !added
|
||||
&& rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
let rotated = rotate(t, -0.5 * PI + prev_angle);
|
||||
if !added
|
||||
&& rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
let rotated = rotate(rotated, PI);
|
||||
if !added
|
||||
&& rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (_idx, t) in &normalized_tris {
|
||||
display::save_tri(&format!("{}{}.svg", save_prefix, save_counter), *t);
|
||||
save_counter += 1;
|
||||
}
|
||||
let save_prefix = "start_";
|
||||
save_counter = 0;
|
||||
let mut worlds = BinaryHeap::new();
|
||||
|
||||
for t in &left_tris {
|
||||
let mut world = World {
|
||||
tris: vec![*t],
|
||||
width: 0.0,
|
||||
};
|
||||
world.normalize();
|
||||
display::save_world(&format!("{}{}.svg", save_prefix, save_counter), &world);
|
||||
save_counter += 1;
|
||||
worlds.push(world);
|
||||
}
|
||||
|
||||
let mut best = World {
|
||||
tris: vec![],
|
||||
width: f32::MAX,
|
||||
};
|
||||
let save_prefix = "world_";
|
||||
save_counter = 0;
|
||||
let mut counter = 0;
|
||||
while !worlds.is_empty() {
|
||||
counter += 1;
|
||||
if counter % 1000 == 0 {
|
||||
println!("{}/∞", counter);
|
||||
}
|
||||
let w = worlds.pop().unwrap();
|
||||
//println!("working");
|
||||
if w.width >= best.width {
|
||||
continue;
|
||||
}
|
||||
//println!("s: {:?}", w);
|
||||
|
||||
/*
|
||||
if save_counter < 1000000 {
|
||||
display::save_world(&format!("{}a_{}.svg", save_prefix, save_counter), &w);
|
||||
}
|
||||
*/
|
||||
let save_iterations = false;
|
||||
|
||||
let mut new = vec![];
|
||||
for (next_idx, next_tri) in left_tris
|
||||
.iter()
|
||||
.filter(|(idx1, _tri)| w.tris.iter().all(|(idx2, _tri)| idx1 != idx2))
|
||||
{
|
||||
let next_tri = *next_tri;
|
||||
for (idx, &(_base_idx, base_tri)) in w.tris.iter().enumerate() {
|
||||
let base_tris = &w.tris[0..=idx];
|
||||
let mut neww = w.clone();
|
||||
let free_angle = right_of(base_tri);
|
||||
let next_angle = left_of(next_tri);
|
||||
let target = next_angle - PI + free_angle;
|
||||
let original_tri = next_tri;
|
||||
let mut next_tri = rotate(next_tri, target);
|
||||
if next_tri.0.y < 0.0 || next_tri.1.y < 0.0 || next_tri.2.y < 0.0 {
|
||||
let miny = min(next_tri.0.y, min(next_tri.1.y, next_tri.2.y));
|
||||
next_tri.0.y -= miny;
|
||||
next_tri.1.y -= miny;
|
||||
next_tri.2.y -= miny;
|
||||
}
|
||||
for &delta in &[
|
||||
/*80.0, 30.0, 10.0, 5.0,*/ 1.0, 0.6, 0.32, 0.18, 0.1, 0.06, 0.03, 0.01,
|
||||
0.003,
|
||||
] {
|
||||
let initial_state = base_tris.iter().any(|(_, x)| x.intersects(&next_tri));
|
||||
let dx = if initial_state { delta } else { -delta };
|
||||
while base_tris.iter().any(|(_, x)| x.intersects(&next_tri)) == initial_state {
|
||||
next_tri.0.x += dx;
|
||||
next_tri.1.x += dx;
|
||||
next_tri.2.x += dx;
|
||||
}
|
||||
}
|
||||
neww.tris.insert(idx+1, (*next_idx, next_tri));
|
||||
if idx + 1 != neww.tris.len() - 1 {
|
||||
for &delta in &[
|
||||
/*80.0, 30.0, 10.0, 5.0,*/ 1.0, 0.6, 0.32, 0.18, 0.1, 0.06, 0.03, 0.01,
|
||||
0.003,
|
||||
] {
|
||||
let initial_state = neww.tris[0..=idx+1].iter().any(|(_, x)| neww.tris[idx+2..].iter().any(|(_, y)| x.intersects(y)));
|
||||
let dx = if initial_state { delta } else { -delta };
|
||||
while neww.tris[0..=idx+1].iter().any(|(_, x)| neww.tris[idx+2..].iter().any(|(_, y)| x.intersects(y))) == initial_state {
|
||||
for (_, tri) in &mut neww.tris[idx+2..] {
|
||||
tri.0.x += dx;
|
||||
tri.1.x += dx;
|
||||
tri.2.x += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
neww.normalize();
|
||||
neww.calc_width();
|
||||
if save_iterations {
|
||||
display::save_world(&format!("{}b_{}.svg", save_prefix, save_counter), &neww);
|
||||
}
|
||||
if neww.tris.len() == count_tris {
|
||||
if neww.width < best.width {
|
||||
println!("[{}] new best: {}", save_counter, neww.width);
|
||||
//println!("{:?}", w.tris);
|
||||
display::save_world(
|
||||
&format!("{}best_{}.svg", save_prefix, save_counter),
|
||||
&neww,
|
||||
);
|
||||
best = neww;
|
||||
}
|
||||
} else if neww.width < best.width {
|
||||
//w.width -= (2.0 * PI - free_angle - next_angle) * 0.01;
|
||||
//if (angle > 50 && angle < 55) || (angle > 88 && angle < 92) {
|
||||
//println!("{:?} -> {:?}", angle, w.width);
|
||||
//}
|
||||
new.push(neww);
|
||||
}
|
||||
save_counter += 1;
|
||||
|
||||
let mut neww = w.clone();
|
||||
let mut next_tri = original_tri;
|
||||
for &delta in &[
|
||||
/*80.0, 30.0, 10.0, 5.0,*/ 1.0, 0.6, 0.32, 0.18, 0.1, 0.06, 0.03, 0.01,
|
||||
0.003,
|
||||
] {
|
||||
let initial_state = base_tris.iter().any(|(_, x)| x.intersects(&next_tri));
|
||||
let dx = if initial_state { delta } else { -delta };
|
||||
while base_tris.iter().any(|(_, x)| x.intersects(&next_tri)) == initial_state {
|
||||
next_tri.0.x += dx;
|
||||
next_tri.1.x += dx;
|
||||
next_tri.2.x += dx;
|
||||
}
|
||||
}
|
||||
neww.tris.insert(idx+1, (*next_idx, next_tri));
|
||||
if idx + 1 != neww.tris.len() - 1 {
|
||||
for &delta in &[
|
||||
/*80.0, 30.0, 10.0, 5.0,*/ 1.0, 0.6, 0.32, 0.18, 0.1, 0.06, 0.03, 0.01,
|
||||
0.003,
|
||||
] {
|
||||
let initial_state = neww.tris[0..=idx+1].iter().any(|(_, x)| neww.tris[idx+2..].iter().any(|(_, y)| x.intersects(y)));
|
||||
let dx = if initial_state { delta } else { -delta };
|
||||
while neww.tris[0..=idx+1].iter().any(|(_, x)| neww.tris[idx+2..].iter().any(|(_, y)| x.intersects(y))) == initial_state {
|
||||
for (_, tri) in &mut neww.tris[idx+2..] {
|
||||
tri.0.x += dx;
|
||||
tri.1.x += dx;
|
||||
tri.2.x += dx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
neww.normalize();
|
||||
neww.calc_width();
|
||||
if save_iterations {
|
||||
display::save_world(&format!("{}b_{}.svg", save_prefix, save_counter), &neww);
|
||||
}
|
||||
if neww.tris.len() == count_tris {
|
||||
if neww.width < best.width {
|
||||
println!("[{}] new best: {}", save_counter, neww.width);
|
||||
//println!("{:?}", w.tris);
|
||||
display::save_world(
|
||||
&format!("{}best_{}.svg", save_prefix, save_counter),
|
||||
&neww,
|
||||
);
|
||||
best = neww;
|
||||
}
|
||||
} else if neww.width < best.width {
|
||||
//w.width -= (2.0 * PI - free_angle - next_angle) * 0.01;
|
||||
//if (angle > 50 && angle < 55) || (angle > 88 && angle < 92) {
|
||||
//println!("{:?} -> {:?}", angle, w.width);
|
||||
//}
|
||||
new.push(neww);
|
||||
}
|
||||
save_counter += 1;
|
||||
|
||||
let free_angle = left_of(base_tri);
|
||||
let next_angle = right_of(next_tri);
|
||||
let target = (free_angle - next_angle).to_degrees();
|
||||
}
|
||||
/*
|
||||
//println!("trying {:?}", next_idx);
|
||||
let (last_idx, last_tri) = *w.tris.last().unwrap();
|
||||
|
||||
let free_angle = right_of(last_tri);
|
||||
|
||||
let next_angle = left_of(next_tri);
|
||||
|
||||
//println!("{:?} -> {:?}: {:?} {:?}", last_idx, next_idx, free_angle.to_degrees(), next_angle.to_degrees());
|
||||
let target = (next_angle - PI + free_angle).to_degrees();
|
||||
for angle in [0.0] {
|
||||
//println!("angle {:?}", angle);
|
||||
let radians = angle.to_radians();
|
||||
let next_angle = next_angle - radians;
|
||||
let mut tri = rotate(next_tri, radians);
|
||||
|
||||
// "binary search"-like optimization here
|
||||
for &delta in &[
|
||||
/*80.0, 30.0, 10.0, 5.0,*/ 1.0, 0.6, 0.32, 0.18, 0.1, 0.06, 0.03, 0.01,
|
||||
0.003,
|
||||
] {
|
||||
let initial_state = last_tri.intersects(&tri);
|
||||
let dx = if initial_state { delta } else { -delta };
|
||||
while last_tri.intersects(&tri) == initial_state {
|
||||
tri.0.x += dx;
|
||||
tri.1.x += dx;
|
||||
tri.2.x += dx;
|
||||
}
|
||||
}
|
||||
let mut w = w.clone();
|
||||
w.tris.push((*next_idx, tri));
|
||||
w.normalize();
|
||||
w.calc_width();
|
||||
if save_iterations {
|
||||
display::save_world(&format!("{}b_{}.svg", save_prefix, save_counter), &w);
|
||||
}
|
||||
if w.tris.len() == count_tris {
|
||||
if w.width < best.width {
|
||||
println!("[{}] new best: {}", save_counter, w.width);
|
||||
//println!("{:?}", w.tris);
|
||||
display::save_world(
|
||||
&format!("{}best_{}.svg", save_prefix, save_counter),
|
||||
&w,
|
||||
);
|
||||
best = w;
|
||||
}
|
||||
} else if w.width < best.width {
|
||||
w.width -= (2.0 * PI - free_angle - next_angle) * 0.01;
|
||||
//if (angle > 50 && angle < 55) || (angle > 88 && angle < 92) {
|
||||
//println!("{:?} -> {:?}", angle, w.width);
|
||||
//}
|
||||
new.push(w);
|
||||
}
|
||||
save_counter += 1;
|
||||
}
|
||||
*/
|
||||
}
|
||||
worlds.extend(new);
|
||||
}
|
||||
println!("best width = {:?}", best.width);
|
||||
display::save_world("world_best.svg", &best);
|
||||
}
|
||||
|
||||
fn left_of(tri: Triangle) -> f32 {
|
||||
let vertex1 = tri.1;
|
||||
let vertex2 = tri.2;
|
||||
|
||||
let next_angle = if vertex1.y > 0.001 && vertex2.y > 0.001 {
|
||||
let angle1 = 0.5 * PI + vertex1.x.signum() * (vertex1.x.abs() / vertex1.y).atan();
|
||||
let angle2 = 0.5 * PI + vertex2.x.signum() * (vertex2.x.abs() / vertex2.y).atan();
|
||||
min(angle1, angle2)
|
||||
} else if vertex1.y < 0.001 {
|
||||
0.5 * PI + vertex2.x.signum() * (vertex2.x.abs() / vertex2.y).atan()
|
||||
} else {
|
||||
0.5 * PI + vertex1.x.signum() * (vertex1.x.abs() / vertex1.y).atan()
|
||||
};
|
||||
next_angle
|
||||
}
|
||||
|
||||
fn right_of(tri: Triangle) -> f32 {
|
||||
let vertex1 = tri.1;
|
||||
let vertex2 = tri.2;
|
||||
|
||||
let free_angle = if vertex1.y > 0.001 && vertex2.y < 0.001 {
|
||||
PI - (vertex1.y / (vertex2.x - vertex1.x).abs()).atan()
|
||||
} else if vertex2.y > 0.001 && vertex1.y < 0.001 {
|
||||
PI - (vertex2.y / (vertex2.x - vertex1.x).abs()).atan()
|
||||
} else {
|
||||
let angle1 = 0.5 * PI - vertex1.x.signum() * (vertex1.x.abs() / vertex1.y).atan();
|
||||
let angle2 = 0.5 * PI - vertex2.x.signum() * (vertex2.x.abs() / vertex2.y).atan();
|
||||
min(angle1, angle2)
|
||||
};
|
||||
free_angle
|
||||
}
|
||||
|
||||
/*
|
||||
fn main2() {
|
||||
let tris = input::read_input();
|
||||
let count_tris = tris.len();
|
||||
let tris = transformations(&tris);
|
||||
|
||||
let save_prefix = "tri_";
|
||||
let mut save_counter = 0;
|
||||
let mut normalized_tris = Vec::with_capacity(tris.len() * 2);
|
||||
let mut left_tris = Vec::with_capacity(tris.len());
|
||||
for (mut idx, t) in tris.into_iter().enumerate() {
|
||||
idx /= 6;
|
||||
let prev_angle = angle_of(t, t.1);
|
||||
let mut added = false;
|
||||
let rotated = rotate(t, 0.5 * PI - prev_angle);
|
||||
if rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
let rotated = rotate(rotated, PI);
|
||||
if !added
|
||||
&& rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
let rotated = rotate(t, -0.5 * PI + prev_angle);
|
||||
if !added
|
||||
&& rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
let rotated = rotate(rotated, PI);
|
||||
if !added
|
||||
&& rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
}
|
||||
let prev_angle = angle_of(t, t.2);
|
||||
added = false;
|
||||
let rotated = rotate(t, 0.5 * PI - prev_angle);
|
||||
if rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
let rotated = rotate(rotated, PI);
|
||||
if !added
|
||||
&& rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
let rotated = rotate(t, -0.5 * PI + prev_angle);
|
||||
if !added
|
||||
&& rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
added = true;
|
||||
}
|
||||
let rotated = rotate(rotated, PI);
|
||||
if !added
|
||||
&& rotated.1.y >= -0.001
|
||||
&& rotated.2.y >= -0.001
|
||||
&& (rotated.1.y < 0.1 || rotated.2.y < 0.1)
|
||||
{
|
||||
normalized_tris.push((idx, rotated));
|
||||
if rotated.1.x > -0.001 && rotated.2.x > -0.001 {
|
||||
left_tris.push((idx, rotated));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (_idx, t) in &normalized_tris {
|
||||
display::save_tri(&format!("{}{}.svg", save_prefix, save_counter), *t);
|
||||
save_counter += 1;
|
||||
}
|
||||
let save_prefix = "start_";
|
||||
save_counter = 0;
|
||||
let mut worlds = BinaryHeap::new();
|
||||
//let left_tris = vec![left_tris[1], left_tris[11], left_tris[17], left_tris[22], left_tris[28]];
|
||||
for t in &left_tris {
|
||||
let mut world = World {
|
||||
tris: vec![*t],
|
||||
width: 0.0,
|
||||
};
|
||||
world.normalize();
|
||||
display::save_world(&format!("{}{}.svg", save_prefix, save_counter), &world);
|
||||
save_counter += 1;
|
||||
worlds.push(world);
|
||||
}
|
||||
|
||||
let mut best = World {
|
||||
tris: vec![],
|
||||
width: f32::MAX,
|
||||
};
|
||||
let save_prefix = "world_";
|
||||
save_counter = 0;
|
||||
let mut counter = 0;
|
||||
let mut bins = Vec::new();
|
||||
bins.push(worlds);
|
||||
let mut progress = true;
|
||||
while progress {
|
||||
progress = false;
|
||||
for bin_idx in 0..bins.len() {
|
||||
counter += 1;
|
||||
if counter % 10000 == 0 {
|
||||
println!("{}/∞", counter);
|
||||
}
|
||||
if bins[bin_idx].is_empty() {
|
||||
continue;
|
||||
}
|
||||
let w = bins[bin_idx].pop().unwrap();
|
||||
//println!("working");
|
||||
if w.width >= best.width {
|
||||
continue;
|
||||
}
|
||||
//println!("s: {:?}", w);
|
||||
|
||||
/*
|
||||
if save_counter < 1000000 {
|
||||
display::save_world(&format!("{}a_{}.svg", save_prefix, save_counter), &w);
|
||||
}
|
||||
*/
|
||||
let save_iterations = false;
|
||||
|
||||
let mut new = vec![];
|
||||
for (next_idx, next_tri) in left_tris
|
||||
.iter()
|
||||
.filter(|(idx1, _tri)| w.tris.iter().all(|(idx2, _tri)| idx1 != idx2))
|
||||
{
|
||||
//println!("trying {:?}", next_idx);
|
||||
let (last_idx, last_tri) = *w.tris.last().unwrap();
|
||||
|
||||
let vertex1 = last_tri.1;
|
||||
let vertex2 = last_tri.2;
|
||||
|
||||
let free_angle = if vertex1.y > 0.001 && vertex2.y < 0.001 {
|
||||
PI - (vertex1.y / (vertex2.x - vertex1.x).abs()).atan()
|
||||
} else if vertex2.y > 0.001 && vertex1.y < 0.001 {
|
||||
PI - (vertex2.y / (vertex2.x - vertex1.x).abs()).atan()
|
||||
} else {
|
||||
let angle1 =
|
||||
0.5 * PI - vertex1.x.signum() * (vertex1.x.abs() / vertex1.y).atan();
|
||||
let angle2 =
|
||||
0.5 * PI - vertex2.x.signum() * (vertex2.x.abs() / vertex2.y).atan();
|
||||
min(angle1, angle2)
|
||||
};
|
||||
|
||||
let vertex1 = next_tri.1;
|
||||
let vertex2 = next_tri.2;
|
||||
|
||||
let next_angle = if vertex1.y > 0.001 && vertex2.y > 0.001 {
|
||||
let angle1 =
|
||||
0.5 * PI + vertex1.x.signum() * (vertex1.x.abs() / vertex1.y).atan();
|
||||
let angle2 =
|
||||
0.5 * PI + vertex2.x.signum() * (vertex2.x.abs() / vertex2.y).atan();
|
||||
min(angle1, angle2)
|
||||
} else if vertex1.y < 0.001 {
|
||||
0.5 * PI + vertex2.x.signum() * (vertex2.x.abs() / vertex2.y).atan()
|
||||
} else {
|
||||
0.5 * PI + vertex1.x.signum() * (vertex1.x.abs() / vertex1.y).atan()
|
||||
};
|
||||
//println!("{:?} -> {:?}: {:?} {:?}", last_idx, next_idx, free_angle.to_degrees(), next_angle.to_degrees());
|
||||
let target = (next_angle - PI + free_angle).to_degrees();
|
||||
let step = 40.0;
|
||||
let as_f32 = |x| x as f32 * step;
|
||||
let range = if target >= 0.0 {
|
||||
(0..=((target - 0.0001) / step) as usize)
|
||||
.map(as_f32)
|
||||
.chain(Some(target))
|
||||
} else {
|
||||
(0..=((next_angle - 0.0001) / step) as usize)
|
||||
.map(as_f32)
|
||||
.chain(None)
|
||||
};
|
||||
|
||||
for angle in range {
|
||||
//println!("angle {:?}", angle);
|
||||
let radians = angle.to_radians();
|
||||
let next_angle = next_angle - radians;
|
||||
let mut tri = rotate(*next_tri, radians);
|
||||
|
||||
// "binary search"-like optimization here
|
||||
for &delta in &[
|
||||
/*80.0, 30.0, 10.0, 5.0,*/ 1.0, 0.6, 0.32, 0.18, 0.1, 0.06, 0.03,
|
||||
0.01, 0.003,
|
||||
] {
|
||||
let initial_state = last_tri.intersects(&tri);
|
||||
let dx = if initial_state { delta } else { -delta };
|
||||
while last_tri.intersects(&tri) == initial_state {
|
||||
tri.0.x += dx;
|
||||
tri.1.x += dx;
|
||||
tri.2.x += dx;
|
||||
}
|
||||
}
|
||||
let mut w = w.clone();
|
||||
w.tris.push((*next_idx, tri));
|
||||
w.normalize();
|
||||
w.calc_width();
|
||||
if save_iterations {
|
||||
display::save_world(&format!("{}b_{}.svg", save_prefix, save_counter), &w);
|
||||
}
|
||||
if w.tris.len() == count_tris {
|
||||
if w.width < best.width {
|
||||
println!("[{}] new best: {}", save_counter, w.width);
|
||||
//println!("{:?}", w.tris);
|
||||
display::save_world(
|
||||
&format!("{}best_{}.svg", save_prefix, save_counter),
|
||||
&w,
|
||||
);
|
||||
best = w;
|
||||
}
|
||||
} else if w.width < best.width {
|
||||
w.width -= (2.0 * PI - free_angle - next_angle) * 0.01;
|
||||
//if (angle > 50 && angle < 55) || (angle > 88 && angle < 92) {
|
||||
//println!("{:?} -> {:?}", angle, w.width);
|
||||
//}
|
||||
new.push(w);
|
||||
}
|
||||
save_counter += 1;
|
||||
}
|
||||
}
|
||||
progress = true;
|
||||
if bin_idx + 1 == bins.len() {
|
||||
let mut new_bin = BinaryHeap::new();
|
||||
new_bin.extend(new);
|
||||
bins.push(new_bin);
|
||||
} else {
|
||||
bins[bin_idx + 1].extend(new);
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("best width = {:?}", best.width);
|
||||
display::save_world("world_best.svg", &best);
|
||||
}
|
||||
*/
|
||||
|
||||
impl World {
|
||||
fn normalize(&mut self) {
|
||||
let mut maxx = 0.0;
|
||||
@ -1003,42 +319,6 @@ fn rotate(mut tri: Triangle, angle: f32) -> Triangle {
|
||||
tri
|
||||
}
|
||||
|
||||
fn angle_of(_tri: Triangle, point: Coordinate) -> f32 {
|
||||
let d = (point.x.powi(2) + point.y.powi(2)).sqrt();
|
||||
(point.y / d).acos()
|
||||
}
|
||||
|
||||
fn transformations(tris: &[Triangle]) -> Vec<Triangle> {
|
||||
let mut new: Vec<Triangle> = Vec::with_capacity(tris.len() * 6);
|
||||
for t in tris {
|
||||
let n = [
|
||||
(0.0, 0.0),
|
||||
(t.1.x - t.0.x, t.1.y - t.0.y),
|
||||
(t.2.x - t.0.x, t.2.y - t.0.y),
|
||||
].into();
|
||||
new.push(n);
|
||||
let n = [[-n.0.x, n.0.y], [-n.1.x, n.1.y], [-n.2.x, n.2.y]].into();
|
||||
new.push(n);
|
||||
let n = [
|
||||
(0.0, 0.0),
|
||||
(t.2.x - t.1.x, t.2.y - t.1.y),
|
||||
(t.0.x - t.1.x, t.0.y - t.1.y),
|
||||
].into();
|
||||
new.push(n);
|
||||
let n = [[-n.0.x, n.0.y], [-n.1.x, n.1.y], [-n.2.x, n.2.y]].into();
|
||||
new.push(n);
|
||||
let n = [
|
||||
(0.0, 0.0),
|
||||
(t.0.x - t.2.x, t.0.y - t.2.y),
|
||||
(t.1.x - t.2.x, t.1.y - t.2.y),
|
||||
].into();
|
||||
new.push(n);
|
||||
let n = [[-n.0.x, n.0.y], [-n.1.x, n.1.y], [-n.2.x, n.2.y]].into();
|
||||
new.push(n);
|
||||
}
|
||||
new
|
||||
}
|
||||
|
||||
fn min(a: f32, b: f32) -> f32 {
|
||||
if a < b {
|
||||
a
|
||||
|
Loading…
Reference in New Issue
Block a user