1.出発駅と到着駅間の駅数を求める
出発駅から到着駅までのおよその所要時間はその間の駅数で分かる。まず同一路線の場合は駅に付けられた番号の差となる。従って、次のようになる。
stat0' :: Source -> Destination -> Int stat0' sor des = abs $ snd (snd sor) - snd (snd des)
路線が異なっているなどの誤った入力を受け付けないようにするために、ガードをつける。このようにすると、同一路線内での出発駅と到着駅の駅数を求める関数stat0は次のようになる。
stat0 :: Source -> Destination -> Int stat0 sor des | fst sor == fst des = stat0' sor des | otherwise = error "Two stations must locate on the same line."
次に一回乗り換えの場合を求める。これは出発駅から乗換駅までの駅数と乗換駅から到着駅までの駅数の和となる。従って、次のようになる。なお、この関数は入力に出発駅と到着駅の他に路線網を必要とする(乗換駅は両方の路線の駅が対となっているので、それぞれで駅数を求める時は同一路線上にある駅を選ぶ必要がある。ifを使うのはそのためである)。
stat1' :: Source -> Destination -> Network -> [Int] stat1' sor des network = map (\x -> if fst sor == fst (fst x) then stat0’ sor (fst x) + stat0’ (snd x) des else stat0’ sor (snd x) + stat0’ (fst x) des) (trans1 (fst sor) (fst des) network)
上記のプログラムで乗換駅は複数の場合がある。このため、それぞれに対して所要の駅数を求める。先ほどと同じように、誤った入力を受け付けないようにガードをする。ここでは、出発駅と到着駅が同一路線にはないという他に、出発駅と到着駅の路線と駅が路線網に含まれていることを確認する。この関数stat1は次のようになる。
stat1 :: Source -> Destination -> Network -> [Int] stat1 sor des network | fst sor /= fst des && elem (fst sor) (names network) && elem (snd sor) (stations network2) && elem (fst des) (names network) && elem (snd des) (stations network2) = stat1' sor des network | otherwise = error "input error."
次に乗換が二回の場合を考える。この場合は、出発駅と最初の乗換駅、最初の乗換駅と二番目の乗換駅、二番目の乗換駅と到着駅のそれぞれの駅数を求め、それらを加えればよい。乗換駅で同一路線を選択するための場合分けが面倒くさいが、関数は次のようになる。
stat2' :: Source -> Destination -> Network -> [Int] stat2' sor des network = map (\x -> if fst sor == fst (fst (fst x)) && fst des == fst (snd (snd x)) then stat0’ sor (fst (fst x)) + stat0’ (snd (fst x)) (fst (snd x)) + stat0’ (snd (snd x)) des else if fst sor == fst (snd (fst x)) && fst des == fst (snd (snd x)) then stat0’ sor (snd (fst x)) + stat0’ (fst (fst x)) (fst (snd x)) + stat0’ (snd (snd x)) des else if fst sor == fst (fst (fst x)) && fst des == fst (fst (snd x)) then stat0’ sor (fst (fst x)) + stat0’ (snd (fst x)) (snd (snd x)) + stat0’ (fst (snd x)) des else stat0’ sor (snd (fst x)) + stat0’ (fst (fst x)) (snd (snd x)) + stat0’ (fst (snd x)) des) (trans2 (fst sor) (fst des) network)
ここでも、入力にガードをつける。そこで、二回乗り換えでの駅数を求める関数stat2は次のようになる。
stat2 :: Source -> Destination -> Network -> [Int] stat2 sor des network | fst sor /= fst des && elem (fst sor) (names network) && elem (snd sor) (stations network) && elem (fst des) (names network2) && elem (snd des) (stations network) = stat2' sor des network | otherwise = error "input error."
駅数だけだと、どのような経路でたどりついたか分からないので、乗換駅と一緒に出力する。これは次のようにする。
steps2' :: Source -> Destination -> Network -> [(Int, (Transfer, Transfer))] steps2' sor des network = zip (stat2' sor des network) (trans2 (fst sor) (fst des) network)
また、例によって入力のチェックを行うと、駅数と乗換駅を表示する関数steps2は次のようになる。
steps2 :: Source -> Destination -> Network -> [(Int, (Transfer, Transfer))] steps2 sor des network | fst sor /= fst des && elem (fst sor) (names network) && elem (snd sor) (stations network) && elem (fst des) (names network2) && elem (snd des) (stations network) = steps2' sor des network | otherwise = error "input error."
ついでに一回乗り換えの場合も上げておく。
steps1' :: Source -> Destination -> Network -> [(Int, Transfer)] steps1' sor des network = zip (stat1' sor des network) (trans1 (fst sor) (fst des) network) steps1 :: Source -> Destination -> Network -> [(Int, Transfer)] steps1 sor des network | fst sor /= fst des && elem (fst sor) (names network) && elem (snd sor) (stations network) && elem (fst des) (names network2) && elem (snd des) (stations network) = steps1' sor des network | otherwise = error "input error."
2.プログラムの実行
それではプログラムを実行してみる。
最初は半蔵門線内の錦糸町(Z13)から表参道(Z2)を求めた。
次に半蔵門線の錦糸町(Z13)から大江戸線の牛込神楽坂(E5)を一回乗り換え、二回乗り換えでの駅数を求めた。一回乗り換えでは、二通りの方法があることが分かる。
次に半蔵門線の錦糸町(Z13)から有楽町線の氷川台(Y5)を一回乗り換え、二回乗り換えでの駅数を求めた。二回乗り換えでは、二通りの方法があることが分かる。
次に駅数だけでなく乗換駅も表示した。例えば、半蔵門線の錦糸町(Z13)から大江戸線の牛込神楽坂(E5)を一回乗り換えでは、清澄白河(E14)を経由した場合が11駅、青山一丁目(E24)を経由した場合が29駅であることが分かる。