駆け出しエンジニアの作業ノート

駆け出しエンジニアが作業ノート風にまとめるページ(関係無い事もしばしば)

Graphillionで使う路線データを自動生成するツールを作った

この記事は「サポーターズCoLab Advent Calendar 2019」15日目の記事となります。

 

adventar.org

 

今回は、このブログの人気記事である。「最長片道切符」に関するお話です。

 

最長片道切符に関しては、以下の記事をご覧ください。

 

psyduck-take-it-easy.hatenablog.com

psyduck-take-it-easy.hatenablog.com

 

さて、この最長片道切符を算出するにあたり、路線データを作るのですが、路線の開業や廃線のたびに、手作業で修正をしていました。また、現在は「稚内肥前山口行き」というようにスタート地点とゴール地点を固定した形式で算出していますが、路線の開業や廃線によってスタートとゴールが移動する可能性も否定できません。今回は、「単純経路」、「スタートを含む経路」、「ゴールを含む経路」の3つのGraphillion用路線データをJR全線のデータから自動生成するスクリプトを作ったので、紹介します。

 

さて、肝心のJR全線データですが、まとまったものが無かったので、wikipedia等から「JRの運賃計算ルール上の路線データ」を持ってきてまとめました。

 

github.com

 

路線の並びはこちらの順に従っています。

 

ja.wikipedia.org

 

スタートを含む経路とゴールを含む経路についてのロジックは、以前コメントを下さった方のサイトを参考にしています。

 

souzoumap.webcrow.jp

 

では、計算スクリプトをかい摘んで説明します。

 

file1 = # 読み込みたい路線データ
f = open(file1, "r")
lines = f.readlines()
station_dict = {}
for line in lines:
line_data = line.split(",")
for i in range(0,2):
if line_data[i] not in station_dict:
station_dict[line_data[i]] = 1
else:
station_dict[line_data[i]] = station_dict[line_data[i]] + 1

 

ここで、読み込んだ路線データ内で駅が何回出てくるかを数えます。3回以上出て来れば、路線が別れる分岐駅で、逆に1回しか出てこない駅は行き止まりとなります。

 

stop_station_list = # 分岐駅では無いが、路線名が途中で変わる駅(神戸・金沢等)や、強制的に分割したい駅を入れる

 

これは、駅が2回しか出てこない場合でも、路線名が変わる神戸や金沢といった駅や、強制的に分割したい駅をlist形式で格納します。強制的に分割しなければいけない事例としては以下の例があります。

 

www.jreast.co.jp

 

こちらの地図で、横浜から大船間を注目すると、内陸側を走行する東海道本線と海側を走行する根岸線の2つがあります。両線とも途中に分岐駅が無いので、それぞれ横浜から大船まで路線データが生成されます。しかし、Graphillionの仕様上2地点間の距離を二重に登録することはできないため、根岸線のデータを桜木町で強制的に分割します。

ちなみに、強制的に分割した駅は北海道・本州・四国・九州ごとに以下になります。

 

"網走", "東森"

"神戸", "桜木町", "舞鶴", "播州赤穂", "", "柳津", "青森", "金沢", "安房鴨川", "新尾道", "西岩国", "水沢江刺", "新神戸", "篠ノ井"

"高松", "徳島", "新谷", "内子"

"門司", "鹿児島", "八代", "(鹿)川内"

 

for line in lines:
line_data = line.split(",")
if start == "":
start = line_data[0]
if (station_dict[line_data[1]] != 2) or (line_data[1] in stop_station_list):
end = line_data[1]
if end == "":
distance += float(line_data[2])
distance = round(distance, 1)
else:
distance += round(float(line_data[2]),2)
distance = round(distance, 1)
print("{0},{1},{2}".format(start, end, distance))
write_list = [start, end, str(distance)]
write_line = ",".join(write_list)
f2.write(write_line)
f2.write("\n")
start = ""
end = ""
distance = 0

 

 

最後にここで地点毎の距離を計算して、印字します。算出された路線データは以下にあります。

 

github.com

 

ちなみに、算出されたデータを基に最長片道切符を計算すると以下になります。

 

スタート→稚内→永山→新旭川南永山→網走→遠矢→東釧路→釧路→十勝清水→新得→落合→布部→富良野→学田→神楽岡旭川→近文→納内→深川→妹背牛→江部乙→滝川→砂川→峰延→岩見沢→志文→(室)三川→(室)追分→安平→遠浅→沼ノ端→植苗→南千歳→(千)千歳→平和→(函)白石→苗穂→札幌→桑園→琴似→二股→長万部中ノ沢石谷→森→東森→池田園→大沼→仁山新函館北斗木古内新青森→川部→東能代→(奥)追分→秋田→余目→坂町→米沢→北山形→羽前千歳→新庄→横手→大曲→盛岡→花巻→新花巻→北上→一ノ関→気仙沼→柳津→前谷地→石巻高城町→松島→小牛田→古川→仙台→(北)福島→岩沼→いわき→(北)郡山→会津若松→新津→東三条→長岡→燕三条→新潟→吉田→柏崎→宮内→越後川口→飯山→糸魚川→松本→篠ノ井→長野→佐久平→高崎→越後湯沢→渋川→新前橋→小山→宇都宮→宝積寺→安積永盛上菅谷→水戸→友部→我孫子→新松戸→南浦和→赤羽→池袋→田端→日暮里→秋葉原錦糸町西船橋→千葉→佐倉→成田→香取→松岸→成東→大網→安房鴨川→木更津→蘇我→南船橋市川塩浜→東京→神田→御茶ノ水→代々木→新宿→西国分寺武蔵浦和→大宮→熊谷→倉賀野→高麗川→拝島→立川→府中本町→武蔵小杉→品川→川崎→尻手→浜川崎→武蔵白石→浅野→鶴見→東神奈川→横浜→桜木町→大船→茅ケ崎→国府津→沼津→富士→甲府→八王子→(横)橋本→新横浜→小田原→熱海→三島→静岡→豊橋→辰野→岡谷→塩尻→多治見→(中)金山→名古屋→亀山→松阪→多気→和歌山→(和)高田→奈良→王寺→久宝寺天王寺→今宮→西九条→大阪→京橋→鴫野→放出→木津→柘植→草津→山科→近江塩津米原→大垣→岐阜→美濃太田→富山→新高岡→金沢→越前花堂敦賀→東舞鶴→綾部→京都→新大阪→新神戸西明石→兵庫→神戸→尼崎→谷川→福知山→和田山鳥取東津山→姫路→相生→東岡山→岡山→津山→新見→総社→倉敷→福山→三原→呉→海田市→広島→塩町→備後落合→備中神代伯耆大山→米子→宍道→益田→新山口宇部→居能→雀田→小野田→厚狭→長門市→幡生→門司

 

門司から先ですが、メモリー不足で到達できませんでした。環境を整えて計算できたら更新します。

 

最長片道切符に関するコードは全てここにあります。

 

github.com