#!/usr/bin/env python3 """gtfs_suche.py — echte schnellste Nahverkehrs-Verbindung aus GTFS-SQLite (zeitbasierter Dijkstra). Aufruf: python3 gtfs_suche.py [HH:MM] Vorraussetzung: DB aus build_gtfs_db.py. Aktiv-ID-Regel: wenn ein Bahnhof mehrere IDs hat, die mit COUNT(*)>0 in st nehmen. """ import sqlite3, sys, heapq from collections import defaultdict DB = "/tmp/gtfs_rt.db" def to_sec(t): p = t.split(":") h = int(p[0]); m = int(p[1]) if len(p) > 1 else 0 return h*3600 + m*60 def fmt(t): return f"{t//3600:02d}:{(t%3600)//60:02d}" def aktive_id(con, stop_name): """Findet die stop_id mit st-Vorkommen (Bahnhof kann mehrere IDs haben).""" cands = con.execute("SELECT stop_id FROM stops WHERE stop_name=?", (stop_name,)).fetchall() for (sid,) in cands: if con.execute("SELECT COUNT(*) FROM st WHERE stop_id=?", (sid,)).fetchone()[0] > 0: return sid return None def verbinde(von_id, nach_id, start="09:00"): con = sqlite3.connect(DB) con.row_factory = sqlite3.Row dep0 = to_sec(start) deps_by_stop = defaultdict(list); stops_by_trip = defaultdict(list) for r in con.execute("SELECT trip_id, stop_id, seq, arr, dep FROM st"): deps_by_stop[r["stop_id"]].append((to_sec(r["dep"]), r["trip_id"], r["seq"])) stops_by_trip[r["trip_id"]].append((r["seq"], r["stop_id"], to_sec(r["arr"]), to_sec(r["dep"]))) con.close() for k in deps_by_stop: deps_by_stop[k].sort() for k in stops_by_trip: stops_by_trip[k].sort() INF = float('inf') dist = defaultdict(lambda: INF); dist[von_id] = dep0 heap = [(dep0, von_id)] pred = {} while heap: t, stop = heapq.heappop(heap) if t != dist[stop]: continue if stop == nach_id: break for dep_s, tid, seq in deps_by_stop[stop]: if dep_s < t: continue for (sseq, sid, arr_s, dep2) in stops_by_trip[tid]: if sseq <= seq: continue if arr_s < dist[sid]: dist[sid] = arr_s; pred[sid] = (tid, stop) heapq.heappush(heap, (arr_s, sid)) if nach_id not in pred and nach_id != von_id: return None if nach_id == von_id: return (0, [], 0, fmt(dep0), fmt(dep0)) trips = []; cur = nach_id while cur in pred and cur != von_id: tid, prev = pred[cur]; trips.append(tid); cur = prev trips.reverse() dur = dist[nach_id] - dep0 return (dur, trips, len(set(trips)), fmt(dep0), fmt(dist[nach_id])) if __name__ == "__main__": von = sys.argv[1]; nach = sys.argv[2] start = sys.argv[3] if len(sys.argv) > 3 else "09:00" r = verbinde(von, nach, start) if r: dur, trips, umst, dep, arr = r print(f"{dur//3600}h {(dur%3600)//60:02d}min | {dep}->{arr} | {umst} Umstieg(e)") else: print("Keine Verbindung")