diff --git a/src/input.rs b/src/input.rs index 2b48993..10476ad 100644 --- a/src/input.rs +++ b/src/input.rs @@ -25,10 +25,10 @@ fn read_stdin() -> InputData { let line = lines.next().unwrap(); let numbers = line.trim().split(' ').map(|x| x.parse::().unwrap()).collect::>(); 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::>().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::>().into(), vec![])); } - let home = lines.next().unwrap().trim().split(' ').map(|x| x.parse::().unwrap().into()).collect::>(); + let home = lines.next().unwrap().trim().split(' ').map(|x| x.parse::().unwrap().into()).collect::>(); InputData { start: Point::new(home[0], home[1]), diff --git a/src/main.rs b/src/main.rs index 627bdc5..4a6972e 100644 --- a/src/main.rs +++ b/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; -type Line = geo::Line; -type LineString = geo::LineString; -type Polygon = geo::Polygon; +type Point = geo::Point; +type Line = geo::Line; +type LineString = geo::LineString; +type Polygon = geo::Polygon; // 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 { - const STEPS: usize = 200; +fn float_range(a: f32, b: f32) -> impl Iterator { + 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::>(), 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 { 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![] }