diff --git a/lib/App/MasterUtils.pm b/lib/App/MasterUtils.pm index 4ba65ee1f16d960767c35713b9d2c9211a8bb487..78d79bb6478a71d90470bbc341d9576f0956ebc3 100644 --- a/lib/App/MasterUtils.pm +++ b/lib/App/MasterUtils.pm @@ -49,14 +49,13 @@ sub is_train_route my $frame = get_rosen_frame $master, $rosen_id; return $frame->{'is_train'}; } - sub get_rosenmei { return (get_rosen_frame $_[0], $_[1])->{'rosenmei'}; } -sub get_eki_position +sub get_eki_indexes { my $master = $_[0]; my $rosen_id = $_[1]; @@ -65,7 +64,18 @@ sub get_eki_position my @ekis = @{ $rosen->{'eki'} }; my @pos; - return first { $ekis[$_] eq $id } 0..$#ekis; + my @refs; + foreach my $i (0 .. $#ekis) + { + if ($ekis[$i] eq $id) { push @refs, $i; } + } + return @refs; +} + +sub get_eki_position +{ + my @indexes = get_eki_indexes $_[0], $_[1], $_[2]; + return $indexes[0]; } sub get_patterns diff --git a/lib/App/Navi.pm b/lib/App/Navi.pm index b6455f57fe1397fbc136d819f2d49988f4cec1ef..b6440f0911904cc6dac42164a7310fd2ae2a66a0 100644 --- a/lib/App/Navi.pm +++ b/lib/App/Navi.pm @@ -40,11 +40,14 @@ sub Raptor_simple my %taustar; my @marked; - # We add two more hashes: + # We also add some more hashes: # one to keep track of the last used service to arrive at a station my %earliest; - # and one to save the station used to board this last used service + # one to save the station used to board this last used service my %from; + # one to keep the arrival / departure times from a station + # (this allows us to avoid having to use get_eki_indexes) + my %adt; # We also save the number of times a station was visited # This may need a demonstration but we consider that the minimal time is already reached if the station is processed two times the number of routes it is served by. @@ -148,89 +151,97 @@ sub Raptor_simple # We do two runs starting from $p, one towards each end of the route. my @r_ekis = @{ (MasterUtils::get_rosen_frame $master, $r)->{'eki'} }; my $ekinum = $#r_ekis; - my $p_index = MasterUtils::get_eki_position $master, $r, $p; - - # New idea: find the fastest service on a single route from $p to $index - for (my $dist = -$#r_ekis; - $dist <= $#r_ekis; # TODO optimization - $dist++) - { - my $index = $p_index - $dist; - if ($index < 0 || $index > $#r_ekis) { next; } - if ($index < $p_index && $d == 0 || - $index > $p_index && $d == 1) { next; } - my $index_rel = $d - ? $ekinum - $index - : $index; - my $pi = $r_ekis[$index]; - - $trip = NaviUtils::direct_trip $master, $r, $p, $pi, $taus{$p}[$k-1]; - - if (defined $trip - && defined (Ressya::arr_time $trip, $index_rel) - && (Ressya::arr_time $trip, $index_rel) < (min $taustar{$pi}, $taustar{$to_id})) + my @p_indexes = MasterUtils::get_eki_indexes $master, $r, $p; + foreach my $p_index (@p_indexes) + { + # New idea: find the fastest service on a single route from $p to $index + for (my $dist = -$#r_ekis; + $dist <= $#r_ekis; # TODO optimization + $dist++) { - my $trip_arrival = Ressya::arr_time $trip, $index_rel; - Log::d "Updating ETA($k) for $pi >> $trip_arrival"; - $taus{$pi}->[$k] = $trip_arrival; - $taustar{$pi} = $trip_arrival; - $earliest{$pi}{'rosen'} = $r; - $earliest{$pi}{'dir'} = $d; - $earliest{$pi}{'service'} = $trip; - $from{$pi} = $p; - - # Check if the target station is not already marked - my $mark = 1; - for (@marked) + my $index = $p_index - $dist; + if ($index < 0 || $index > $#r_ekis) { next; } + if ($index < $p_index && $d == 0 || + $index > $p_index && $d == 1) { next; } + my $index_rel = $d + ? $ekinum - $index + : $index; + my $pi = $r_ekis[$index]; + + ($trip, my $dt, my $at) = NaviUtils::direct_trip $master, $r, $p, $pi, $taus{$p}[$k-1]; + + # if (defined $trip + # && defined (Ressya::arr_time $trip, $index_rel) + # && (Ressya::arr_time $trip, $index_rel) < (min $taustar{$pi}, $taustar{$to_id})) + # { + if (defined $trip + && defined $at + && $at < (min $taustar{$pi}, $taustar{$to_id})) { - if ($_->{'eki'} eq $pi) { $mark = 0; } + # my $trip_arrival = Ressya::arr_time $trip, $index_rel; + Log::d "Updating ETA($k) for $pi >> $at using $dt from $p"; + # $adt{$p}{'hatsu'} = $dt; + $adt{$pi}{'chaku'} = $at; + $taus{$pi}->[$k] = $at; + $taustar{$pi} = $at; + $earliest{$pi}{'rosen'} = $r; + $earliest{$pi}{'dir'} = $d; + $earliest{$pi}{'service'} = $trip; + $from{$pi} = $p; + + # Check if the target station is not already marked + my $mark = 1; + for (@marked) + { + if ($_->{'eki'} eq $pi) { $mark = 0; } - } + } - # This is only applicable if the marked station was not reached on foot. - if (defined $_->{'rosen'}) - { - # On routes with multiple service patterns (over 3: minimal route should contain an all-stop pattern & a forwarding pattern), do not consider non-terminal stations with only one pattern stopping - # This will most likely save a lot of time on routes with a great amount of stops / services (e.g. high-frequency lines) - my $all_patterns = MasterUtils::get_patterns $master, $r; - # TODO maybe move these computations to a "metadata" frame - my $stopping_patterns = $master->{'metadata'}->{$r}->{$pi}; - if ($stopping_patterns < 2 && $all_patterns >= 3) + # This is only applicable if the marked station was not reached on foot. + if (defined $_->{'rosen'}) { - $mark = 0; + # On routes with multiple service patterns (over 3: minimal route should contain an all-stop pattern & a forwarding pattern), do not consider non-terminal stations with only one pattern stopping + # This will most likely save a lot of time on routes with a great amount of stops / services (e.g. high-frequency lines) + my $all_patterns = MasterUtils::get_patterns $master, $r; + # TODO maybe move these computations to a "metadata" frame + my $stopping_patterns = $master->{'metadata'}->{$r}->{$pi}; + if ($stopping_patterns < 2 && $all_patterns >= 3) + { + $mark = 0; + } + } + + if ($mark) + { + push @marked, { eki => $pi, rosen => $r, direction => 0 }; + push @marked, { eki => $pi, rosen => $r, direction => 1 }; + Log::d "Marking station $pi"; } - } - - if ($mark) - { - push @marked, { eki => $pi, rosen => $r, direction => 0 }; - push @marked, { eki => $pi, rosen => $r, direction => 1 }; - Log::d "Marking station $pi"; - } - } - else - { - if (defined $trip && defined (Ressya::arr_time $trip, $index_rel)) - { - my $trip_arrival = Ressya::arr_time $trip, $index_rel; - Log::d "Found earliest departure arrives @ $trip_arrival, which is later than the current earliest departure ($taustar{$pi}), or is later than the current ETA @ $to_id ($taustar{$to_id})" } else { - Log::d "No earliest departure, or departure is later than the current earliest departure ($taustar{$pi}) / the current ETA @ $to_id ($taustar{$to_id})" + if (defined $trip && defined (Ressya::arr_time $trip, $index_rel)) + { + my $trip_arrival = Ressya::arr_time $trip, $index_rel; + Log::d "Found earliest departure arrives @ $trip_arrival, which is later than the current earliest departure ($taustar{$pi}), or is later than the current ETA @ $to_id ($taustar{$to_id})" + } + else + { + Log::d "No earliest departure, or departure is later than the current earliest departure ($taustar{$pi}) / the current ETA @ $to_id ($taustar{$to_id})" + } + } - + + + # if (!defined $trip || + # (!defined Ressya::dep_time $trip, $index_rel || + # $taus{$pi}[$k-1] <= Ressya::dep_time $trip, $index_rel)) + # { + # # $trip = earliest_trip $k, $r, $pi, $dir; + # } } - - # if (!defined $trip || - # (!defined Ressya::dep_time $trip, $index_rel || - # $taus{$pi}[$k-1] <= Ressya::dep_time $trip, $index_rel)) - # { - # # $trip = earliest_trip $k, $r, $pi, $dir; - # } } - } my @next_marked; @@ -307,30 +318,42 @@ sub Raptor_simple } # First crawl: build a list of arrival/departure times + # This does not apply for stations reached on foot + # (processed afterwards) for (my $i = 0; $i <= $#path; $i++) { my %eki_jikoku = ( 'chaku' => undef, 'hatsu' => undef ); + if ($i == 0) { $eki_jikoku{'chaku'} = $dep_time; } + if ($i != $#path and !defined $legs[$i]->{'time'}) { my $next_frame = $earliest{$path[$i+1]}; - my $next_eki_pos = $next_frame->{'dir'} - ? $master->{'rosen'}->{$next_frame->{'rosen'}}->{'eki_num'} - (MasterUtils::get_eki_position $master, $next_frame->{'rosen'}, $path[$i]) - 1 - : MasterUtils::get_eki_position $master, $next_frame->{'rosen'}, $path[$i]; - - my $dep = Ressya::dep_time $next_frame->{'service'}, $next_eki_pos; - $eki_jikoku{'hatsu'} = $dep; + my $dir = $next_frame->{'dir'}; + my @next_indexes = MasterUtils::get_eki_indexes $master, $next_frame->{'rosen'}, $path[$i]; + foreach my $next_index (@next_indexes) + { + my $next_eki_pos = $dir + ? $master->{'rosen'}->{$next_frame->{'rosen'}}->{'eki_num'} - $next_index - 1 + : $next_index; + my $dep = Ressya::dep_time $next_frame->{'service'}, $next_eki_pos; + if (defined $dep) { $eki_jikoku{'hatsu'} = $dep; } + } } if ($i != 0 and !defined $legs[$i-1]->{'time'}) { my $previous_frame = $earliest{$path[$i]}; - my $previous_eki_pos = $previous_frame->{'dir'} - ? $master->{'rosen'}->{$previous_frame->{'rosen'}}->{'eki_num'} - (MasterUtils::get_eki_position $master, $previous_frame->{'rosen'}, $path[$i]) - 1 - : MasterUtils::get_eki_position $master, $previous_frame->{'rosen'}, $path[$i]; - - my $arr = Ressya::arr_time $previous_frame->{'service'}, $previous_eki_pos; - $eki_jikoku{'chaku'} = $arr; + my $dir = $previous_frame->{'dir'}; + my @previous_indexes = MasterUtils::get_eki_indexes $master, $previous_frame->{'rosen'}, $path[$i]; + foreach my $previous_index (@previous_indexes) + { + my $previous_eki_pos = $dir + ? $master->{'rosen'}->{$previous_frame->{'rosen'}}->{'eki_num'} - $previous_index - 1 + : $previous_index; + my $arr = Ressya::arr_time $previous_frame->{'service'}, $previous_eki_pos; + if (defined $arr) { $eki_jikoku{'chaku'} = $arr; } + } } push @jikoku, \%eki_jikoku; @@ -346,9 +369,9 @@ sub Raptor_simple my $m = (defined $u->{'meisyo'}) ? ' ' . $u->{'meisyo'} : ''; my $from_what = MasterUtils::get_ekimei $master, $path[$i]; - my $from_dep = $jikoku[$i]->{'hatsu'}; + my $from_dep = $jikoku[$i]{'hatsu'}; my $to_what = MasterUtils::get_ekimei $master, $path[$i+1]; - my $to_arr = $jikoku[$i+1]->{'chaku'}; + my $to_arr = $jikoku[$i+1]{'chaku'}; print( (TimeUtils::format_time $from_dep) . "\t$from_what\n" @@ -369,7 +392,7 @@ sub Raptor_simple if ($i != $#path - 1 && !defined $legs[$i+1]->{'time'}) { - my $to_dep = $jikoku[$i+1]->{'hatsu'}; + my $to_dep = $jikoku[$i+1]{'hatsu'}; print( '(' . TimeUtils::format_time_simple (TimeUtils::subtract_from $to_arr, $to_dep) . ")\tO\n" @@ -377,7 +400,7 @@ sub Raptor_simple } if ($i != $#path - 1 && defined $legs[$i+1]->{'time'}) { - my $to_dep = $jikoku[$i+2]->{'hatsu'}; + my $to_dep = $jikoku[$i+2]{'hatsu'}; my $tt = $legs[$i+1]->{'time'}; my $total = TimeUtils::subtract_from $to_arr, $to_dep; my $wait = TimeUtils::subtract_from $tt, $total; diff --git a/lib/App/NaviUtils.pm b/lib/App/NaviUtils.pm index bfe0e4ad07cc4cc2361443442442ba36cfe8861c..e29a69ea73bd614a7afc7a8ab8b9f277ee52860b 100644 --- a/lib/App/NaviUtils.pm +++ b/lib/App/NaviUtils.pm @@ -43,35 +43,48 @@ sub direct_trip # Determine direction # 0 down, 1 up - my $from_pos = MasterUtils::get_eki_position $master, $r, $from_id; - my $to_pos = MasterUtils::get_eki_position $master, $r, $to_id; - my $dir = $to_pos - $from_pos < 0 ? 1 : 0; - Log::d 'Direction is ' . ($dir ? 'up' : 'down'); - my $dia = $dir - ? $frame->{'dia'}->{'nobori'} : $frame->{'dia'}->{'kudari'}; - - my $from_corr = $dir - ? $frame->{'eki_num'} - $from_pos - 1 - : $from_pos; - my $to_corr = $dir - ? $frame->{'eki_num'} - $to_pos - 1 - : $to_pos; - - # Only keep departures after $dep that stop at $from_id - my $final; - foreach my $u (@$dia) + # Departure time from the origin + my $final_from = ~0; + # Arrival time at the destination + my $final_to = ~0; + my @froms = MasterUtils::get_eki_indexes $master, $r, $from_id; + my @tos = MasterUtils::get_eki_indexes $master, $r, $to_id; + + foreach my $from_pos (@froms) { - my $udep = Ressya::dep_time $u, $from_corr; - if (!defined $udep || $udep < $dep) { next; } - my $uarr = Ressya::arr_time $u, $to_corr; - if (!defined $uarr) { next; } - # TODO Times > 23:59 are currently not supported. - if ($uarr < $udep) { next; } - if (!defined $final || - $uarr < Ressya::arr_time $final, $to_corr) - { - $final = $u; + foreach my $to_pos (@tos) + { + my $dir = $to_pos - $from_pos < 0 ? 1 : 0; + Log::d 'Direction is ' . ($dir ? 'up' : 'down'); + my $dia = $dir + ? $frame->{'dia'}->{'nobori'} : $frame->{'dia'}->{'kudari'}; + + my $from_corr = $dir + ? $frame->{'eki_num'} - $from_pos - 1 + : $from_pos; + my $to_corr = $dir + ? $frame->{'eki_num'} - $to_pos - 1 + : $to_pos; + + # Only keep departures after $dep that stop at $from_id + + foreach my $u (@$dia) + { + my $udep = Ressya::dep_time $u, $from_corr; + if (!defined $udep || $udep < $dep) { next; } + my $uarr = Ressya::arr_time $u, $to_corr; + if (!defined $uarr) { next; } + # TODO Times > 23:59 are currently not supported. + if ($uarr < $udep) { next; } + if (!defined $final || + $uarr < $final_to) + { + $final = $u; + $final_from = $udep; + $final_to = $uarr; + } + } } } @@ -81,9 +94,8 @@ sub direct_trip return; } - my $display_dep = Ressya::dep_time $final, $from_corr; - Log::d "Found earliest departure from $from_id @ $display_dep"; - return $final; + Log::d "Found earliest departure from $from_id @ $final_from > $final_to"; + return ($final, $final_from, $final_to); } 1; diff --git a/src/oud2_parser.pl b/src/oud2_parser.pl index 867daff4e521cfd33c08be06c3e2dd29caf68080..d8b85c671ba822afad2832bd92b4a0718c71afe8 100644 --- a/src/oud2_parser.pl +++ b/src/oud2_parser.pl @@ -451,11 +451,11 @@ $master{'transfer_times'} = $transfers; # FrameUtils::hassya_hyou \%master, 'sekihoku1_28'; -my $d = MasterUtils::search_eki \%master, '帯広'; -my $a = MasterUtils::search_eki \%master, '釧路'; +my $d = MasterUtils::search_eki \%master, '春別'; +my $a = MasterUtils::search_eki \%master, '五十嵐'; sub eki { return MasterUtils::search_eki \%master, $_[0]; } -Navi::Raptor_simple \%master, $d, $a, 525; +Navi::Raptor_simple \%master, $d, $a, 1000; # FrameUtils::hassya_hyou \%master, (eki '古瀬');