Prettify source code

This commit is contained in:
Arne Keller 2019-02-03 14:49:48 +01:00
parent 63cb497325
commit 8eefcf7032
2 changed files with 56 additions and 35 deletions

View File

@ -24,8 +24,8 @@ pub(crate) fn dump_latex_code(route: &[RunState], polys: &[Polygon]) {
} }
} }
} }
if route[route.len()-1].pos.y()/SCALE > ymax { if route[route.len() - 1].pos.y() / SCALE > ymax {
ymax = route[route.len()-1].pos.y()/SCALE; ymax = route[route.len() - 1].pos.y() / SCALE;
} }
println!("\\begin{{tikzpicture}}"); println!("\\begin{{tikzpicture}}");
println!("\\tkzInit[xmax={},ymax={}]", xmax + 0.3, ymax + 0.3); println!("\\tkzInit[xmax={},ymax={}]", xmax + 0.3, ymax + 0.3);
@ -58,10 +58,15 @@ pub(crate) fn dump_latex_code(route: &[RunState], polys: &[Polygon]) {
println!(")"); println!(")");
} }
for (idx, s) in route.iter().enumerate() { for (idx, s) in route.iter().enumerate() {
println!("\\tkzDefPoint({},{}){{R{}}}", s.pos.x()/SCALE, s.pos.y()/SCALE, idx); println!(
"\\tkzDefPoint({},{}){{R{}}}",
s.pos.x() / SCALE,
s.pos.y() / SCALE,
idx
);
} }
for idx in 1..route.len() { for idx in 1..route.len() {
println!("\\tkzDrawSegment(R{},R{})", idx-1, idx); println!("\\tkzDrawSegment(R{},R{})", idx - 1, idx);
} }
for idx in 0..route.len() { for idx in 0..route.len() {
println!("\\tkzDrawPoint[fill=red,color=black,size=13](R{})", idx); println!("\\tkzDrawPoint[fill=red,color=black,size=13](R{})", idx);

View File

@ -52,9 +52,6 @@ fn main() {
let data = input::read_input(); let data = input::read_input();
let house = data.start; let house = data.start;
let polys = data.polys; let polys = data.polys;
for p in &polys {
assert!(p.interiors.is_empty());
}
// alle Ecken der Hindernisse bestimmen // alle Ecken der Hindernisse bestimmen
let points = polys let points = polys
.iter() .iter()
@ -62,7 +59,7 @@ fn main() {
.flatten() .flatten()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// Startzustand // Startzustand: Lisa ist an ihrem Haus, Bus noch nicht losgefahren
let start = RunState { let start = RunState {
pos: house, pos: house,
bus: bus, bus: bus,
@ -71,62 +68,69 @@ fn main() {
eprintln!("Maximum: {:?}", delay_to_time(start.delay)); eprintln!("Maximum: {:?}", delay_to_time(start.delay));
// 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
let mut best_delay = 0.0; let mut best_delay = 0.0;
let mut best = vec![]; let mut best = vec![];
// Zwischenlösungen speichern
let save_prefix = "tmp_"; let save_prefix = "tmp_";
let mut save_counter = 0; let mut save_counter = 0;
// weitersuchen, bis kein besserer Zustand mehr vorhanden ist // weitersuchen, bis kein besserer Zustand mehr vorhanden ist
while states.peek().map(|x| x[0].delay > best_delay) == Some(true) { while states.peek().map(|x| x[0].delay > best_delay) == Some(true) {
let s = states.pop().unwrap(); // besten Zustand einlesen
let last = &s[0]; let state = states.pop().unwrap();
let last = &state[0];
// neue Zustände // neue Zustände
let mut all = vec![]; let mut all = vec![];
// versuche zu jeder anderen Ecke zu gehen // versuche, zu jeder anderen Ecke zu gehen
for next in points for next in points
.iter() .iter()
.filter(|next| !s.iter().any(|x| x.pos == (**next).into())) // Ecke sollte nicht schon in Route sein
.filter(|next| !state.iter().any(|p| p.pos == (**next).into()))
.map(|x| Point::from(*x))
// Weg zu dieser Ecke sollte kein Polygon schneiden
.filter(|next| none_intersect(&polys, &Line::new(last.pos, *next)))
{ {
let next = Point::from(*next); // Lisa könnte zu dieser Ecke rennen
if next != last.pos && none_intersect(&polys, &Line::new(last.pos, next)) { let bus_next = last.bus.translate(0.0, distance(last.pos, next) * 2.0);
// Lisa könnte zu dieser Ecke rennen let delay = max_possible_delay(bus_next, next);
let bus_next = last.bus.translate(0.0, distance(last.pos, next) * 2.0); if delay > best_delay {
let delay = max_possible_delay(bus_next, next); let mut route = state.clone();
if delay > best_delay { route.insert(
let mut route = s.clone(); 0,
route.insert( RunState {
0, pos: next,
RunState { bus: bus_next,
pos: next, delay,
bus: bus_next, },
delay, );
}, all.push(route);
);
all.push(route);
}
} }
} }
// versuche, direkt zum Bus zu gehen // versuche, direkt zum Bus zu gehen
let bus = last.bus; let bus = last.bus;
let range = to_bus(bus, last.pos); let range = to_bus(bus, last.pos);
if range.len() == 2 { if range.len() == 2 {
// Lisa trifft Bus mit 60°-Winkel
let next = Point::new( let next = Point::new(
0.0, 0.0,
last.pos.y() + 30.0f64.to_radians().tan() * last.pos.x(), last.pos.y() + 30.0f64.to_radians().tan() * last.pos.x(),
); );
let line = Line::new(last.pos, next); let line = Line::new(last.pos, next);
// freier Weg?
if none_intersect(&polys, &line) { if none_intersect(&polys, &line) {
let delay = line.end.y let delay = line.end.y
- bus.y() - line.end_point().euclidean_distance(&line.start_point()) - bus.y() - line.end_point().euclidean_distance(&line.start_point())
* 2.0; * 2.0;
if delay > best_delay { if delay > best_delay {
// neue beste Wartezeit // neue beste Wartezeit
let mut route = s.clone(); let mut route = state.clone();
route.insert( route.insert(
0, 0,
RunState { RunState {
@ -135,8 +139,9 @@ fn main() {
delay, delay,
}, },
); );
// Verbesserung anzeigen und speichern
eprintln!( eprintln!(
"Verbesserung: {:?} ({:?} Zustände verbleiben)", "Verbesserung: {:?} ({:?}+ Zustände verbleiben)",
delay_to_time(delay), delay_to_time(delay),
states.len() states.len()
); );
@ -152,12 +157,16 @@ fn main() {
save_counter += 1; save_counter += 1;
} }
} }
// falls Bus überhaupt noch erreicht wird: neu gefundene Routen speichern
states.extend(all); states.extend(all);
} }
} }
let route = best; let route = best;
eprintln!("Startzeit: {:?}", delay_to_time(best_delay)); eprintln!("Startzeit: {:?}", delay_to_time(best_delay));
eprintln!("Zielzeit: {:?}", delay_to_time(route.last().unwrap().bus.y() - bus_start.y())); eprintln!(
"Zielzeit: {:?}",
delay_to_time(route.last().unwrap().bus.y() - bus_start.y())
);
eprintln!("Treffpunkt: y={:.0}", route.last().unwrap().pos.y()); eprintln!("Treffpunkt: y={:.0}", route.last().unwrap().pos.y());
let mut length = 0.0; let mut length = 0.0;
let mut last = &house; let mut last = &house;
@ -168,7 +177,13 @@ fn main() {
} else if s.pos.x() == 0.0 { } else if s.pos.x() == 0.0 {
eprint!("Treffpunkt: ") eprint!("Treffpunkt: ")
} else { } else {
eprint!("Polygon {:02}: ", polys.iter().position(|p| p.exterior.0.contains(&s.pos.into())).unwrap() + 1); eprint!(
"Polygon {:02}: ",
polys
.iter()
.position(|p| p.exterior.0.contains(&s.pos.into()))
.unwrap() + 1
);
} }
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); length += last.euclidean_distance(&s.pos);
@ -177,7 +192,8 @@ fn main() {
eprintln!("Länge: {:.0}m", length); eprintln!("Länge: {:.0}m", length);
let seconds = length / (15.0 / 3.6); let seconds = length / (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);
display::dump_latex_code(&route, &polys); // beste Route grafisch ausgeben
display::dump_svg(&route, &polys);
} }
fn none_intersect(polys: &[Polygon], line: &Line) -> bool { fn none_intersect(polys: &[Polygon], line: &Line) -> bool {
@ -228,7 +244,7 @@ fn max_possible_delay(bus: Point, start: Point) -> f64 {
y_l - (3.0 * x_l.powi(2)).sqrt() - y_b y_l - (3.0 * x_l.powi(2)).sqrt() - y_b
} }
// Go straight to the bus. Returns the points where the bus can be reached. /// Gehe direkt zum Bus. Gibt die Punkte zurück, bei denen Lisa nicht auf den Bus warten müsste.
fn to_bus(bus: Point, start: Point) -> Vec<Point> { fn to_bus(bus: Point, start: Point) -> Vec<Point> {
let x_l = start.x(); let x_l = start.x();
let y_l = start.y(); let y_l = start.y();