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