駅すぱあとが対応している最近増えてきた特殊な運賃計算ルール

[ヴァル研究所 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/val) 21日目の記事です。

## はじめに

普段私は「乗換BIG4」と呼ばれる鉄道ファン社員の一員として細々と活動するかたわら、駅すぱあとの運賃計算プログラムの改善業務を行っています。
運賃計算のプログラムと言われてもあまりピンとこない方も多いと思いますが、その中身は複雑怪奇で新規実装、保守作業ともいつも苦労しています。[^0]
ということで、今回は最近増えてきたとある運賃計算ルールに焦点を当て、その一端をお見せしたいと思います。

[^0]: 社内の重鎮の言葉に「運賃計算は生き物」「運賃計算は闇」などがあります。

### 注意

この記事の内容は全て2017年12月時点の情報、ルールを元に作成しています。
特に運賃計算のルールは高頻度で更新されていますので、常に最新の情報をご確認ください。
(駅すぱあとってサービスが便利ですよ！)

## 運賃計算の基本

まずは基本的なパターンです。
日本の鉄道の運賃は、多くの場合以下の手順で求めることができます。

1. 乗車経路の距離(営業キロ)を求める
2. 運賃表に当てはめて運賃を求める

簡単に言えば、遠くまで乗れば高くなるってことです。まあ普通ですよね。
例えば、弊社のある高円寺駅から新宿駅までは、JR中央線経由で営業キロが5.8km、これを以下の運賃表[^1]に当てはめると[^2]、運賃は160円(IC運賃154円)となります。

| 営業キロ(km) | きっぷの運賃(円) | IC運賃(円) |
|:---:|:---:|:---:|
| 1~3 | 140 | 133 |
| 4~6 | 160 | 154 |
| 7~10 | 170 | 165 |
| 11~15 | 220 | 216 |
| 16~20 | 310 | 302 |
| ... | ... | ... |

<img width="808" alt="koenji_shinjuku.png" src="https://qiita-image-store.s3.amazonaws.com/0/36655/25dc08a4-f1d6-282a-7f55-7b1cbbe9f7bf.png">
(この図は[駅すぱあと路線図](https://roote.ekispert.net/ja/rmap)を加工したものです。以下同じ)

なお、実際には「電車特定区間」「大都市近郊区間」「特定都区市内」など多くのルールが裏で介在し、どの運賃表を使うのかについてもいろいろ判定する必要があるのですが、話がややこしくなるのでここでは説明しません。
いろいろなルールを考える必要はあるけども最終的には普通の結果になった、ぐらいに考えてください。

[^1]: 「東京の電車特定区間の普通運賃表」
[^2]: 1km未満の端数は切り上げ。

## 隣の駅と同じ駅とみなす特例(八木西口駅の場合)

基本が分かったところで特殊な例を見てみましょう。
奈良県橿原市にある近鉄橿原線の八木西口(やぎにしぐち)駅です。

<img width="502" alt="yaginishiguchi.png" src="https://qiita-image-store.s3.amazonaws.com/0/36655/07276f73-94a4-4880-47e5-9ab0aa1d3dcc.png">

路線図だけ見ると何の変哲もない駅ですが、実はこの八木西口駅は、運賃計算上「隣の大和八木(やまとやぎ)駅と**同じ駅として扱う**」というルールがあります(以下、このような特例を**「同駅特例」**と呼ぶことにします)。

例えば、田原本(たわらもと)駅から八木西口駅までの運賃は、手前の大和八木駅までの営業キロ4.6kmを基準とし、210円(IC運賃同額、以下近鉄線内同じ)となります。

<img width="502" alt="tawaramoto_yagi.png" src="https://qiita-image-store.s3.amazonaws.com/0/36655/23812ca5-97ea-cd06-9a77-ad4f2c0eeacf.png">

また、飛鳥(あすか)駅から八木西口駅までの運賃は、その先の大和八木駅までの営業キロ5.5kmを基準とし、230円となります。

<img width="502" alt="asuka_yagi.png" src="https://qiita-image-store.s3.amazonaws.com/0/36655/7d88f9ce-b224-e464-1580-5f244dbdecf0.png">

なお、大和八木駅から八木西口駅までの場合は、初乗り運賃の150円となります。

なぜこのような扱いになったのかが気になるところですが、元々大和八木駅の前身となる駅[^2.5]が八木西口駅の場所にあり、その後1929年に移転するも元の駅設備も継続して八木西口駅として使用することになったため、このようなルールになったようです。
運賃計算のルールはしばしば歴史的経緯の影響を受けることになります。
正しい運賃を算出するため、駅すぱあとでも運賃計算時はこの同駅特例を考慮して運賃計算を行っています。

[^2.5]: 大阪電気軌道の大軌八木駅。

## 現代に生まれた同駅特例(小田栄駅の例)

八木西口駅の例はかなり特殊な部類で長らく同様の例は存在しませんでしたが、最近になりとても良く似た駅が開業しました。
神奈川県川崎市にあるJR南武線の小田栄(おださかえ)駅です。

<img width="579" alt="odasakae.png" src="https://qiita-image-store.s3.amazonaws.com/0/36655/96f33227-dcf0-0851-7c73-36d193efdc5f.png">

2016年3月26日、北海道新幹線と同じ日に開業したこの駅には、隣の川崎新町駅と同じ駅として扱うというルールが設定されました。
基本的には八木西口駅と同じパターンですが、実は完全に同じではなく**「小田栄駅・川崎新町駅相互間を利用する場合はICカードが使用できない」**という別のルールも設定されています。

参考 : [南武線(川崎新町～浜川崎間)小田栄駅 開業日のお知らせ](http://www.city.kawasaki.jp/500/cmsfiles/contents/0000074/74794/houdoukaigyou.pdf)

このルールが設定された正確な理由は発表されていませんが、この駅は期間や費用を抑えて建設された経緯があることから、きっぷの発券システムやICカードの改札システムの高額な改修費用を抑えることが目的と推察されます。
そのためか、小田栄駅のIC改札データは川崎新町駅と同一で、この2駅間でICカードを利用すると同じ駅同士で入出場する扱いとなり、結果的にICカードの使用ができないということになっています。[^3]

[^3]: 八木西口駅・大和八木駅相互間ではICカードが使えますが、これはICカードのシステムが導入される前からルールが存在していたため、最初から仕様に組み込まれたものと思われます。

非常に細かいところですが、特に首都圏ではきっぷとICの運賃に差があることから、駅すぱあとではこの違いも考慮して運賃計算を行っています。

## 同駅でない場合もある同駅特例(東武ワールドスクウェア駅の例)

2017年7月22日に開業した栃木県日光市の東武鬼怒川線、東武ワールドスクウェア駅にも同駅特例が設定されました。
この駅は隣の小佐越(こさごえ)駅と同じ駅と扱われ、2駅相互間でのICカード利用は不可となります。

<img width="520" alt="worldsquare.png" src="https://qiita-image-store.s3.amazonaws.com/0/36655/6b06c899-50e6-8679-4b16-b17b67c299ab.png">

しかしこの駅、さらに小田栄駅とも違うルールが存在します。
それは**「東武ワールドスクウェア駅・鬼怒川公園駅相互間のきっぷ運賃は、小佐越駅発着とせず東武ワールドスクウェア駅発着とみなす」**というものです。

参考 : [東武鬼怒川線新駅「東武ワールドスクウェア」の開業日を７月２２日（土）に決定しました！](http://www.tobu.co.jp/file/pdf/79c334dda9506eee8dc5a17f5b07168c/170228_3.pdf?date=20170228191107)

お前は何を言っているんだと思われたかもしれませんが、理屈はこういうことです。
小佐越駅・鬼怒川公園駅間の営業キロは4.6kmで**運賃170円(IC運賃165円)**、しかし本来の東武ワールドスクウェア駅・鬼怒川公園駅間の営業キロ3.9kmに当てはめて考えると**運賃150円(IC運賃144円)**になります。
つまり、同駅特例の適用によってこの2駅間の利用では運賃面で不利になってしまうので、その是正のためにいわば「特例の特例」が適用されています。
ただし、ICカードを利用した場合はそのまま小佐越駅・鬼怒川公園駅間の運賃が適用となるため[^4]、東武ワールドスクウェア駅・鬼怒川公園駅間の運賃は、**きっぷ運賃150円、IC運賃165円**が正解となります。
東武鉄道各駅の中で運賃が高くなってしまう駅が鬼怒川公園駅のみということもあり、このようなルールが設定されたのだと思われます(新藤原より先は野岩鉄道に入るため別精算になります)。[^5]

[^4]: IC改札のデータはあくまでも小佐越駅なので、小佐越駅までの運賃になります。
[^5]: 小田栄駅の場合も同様に不利になる駅が存在しますが、JR線の場合は全国に影響が広がってしまうため、同様の特例適用は難しいものと思われます。

## 同駅特例のまとめ

3通りの同駅特例について整理すると以下のようになります。

| 駅名 | 同駅とみなす駅 | 同駅相互間でのICカード利用 | 同駅とみなさない駅の存在 |
|:--:|:--:|:--:|:--:|
|八木西口|大和八木|◯|×|
|小田栄|川崎新町|×|×|
|東武ワールドスクウェア|小佐越|×|◯|

ご覧の通り、同じように見えて全て少しずつ異なるルールです。
この他にも、「同駅相互間の運賃」や「同駅とみなさない駅との間の運賃」なども考慮すべきポイントになるでしょうか。実際にサービス内に正しく反映させるためには、この違いを表現する必要があります。
また、同駅特例に似ているルールに「外方の隣接駅」という概念で運賃を計算する駅もありますが、これもまた今回の特例とは似て非なるものですので、別の方法で実装することになります。[^6.5]

なお、同駅特例は同種のルールに見えますが、その成立の経緯は八木西口駅と他2駅で大きく異なるため、たまたまよく似ていたというのが正確なところでしょうか。
近年開業した2駅は、ICカードが普及したことにより生まれたルールとも言えるでしょう。運賃計算のルールにも時代ごとに「トレンド」のようなものがある、というわけですね。

[^6.5]: 乗車方向によって同駅とみなす駅が変わるルールです。JR常磐線の偕楽園駅(臨時駅)や、JR大船渡線BRTのまちなか陸前高田駅(2018年4月1日廃止予定)などが該当します。かつては、国鉄の仮乗降場でしばしば適用されていました。

## 駅すぱあとでの対応

さて、ここまでの内容についてどのように感じられたでしょうか？
何が何だか分からないという方も、案外なんとかなるんじゃないかと感じられた方もいらっしゃるかもしれません。
確かにこの同駅特例しか存在しない世界であればそれほど苦労しないように思いますが、実際にはその他の多くの特例が同時に適用されるため、それらと複合した場合に正しく動作するかを見極める必要があります。[^6]
特に鉄道の場合、このルールの複合が意図しない結果をもたらし、間違った運賃を計算してしまうこともあるため、そのような状況をいかに出さないか、テストで発見できるかが鍵になってきます。
また、日々変わりゆくルールを的確に捉え、速く正確に実装するために保守が容易にできる構造であることも理想でしょう。

[^6]: 小田栄駅の場合、「電車特定区間」「東京近郊区間」「特定都区市内(横浜市内)」「Suica首都圏エリア」「京急線との八丁畷駅における乗継割引」などなど、他のより複雑なルールも複数考慮対象になります。

とはいえ、来年で発売から30年が経過する駅すぱあとのコードやデータは過去の多くの特例を包含し、新規実装や保守の足かせになってしまっている面も否定できません。
誤解を恐れずに言ってしまえば、特例の数だけif文がある(!)と思ってください。もちろん共通性のある部分はまとめていますが、把握するだけでも一苦労です。
そんな状況なので、運賃計算におけるコードやデータの内容を見直し、より保守のしやすい現代的な実装となるように日々改善を行っています。

## おわりに

いかがでしたでしょうか。普段は運賃計算の方法なんて気にしない方がほとんどだと思いますが、裏では複雑なものが動いているんだなあとたまに思い出して頂ければと思います。運賃計算の実装や保守は大変なこともありますが、鉄道ファンとしては楽しくもあります。運賃計算ルール自体が趣味になってしまいましたし。
なお、2018年4月1日にJR両毛線にあしかがフラワーパーク駅が開業しますが、この駅も隣の富田駅と同駅扱いになると発表されています。2018年春にはICOCAの距離制限ルール導入など大きな変更があるので、これからも気合を入れて対応していきたいと思います。