概要
Nabetaniさんの「とある世界のタクシー料金」問題をRubyで解いてみました。
元記事はこちらから
http://qiita.com/Nabetani/items/c70417d384720a3339d6
実装
Rubyで解いてますが、解き方自体はどの言語でも良さそうな感じの実装です。
(どちらの都市でも200m毎に料金加算なので使ってない定数は放置)
taxi_fee.rb
# encoding: sjis
#
# とある世界のタクシー料金を計算する
# Author:: lithtle
# Created_At:: 2015-04-21
# Link:: http://nabetani.sakura.ne.jp/hena/ord30taxi/
# 都市の地点と経路
CITY = {
enlightened: [:A, :B, :C, :AB, :AC, :BG, :CF, :BC],
registance: [:D, :E, :F, :G, :AD, :CD, :DE, :DF, :EG, :FG]
}.freeze
# 各地点間の距離
DISTANTCE = {
AB: 1090,
AC: 180,
AD: 540,
BC: 960,
BG: 1270,
CD: 400,
CF: 200,
DE: 720,
DF: 510,
EG: 1050,
FG: 230
}.freeze
# 各都市でのタクシー設定
TAXI_SETTING = {
enlightened: {min_dist: 995, min_fee: 400, per_meter: 200, per_fee: 60},
registance: {min_dist: 845, min_fee: 350, per_meter: 200, per_fee: 50}
}.freeze
# 経路から都市を判定する
# == Args
# _route_: 経路または地点、文字列
# == Returns
# 覚醒派か開放派か
def get_city(route)
if CITY[:enlightened].any?{ |e| e == route.to_sym || e == route.reverse.to_sym }
:enlightened
elsif CITY[:registance].any?{ |e| e == route.to_sym || e == route.reverse.to_sym }
:registance
else
raise "未定義の経路指定"
end
end
# とある世界のタクシー料金を求める
# == Args
# _route_: 料金を計算したいルート
# == Returns
# 料金
def get_taxi_fee(route)
n = 2
start_point = route[0]
# 各地点の累積距離を求める
route = route.scan(/\w/).each_cons(n).map(&:join) # => ["AB", "BC", "CD"]
each_dist = route.map{ |e| DISTANTCE[e.to_sym] || DISTANTCE[e.reverse.to_sym] } # => [100, 200, 300]
integrated_distantce = each_dist.collect.with_index{ |e, i| each_dist[0..i].reduce(:+) } # => [100, 300, 600]
# 初期設定(初乗り運賃、初乗り料金)を求める
running_disatnce, total_fee = [
TAXI_SETTING[get_city(start_point)][:min_dist],
TAXI_SETTING[get_city(start_point)][:min_fee]
]
# タクシー⊂(^ω^)⊃ブーン
total_distance = integrated_distantce[-1]
while running_disatnce < total_distance
# 到着したら終了
if running_disatnce > total_distance
break
end
# 現在位置からどちらの都市かを判定し運賃を加算
current_pos = route[integrated_distantce.find_index{ |e| e > running_disatnce }]
total_fee += TAXI_SETTING[get_city(current_pos)][:per_fee]
# 200m すすむ
running_disatnce += 200
end
total_fee
end
# てすと
def test
DATA.read.split("\n").map{ |e|
e.gsub(/\s+/, ",").split(",")
}.each do |item|
i, route, expect = item
actual = get_taxi_fee(route)
ok = actual == expect.to_i ? "ok" : "ng"
puts "%2d: %-10s => res: %5s == %-5s : exp => %s" % [i.to_i, route, actual, expect, ok]
end
end
if $0 == __FILE__
test
end
__END__
0 ADFC 510
1 CFDA 500
2 AB 460
3 BA 460
4 CD 400
5 DC 350
6 BG 520
7 GB 530
8 FDA 450
9 ADF 450
10 FDACB 750
11 BCADF 710
12 EDACB 800
13 BCADE 810
14 EGFCADE 920
15 EDACFGE 910
16 ABCDA 960
17 ADCBA 1000
18 BADCFGB 1180
19 BGFCDAB 1180
20 CDFC 460
21 CFDC 450
22 ABGEDA 1420
23 ADEGBA 1470
24 CFGB 640
25 BGFC 630
26 ABGEDFC 1480
27 CFDEGBA 1520
28 CDFGEDABG 1770
29 GBADEGFDC 1680
その他
都市名がingress由来ということにさっぱり気づきませんでした。書いてる途中にふと気になって調べてみたらingressのページがでてきたため、いそいでコードに修正を加えました。