Optimize intersection detection algorithm; use 32-bit floats
This commit is contained in:
parent
1b9b8ae007
commit
fe353e85fc
@ -25,10 +25,10 @@ fn read_stdin() -> InputData {
|
||||
let line = lines.next().unwrap();
|
||||
let numbers = line.trim().split(' ').map(|x| x.parse::<usize>().unwrap()).collect::<Vec<_>>();
|
||||
let corner_count = numbers[0];
|
||||
polygons.push(Polygon::new((0..corner_count).map(|idx| ((numbers[idx*2+1] as f64).into(), (numbers[idx*2+2] as f64).into())).collect::<Vec<_>>().into(), vec![]));
|
||||
polygons.push(Polygon::new((0..corner_count).map(|idx| ((numbers[idx*2+1] as f32).into(), (numbers[idx*2+2] as f32).into())).collect::<Vec<_>>().into(), vec![]));
|
||||
}
|
||||
|
||||
let home = lines.next().unwrap().trim().split(' ').map(|x| x.parse::<f64>().unwrap().into()).collect::<Vec<_>>();
|
||||
let home = lines.next().unwrap().trim().split(' ').map(|x| x.parse::<f32>().unwrap().into()).collect::<Vec<_>>();
|
||||
|
||||
InputData {
|
||||
start: Point::new(home[0], home[1]),
|
||||
|
102
src/main.rs
102
src/main.rs
@ -1,35 +1,33 @@
|
||||
use geo::*;
|
||||
use geo::prelude::*;
|
||||
|
||||
use decorum::R64;
|
||||
use decorum::Real;
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::BinaryHeap;
|
||||
|
||||
mod display;
|
||||
mod input;
|
||||
|
||||
type Point = geo::Point<R64>;
|
||||
type Line = geo::Line<R64>;
|
||||
type LineString = geo::LineString<R64>;
|
||||
type Polygon = geo::Polygon<R64>;
|
||||
type Point = geo::Point<f32>;
|
||||
type Line = geo::Line<f32>;
|
||||
type LineString = geo::LineString<f32>;
|
||||
type Polygon = geo::Polygon<f32>;
|
||||
|
||||
// 30 km/h = 1 units/unit
|
||||
// 15 km/h = 0.5 units/unit
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
struct RunState {
|
||||
/// Theoretically possible maximum delay
|
||||
delay: R64,
|
||||
delay: f32,
|
||||
/// Our current location
|
||||
pos: Point,
|
||||
/// Current location of the bus, not including any delays
|
||||
bus: Point
|
||||
}
|
||||
impl cmp::Eq for RunState {}
|
||||
impl cmp::Ord for RunState {
|
||||
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
||||
self.delay.cmp(&other.delay)
|
||||
self.delay.partial_cmp(&other.delay).unwrap()
|
||||
}
|
||||
}
|
||||
impl cmp::PartialOrd for RunState {
|
||||
@ -39,7 +37,7 @@ impl cmp::PartialOrd for RunState {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let bus = Point::new(0.0.into(), (-1300.0).into());
|
||||
let bus = Point::new(0.0.into(), (-2000.0).into());
|
||||
|
||||
let data = input::read_input();
|
||||
let house = data.start;
|
||||
@ -65,13 +63,23 @@ fn main() {
|
||||
let mut states = BinaryHeap::new();
|
||||
states.push(vec![start]);
|
||||
|
||||
let mut best_delay = R64::from(0.0);
|
||||
let mut best_delay = f32::from(0.0);
|
||||
let mut best = vec![];
|
||||
|
||||
while states.peek().map(|x| x.last().unwrap().delay > best_delay) == Some(true) {
|
||||
eprintln!(". {:?} states left", states.len());
|
||||
while states.peek().map(|x| x[0].delay > best_delay) == Some(true) {
|
||||
eprintln!(". {:?} states left:", states.len());
|
||||
/*
|
||||
if states.len() > 10 {
|
||||
for s in &states {
|
||||
eprintln!("{:?}", s);
|
||||
}
|
||||
panic!();
|
||||
}
|
||||
*/
|
||||
let s = states.pop().unwrap();
|
||||
let last = s.last().unwrap();
|
||||
let last = &s[0]; //s.last().unwrap();
|
||||
eprintln!("{},{}", last.pos.x(), last.pos.y());
|
||||
//eprintln!("{:?}", states.peek());
|
||||
|
||||
// new states
|
||||
let mut all = vec![];
|
||||
@ -81,10 +89,10 @@ fn main() {
|
||||
let next = Point::from(*next);
|
||||
if next != last.pos && none_intersect(&polys, &Line::new(last.pos, next)) {
|
||||
// could run to that point
|
||||
let bus_next = last.bus.translate(0.0.into(), distance(last.pos, next) * R64::from(2.0));
|
||||
let bus_next = last.bus.translate(0.0, distance(last.pos, next) * 2.0);
|
||||
let mut route = s.clone();
|
||||
eprintln!("{},{} would go {},{}", last.pos.x(), last.pos.y(), next.x(), next.y());
|
||||
route.push(RunState {
|
||||
//eprintln!("{},{} would go {},{}", last.pos.x(), last.pos.y(), next.x(), next.y());
|
||||
route.insert(0, RunState {
|
||||
pos: next,
|
||||
bus: bus_next,
|
||||
delay: max_possible_delay(bus_next, next)
|
||||
@ -94,13 +102,13 @@ fn main() {
|
||||
}
|
||||
// attempt to go to the bus, with varying delays
|
||||
let mut bus_reached = false;
|
||||
for delay in float_range(last.delay.into(), 0.0).map(R64::from) {
|
||||
for delay in float_range(last.delay.into(), 0.0).map(f32::from) {
|
||||
let bus = last.bus.translate(0.0.into(), delay);
|
||||
let range = to_bus(bus, last.pos);
|
||||
if range.len() == 2 {
|
||||
bus_reached = true; // TODO: what if effectively unreachable?
|
||||
let range = Line::new(range[0], range[1]);
|
||||
for percent in float_range(0.0, 1.0).map(R64::from) {
|
||||
for percent in float_range(0.0, 1.0).map(f32::from) {
|
||||
let mut next = range.start;
|
||||
next.x += range.dx() * percent;
|
||||
next.y += range.dy() * percent;
|
||||
@ -109,13 +117,14 @@ fn main() {
|
||||
if delay > best_delay {
|
||||
// new high score!
|
||||
let mut route = s.clone();
|
||||
route.push(RunState {
|
||||
route.insert(0, RunState {
|
||||
pos: next,
|
||||
bus: next,
|
||||
delay
|
||||
});
|
||||
eprintln!("# New best delay {:?}", delay);
|
||||
best = route;
|
||||
best.reverse();
|
||||
best_delay = delay;
|
||||
} else {
|
||||
// not worth it
|
||||
@ -125,6 +134,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
if bus_reached {
|
||||
//eprintln!("-> adding all to queue");
|
||||
states.extend(all);
|
||||
}
|
||||
|
||||
@ -146,20 +156,33 @@ fn main() {
|
||||
}
|
||||
|
||||
/// [a; b]
|
||||
fn float_range(a: f64, b: f64) -> impl Iterator<Item = f64> {
|
||||
const STEPS: usize = 200;
|
||||
fn float_range(a: f32, b: f32) -> impl Iterator<Item = f32> {
|
||||
const STEPS: usize = 25;
|
||||
let d = b - a;
|
||||
(0..=STEPS).map(move |s| a + ((s as f64) * d)/STEPS as f64)
|
||||
(0..=STEPS).map(move |s| a + ((s as f32) * d)/STEPS as f32)
|
||||
}
|
||||
|
||||
fn none_intersect(polys: &[Polygon], line: &Line) -> bool {
|
||||
/*
|
||||
if line.end.x != 0.0 {
|
||||
eprintln!("checking {:?}", line);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
if line.end.x > 0.0 {
|
||||
eprintln!("{:?}", line);
|
||||
}
|
||||
*/
|
||||
for p in polys {
|
||||
let mut middle = line.start;
|
||||
middle.x += line.dx() / 2.0;
|
||||
middle.y += line.dy() / 2.0;
|
||||
let middle: Point = middle.into();
|
||||
'poly: for p in polys {
|
||||
for l in p.exterior.lines().chain(vec![Line::new(p.exterior.0[0], *p.exterior.0.last().unwrap())]) {
|
||||
if (l.start == line.start && l.end == line.end) || (l.start == line.end && l.end == line.start) {
|
||||
// point is on polygon border
|
||||
continue 'poly;
|
||||
}
|
||||
if l.start == line.start || l.end == line.end || l.start == line.end || l.end == line.start {
|
||||
/*
|
||||
if line.end.x > 0.0 {
|
||||
@ -174,25 +197,38 @@ fn none_intersect(polys: &[Polygon], line: &Line) -> bool {
|
||||
}
|
||||
*/
|
||||
if l.intersects(line) {
|
||||
/*
|
||||
if line.end.x != 0.0 {
|
||||
eprintln!("{:?} intersects {:?}", l, line);
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if p.euclidean_distance(&middle) == 0.0 {
|
||||
/*
|
||||
if line.end.x != 0.0 {
|
||||
eprintln!("{:?} is in polygon {:?}, contains = {}", middle, p.exterior.lines().collect::<Vec<_>>(), p.contains(&middle));
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn distance(a: Point, b: Point) -> R64 {
|
||||
fn distance(a: Point, b: Point) -> f32 {
|
||||
((a.x() - b.x()).powi(2) + (a.y() - b.y()).powi(2)).sqrt()
|
||||
}
|
||||
|
||||
fn max_possible_delay(bus: Point, start: Point) -> R64 {
|
||||
fn max_possible_delay(bus: Point, start: Point) -> f32 {
|
||||
let a = start.x();
|
||||
let b = start.y();
|
||||
let c = bus.x();
|
||||
assert_eq!(c, 0.0);
|
||||
let d = bus.y();
|
||||
|
||||
b - ((a.powi(2)) * R64::from(3.0)).sqrt() - d
|
||||
b - ((a.powi(2)) * f32::from(3.0)).sqrt() - d
|
||||
}
|
||||
|
||||
// Go straight to the bus. Returns the points where the bus can be reached.
|
||||
@ -202,15 +238,15 @@ fn to_bus(bus: Point, start: Point) -> Vec<Point> {
|
||||
let c = bus.x();
|
||||
let d = bus.y();
|
||||
|
||||
let v: R64 = -a.powi(2) * R64::from(3.0) + R64::from(6.0) * a * c + b.powi(2) - R64::from(2.0) * b * d - R64::from(3.0) * c.powi(2) + d.powi(2);
|
||||
let v: f32 = -a.powi(2) * f32::from(3.0) + f32::from(6.0) * a * c + b.powi(2) - f32::from(2.0) * b * d - f32::from(3.0) * c.powi(2) + d.powi(2);
|
||||
if v >= 0.0 {
|
||||
// v = sqrt(-3 A^2 + 6 A C + B^2 - 2 B D - 3 C^2 + D^2)
|
||||
let v = v.sqrt();
|
||||
// x = 1/3 (+-v + 2 B - 2 D)
|
||||
let x1: R64 = (v + R64::from(2.0) * b - R64::from(2.0) * d) / R64::from(3.0);
|
||||
let x2: R64 = (-v + R64::from(2.0) * b - R64::from(2.0) * d) / R64::from(3.0);
|
||||
if x1 > R64::from(0.0) && x2 > R64::from(0.0) {
|
||||
vec![bus.translate(0.0.into(), R64::from(2.0) * x1), bus.translate(0.0.into(), R64::from(2.0) * x2)]
|
||||
let x1: f32 = (v + f32::from(2.0) * b - f32::from(2.0) * d) / f32::from(3.0);
|
||||
let x2: f32 = (-v + f32::from(2.0) * b - f32::from(2.0) * d) / f32::from(3.0);
|
||||
if x1 > f32::from(0.0) && x2 > f32::from(0.0) {
|
||||
vec![bus.translate(0.0.into(), f32::from(2.0) * x1), bus.translate(0.0.into(), f32::from(2.0) * x2)]
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user