diff --git a/src/display.rs b/src/display.rs index ef05950..fd8e99c 100644 --- a/src/display.rs +++ b/src/display.rs @@ -74,6 +74,7 @@ pub(crate) fn dump_latex_code(route: &[RunState], polys: &[Polygon]) { println!("\\end{{tikzpicture}}"); } +/* pub(crate) fn dump_route(house: Point, polys: &[Polygon], route: &Vec) { let (points, lines, route1, route2_start) = gen_params(house, route); print!( @@ -243,3 +244,4 @@ pub(crate) fn generate_svg( document.to_string() } +*/ diff --git a/src/main.rs b/src/main.rs index 7961c5d..ba23aa6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,8 +23,8 @@ struct RunState { delay: f64, /// Lisas Position pos: Point, - /// Position des Busses - bus: Point, + // Bisher zurückgelegte Strecke + total_distance: f64, } impl cmp::Eq for RunState {} impl cmp::Ord for RunState { @@ -39,14 +39,17 @@ impl cmp::PartialOrd for RunState { } fn main() { - // 07:00: Bus ist 15 km entfernt - let start_time = NaiveTime::from_hms(7, 0, 0); - let bus = Point::new(0.0, -15000.0); - let bus_start = bus; // 30 km/h -> 8.3 m/s let bus_speed = 30.0 / 3.6; + let lisa_speed = 15.0 / 3.6; // Zeitpunkt basierend auf Wartezeit in Sekunden berechnen - let delay_to_time = |delay| start_time + Duration::seconds((delay / bus_speed) as i64); + let calc_time = |total_distance, y| { + NaiveTime::from_hms(7, 30, 0) + - Duration::seconds(((total_distance * 2.0 - y) / bus_speed) as i64) + }; + let calc_end_time = |total_distance, y| { + calc_time(total_distance, y) + Duration::seconds((total_distance / lisa_speed) as i64) + }; // Input einlesen (Lisas Haus und Hindernisse) let data = input::read_input(); @@ -62,18 +65,22 @@ fn main() { // Startzustand: Lisa ist an ihrem Haus, Bus noch nicht losgefahren let start = RunState { pos: house, - bus: bus, - delay: max_possible_delay(bus, house), + delay: max_possible_delay(0.0, house), + total_distance: 0.0, }; - eprintln!("Theoretisches Maximum: {:?}", delay_to_time(start.delay)); + let meeting_point = Point::new(0.0, house.y() + 30.0f64.to_radians().tan() * house.x()); + eprintln!( + "Theoretisches Maximum: {:?}", + calc_time(distance(meeting_point, house), meeting_point.y()) + ); // Zustände in Max-Heap sortieren let mut states = BinaryHeap::new(); states.push(vec![start]); // beste Lösung speichern - let mut best_delay = 0.0; + let mut best_delay = f64::NEG_INFINITY; let mut best = vec![]; // Zwischenlösungen speichern let save_prefix = "tmp_"; @@ -84,6 +91,7 @@ fn main() { // besten Zustand einlesen let state = states.pop().unwrap(); let last = &state[0]; + println!("last {:?}", last); // neue Zustände let mut all = vec![]; @@ -98,79 +106,79 @@ fn main() { .filter(|next| none_intersect(&polys, &Line::new(last.pos, *next))) { // Lisa könnte zu dieser Ecke rennen - let bus_next = last.bus.translate(0.0, distance(last.pos, next) * 2.0); - let delay = max_possible_delay(bus_next, next); + let total_distance = last.total_distance + distance(last.pos, next); + let delay = max_possible_delay(total_distance, next); if delay > best_delay { let mut route = state.clone(); route.insert( 0, RunState { pos: next, - bus: bus_next, delay, + total_distance, }, ); all.push(route); } } // versuche, direkt zum Bus zu gehen - let bus = last.bus; - let range = to_bus(bus, last.pos); - if range.len() == 2 { - // Lisa trifft Bus mit 60°-Winkel - let next = Point::new( - 0.0, - last.pos.y() + 30.0f64.to_radians().tan() * last.pos.x(), - ); - let line = Line::new(last.pos, next); - // freier Weg? - if none_intersect(&polys, &line) { - let delay = line.end.y - - bus.y() - line.end_point().euclidean_distance(&line.start_point()) - * 2.0; - if delay > best_delay { - // neue beste Wartezeit - let mut route = state.clone(); - route.insert( - 0, - RunState { - pos: next, - bus: next, - delay, - }, - ); - // Verbesserung anzeigen und speichern - eprintln!( - "Verbesserung: {:?} ({:?}+ Zustände verbleiben)", - delay_to_time(delay), - states.len() - ); - best = route; - best.reverse(); - best_delay = delay; - display::save_svg( - &format!("{}{}.svg", save_prefix, save_counter), - house, - &polys, - &best, - ); - save_counter += 1; - } + // Lisa trifft Bus mit 60°-Winkel + let next = Point::new( + 0.0, + last.pos.y() + 30.0f64.to_radians().tan() * last.pos.x(), + ); + let line = Line::new(last.pos, next); + // freier Weg? + if none_intersect(&polys, &line) { + let line_length = line.end_point().euclidean_distance(&line.start_point()); + let total_distance = last.total_distance + line_length; + let delay = max_possible_delay(total_distance, line.end_point()); + if delay > best_delay { + // neue beste Wartezeit + let mut route = state.clone(); + route.insert( + 0, + RunState { + pos: next, + delay, + total_distance, + }, + ); + // Verbesserung anzeigen und speichern + eprintln!( + "Verbesserung: {:?} ({:?}+ Zustände verbleiben)", + calc_time(total_distance, line.end.y), + states.len() + ); + best = route; + best.reverse(); + best_delay = delay; + /* + display::save_svg( + &format!("{}{}.svg", save_prefix, save_counter), + house, + &polys, + &best, + ); + */ + save_counter += 1; } - // falls Bus überhaupt noch erreicht wird: neu gefundene Routen speichern - states.extend(all); } + // neu gefundene Routen speichern + states.extend(all); } eprintln!("Finale Lösung:"); let route = best; - eprintln!("Startzeit: {:?}", delay_to_time(best_delay)); + let last = route.last().unwrap(); + eprintln!( + "Startzeit: {:?}", + calc_time(last.total_distance, last.pos.y()) + ); eprintln!( "Zielzeit: {:?}", - delay_to_time(route.last().unwrap().bus.y() - bus_start.y()) + calc_end_time(last.total_distance, last.pos.y()) ); - eprintln!("Treffpunkt: y={:.0}", route.last().unwrap().pos.y()); - let mut length = 0.0; - let mut last = &house; + eprintln!("Treffpunkt: y={:.0}", last.pos.y()); eprintln!("Route:"); for s in &route { if s.pos == house { @@ -187,11 +195,9 @@ fn main() { ); } eprintln!("x={:.02} y={:.02}", s.pos.x(), s.pos.y()); - length += last.euclidean_distance(&s.pos); - last = &s.pos; } - eprintln!("Länge: {:.0}m", length); - let seconds = length / (15.0 / 3.6); + eprintln!("Länge: {:.0}m", last.total_distance); + let seconds = last.total_distance / (15.0 / 3.6); eprintln!("Dauer: {:02.0}:{:02.0}", seconds / 60.0, seconds % 60.0); // beste Route grafisch ausgeben display::dump_latex_code(&route, &polys); @@ -235,14 +241,10 @@ fn distance(a: Point, b: Point) -> f64 { ((a.x() - b.x()).powi(2) + (a.y() - b.y()).powi(2)).sqrt() } -fn max_possible_delay(bus: Point, start: Point) -> f64 { - let x_l = start.x(); - let y_l = start.y(); - let x_b = bus.x(); - assert_eq!(x_b, 0.0); - let y_b = bus.y(); - - y_l - (3.0 * x_l.powi(2)).sqrt() - y_b +fn max_possible_delay(total_distance: f64, lisa: Point) -> f64 { + let x_l = lisa.x(); + let y_l = lisa.y(); + y_l - (3.0 * x_l.powi(2)).sqrt() - total_distance * 2.0 } /// Gehe direkt zum Bus. Gibt die Punkte zurück, bei denen Lisa nicht auf den Bus warten müsste.