Don't store bus position

This commit is contained in:
Arne Keller 2019-03-29 18:53:57 +01:00
parent ddc323eba7
commit 103e8c309c
2 changed files with 79 additions and 75 deletions

View File

@ -74,6 +74,7 @@ pub(crate) fn dump_latex_code(route: &[RunState], polys: &[Polygon]) {
println!("\\end{{tikzpicture}}"); println!("\\end{{tikzpicture}}");
} }
/*
pub(crate) fn dump_route(house: Point, polys: &[Polygon], route: &Vec<RunState>) { pub(crate) fn dump_route(house: Point, polys: &[Polygon], route: &Vec<RunState>) {
let (points, lines, route1, route2_start) = gen_params(house, route); let (points, lines, route1, route2_start) = gen_params(house, route);
print!( print!(
@ -243,3 +244,4 @@ pub(crate) fn generate_svg(
document.to_string() document.to_string()
} }
*/

View File

@ -23,8 +23,8 @@ struct RunState {
delay: f64, delay: f64,
/// Lisas Position /// Lisas Position
pos: Point, pos: Point,
/// Position des Busses // Bisher zurückgelegte Strecke
bus: Point, total_distance: f64,
} }
impl cmp::Eq for RunState {} impl cmp::Eq for RunState {}
impl cmp::Ord for RunState { impl cmp::Ord for RunState {
@ -39,14 +39,17 @@ impl cmp::PartialOrd for RunState {
} }
fn main() { 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 // 30 km/h -> 8.3 m/s
let bus_speed = 30.0 / 3.6; let bus_speed = 30.0 / 3.6;
let lisa_speed = 15.0 / 3.6;
// Zeitpunkt basierend auf Wartezeit in Sekunden berechnen // 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) // Input einlesen (Lisas Haus und Hindernisse)
let data = input::read_input(); let data = input::read_input();
@ -62,18 +65,22 @@ fn main() {
// Startzustand: Lisa ist an ihrem Haus, Bus noch nicht losgefahren // Startzustand: Lisa ist an ihrem Haus, Bus noch nicht losgefahren
let start = RunState { let start = RunState {
pos: house, pos: house,
bus: bus, delay: max_possible_delay(0.0, house),
delay: max_possible_delay(bus, 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 // Zustände in Max-Heap sortieren
let mut states = BinaryHeap::new(); let mut states = BinaryHeap::new();
states.push(vec![start]); states.push(vec![start]);
// beste Lösung speichern // beste Lösung speichern
let mut best_delay = 0.0; let mut best_delay = f64::NEG_INFINITY;
let mut best = vec![]; let mut best = vec![];
// Zwischenlösungen speichern // Zwischenlösungen speichern
let save_prefix = "tmp_"; let save_prefix = "tmp_";
@ -84,6 +91,7 @@ fn main() {
// besten Zustand einlesen // besten Zustand einlesen
let state = states.pop().unwrap(); let state = states.pop().unwrap();
let last = &state[0]; let last = &state[0];
println!("last {:?}", last);
// neue Zustände // neue Zustände
let mut all = vec![]; let mut all = vec![];
@ -98,79 +106,79 @@ fn main() {
.filter(|next| none_intersect(&polys, &Line::new(last.pos, *next))) .filter(|next| none_intersect(&polys, &Line::new(last.pos, *next)))
{ {
// Lisa könnte zu dieser Ecke rennen // Lisa könnte zu dieser Ecke rennen
let bus_next = last.bus.translate(0.0, distance(last.pos, next) * 2.0); let total_distance = last.total_distance + distance(last.pos, next);
let delay = max_possible_delay(bus_next, next); let delay = max_possible_delay(total_distance, next);
if delay > best_delay { if delay > best_delay {
let mut route = state.clone(); let mut route = state.clone();
route.insert( route.insert(
0, 0,
RunState { RunState {
pos: next, pos: next,
bus: bus_next,
delay, delay,
total_distance,
}, },
); );
all.push(route); all.push(route);
} }
} }
// versuche, direkt zum Bus zu gehen // versuche, direkt zum Bus zu gehen
let bus = last.bus; // Lisa trifft Bus mit 60°-Winkel
let range = to_bus(bus, last.pos); let next = Point::new(
if range.len() == 2 { 0.0,
// Lisa trifft Bus mit 60°-Winkel last.pos.y() + 30.0f64.to_radians().tan() * last.pos.x(),
let next = Point::new( );
0.0, let line = Line::new(last.pos, next);
last.pos.y() + 30.0f64.to_radians().tan() * last.pos.x(), // freier Weg?
); if none_intersect(&polys, &line) {
let line = Line::new(last.pos, next); let line_length = line.end_point().euclidean_distance(&line.start_point());
// freier Weg? let total_distance = last.total_distance + line_length;
if none_intersect(&polys, &line) { let delay = max_possible_delay(total_distance, line.end_point());
let delay = line.end.y if delay > best_delay {
- bus.y() - line.end_point().euclidean_distance(&line.start_point()) // neue beste Wartezeit
* 2.0; let mut route = state.clone();
if delay > best_delay { route.insert(
// neue beste Wartezeit 0,
let mut route = state.clone(); RunState {
route.insert( pos: next,
0, delay,
RunState { total_distance,
pos: next, },
bus: next, );
delay, // Verbesserung anzeigen und speichern
}, eprintln!(
); "Verbesserung: {:?} ({:?}+ Zustände verbleiben)",
// Verbesserung anzeigen und speichern calc_time(total_distance, line.end.y),
eprintln!( states.len()
"Verbesserung: {:?} ({:?}+ Zustände verbleiben)", );
delay_to_time(delay), best = route;
states.len() best.reverse();
); best_delay = delay;
best = route; /*
best.reverse(); display::save_svg(
best_delay = delay; &format!("{}{}.svg", save_prefix, save_counter),
display::save_svg( house,
&format!("{}{}.svg", save_prefix, save_counter), &polys,
house, &best,
&polys, );
&best, */
); save_counter += 1;
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:"); eprintln!("Finale Lösung:");
let route = best; 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!( eprintln!(
"Zielzeit: {:?}", "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()); eprintln!("Treffpunkt: y={:.0}", last.pos.y());
let mut length = 0.0;
let mut last = &house;
eprintln!("Route:"); eprintln!("Route:");
for s in &route { for s in &route {
if s.pos == house { if s.pos == house {
@ -187,11 +195,9 @@ fn main() {
); );
} }
eprintln!("x={:.02} y={:.02}", s.pos.x(), s.pos.y()); 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); eprintln!("Länge: {:.0}m", last.total_distance);
let seconds = length / (15.0 / 3.6); let seconds = last.total_distance / (15.0 / 3.6);
eprintln!("Dauer: {:02.0}:{:02.0}", seconds / 60.0, seconds % 60.0); eprintln!("Dauer: {:02.0}:{:02.0}", seconds / 60.0, seconds % 60.0);
// beste Route grafisch ausgeben // beste Route grafisch ausgeben
display::dump_latex_code(&route, &polys); 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() ((a.x() - b.x()).powi(2) + (a.y() - b.y()).powi(2)).sqrt()
} }
fn max_possible_delay(bus: Point, start: Point) -> f64 { fn max_possible_delay(total_distance: f64, lisa: Point) -> f64 {
let x_l = start.x(); let x_l = lisa.x();
let y_l = start.y(); let y_l = lisa.y();
let x_b = bus.x(); y_l - (3.0 * x_l.powi(2)).sqrt() - total_distance * 2.0
assert_eq!(x_b, 0.0);
let y_b = bus.y();
y_l - (3.0 * x_l.powi(2)).sqrt() - y_b
} }
/// Gehe direkt zum Bus. Gibt die Punkte zurück, bei denen Lisa nicht auf den Bus warten müsste. /// Gehe direkt zum Bus. Gibt die Punkte zurück, bei denen Lisa nicht auf den Bus warten müsste.