このディレクトリの索引
#  問題文
#  ぼく、一目惚れをしました。昨日学内ですれ違った彼女の名前、どうしても知りたいんです。いや、名前だけじゃない……!身長も体重も、彼女の全てが知りたい!
#  でも、僕には彼女に話しかける勇気なんてない。彼女の体重は何 kg なんだろうか...彼女の身長は何 cm くらいなんだろうか...。結局、一晩中彼女のことだけを考えてぜんぜん寝られていない。
#  さすがに女性にいきなり体重を聞くのは失礼だろう。そんなことは分かっている。そんなものを聞いたりしたら、間違いなく嫌われてしまうだろう。
#  「うーむ、どうしたものか……ハッ!」
#  僕の脳内に稲妻が走った。そうだ、身長とBMI(※)を聞けばいいんだ。そうしたら体重を逆算できる。名前はもうどうでもいいや、これは名案だ。
#  そうと決まれば、 身長[cm] と BMI[kg?m2] の2つの値に基づいて 体重[kg] を逆算してくれるプログラムを有能プログラマーである君に作ってもらいたい。
#  
#  
#  ※ BMI[kg?m2] とは、ボディマス指数と呼ばれるもので、以下の計算式で与えられる。ただし、Height と Weight はそれぞれ身長と体重のことである。
#  
#  入力
#  入力は以下の形式で標準入力から与えられる。
#  
#  Height BMI
#  Height(120.0≦Height≦200.0) は、プログラムに与えられる身長[cm]を表す実数である。小数点第 1 位まで与えられる。
#  BMI(10.0≦BMI≦40.0) は、プログラムに与えられる BMI[kg?m2] を表す実数である。小数点第 1 位まで与えられる。
#  出力
#  入力に基づいて逆算した 体重 [kg] を一行に出力せよ。
#  出力は絶対誤差が 10−2 以下であれば許容される。
#  なお、出力の最後には改行を入れること。

'ぼく、一目惚れをしました。昨日学内ですれ違った彼女の名前、どうしても知りたいんです。いや、名前だけじゃない……!身長も体重も、彼女の全てが知りたい!
でも、僕には彼女に話しかける勇気なんてない。彼女の体重は何 kg なんだろうか...彼女の身長は何 cm くらいなんだろうか...。結局、一晩中彼女のことだけを考えてぜんぜん寝られていない。
さすがに女性にいきなり体重を聞くのは失礼だろう。そんなことは分かっている。そんなものを聞いたりしたら、間違いなく嫌われてしまうだろう。
「うーむ、どうしたものか……ハッ!」
僕の脳内に稲妻が走った。そうだ、身長とBMI(※)を聞けばいいんだ。そうしたら体重を逆算できる。名前はもうどうでもいいや、これは名案だ。' :-
標準入力から身長とBMIを得る(_身長,_BMI),
'身長[cm] と BMI[kg?m2] の2つの値に基づいて 体重[kg] を逆算する'(_身長,_BMI,_体重),
format('~1f\n',[_体重]).


標準入力から身長とBMIを得る(_身長,_BMI) :-
文字列を得る(_文字列),
split(_文字列,[' '],[_身長文字列,_BMI文字列]),
get_term_from_atom(_身長文字列,_身長,[]),
get_term_from_atom(_BMI文字列,_BMI,[]).


'身長[cm] と BMI[kg?m2] の2つの値に基づいて 体重[kg] を逆算する'(_身長,_BMI,_体重) :-
'身長[cm] と BMI[kg?m2] の2つの値に基づいて 体重[kg] を逆算する'(0,_身長,_BMI,_体重_BMIとの差ならび),
'BMIの計算差が最小のものの体重'(_体重_BMIとの差ならび,_体重).


'身長[cm] と BMI[kg?m2] の2つの値に基づいて 体重[kg] を逆算する'(2000,_身長,_BMI,[]) :- !.
'身長[cm] と BMI[kg?m2] の2つの値に基づいて 体重[kg] を逆算する'(N,_身長,_BMI,[[N,_BMI_の計算差]|R]) :-
'身長、体重から、BMIの計算差を得る'(N,_身長,_BMI,N_2,_体重,_BMIの計算差),
'身長[cm] と BMI[kg?m2] の2つの値に基づいて 体重[kg] を逆算する'(N_2,_身長,_BMI,R).


'身長、体重から、BMIの計算差を得る'(N,_身長,_BMI,N_2,_体重,_BMIの計算差) :-
_BMIの計算差 is abs((N / 10) / ((_身長 / 100) ^ 2)) - _BMI),
succ(N,N_2),
_体重 is N / 10.


'BMIの計算差が最小のものの体重'(_N_BMIとの差ならび,_体重) :-
select([_体重,_BMIの差],_N_BMIとの差ならび,R),
forall(member([_,_BMIの差_1],R),_BMIの差 =< _BMIの差_1).


文字列を得る(_文字列) :-
findall(_文字,(repeat,get_char(_文字),(_文字=end_of_file,!,fail;_文字='\n',!,fail;true)),L),
atomic_list_concat(L,_文字列).


文字列を区切り文字列で分ける(_文字列,_区切り文字列候補,[_前文字列|R]) :-
文字列を区切り文字列候補で前文字列と後文字列に分ける(_文字列,_区切り文字列候補,_前文字列,_区切り文字列,_後文字列),
文字列を区切り文字列で分ける(_後文字列,_区切り文字列候補,R),!.
文字列を区切り文字列で分ける(_文字列,_,[_文字列]).


文字列を区切り文字列候補で前文字列と後文字列に分ける(_文字列,_区切り文字列候補,_前文字列,_区切り文字列,_後文字列) :-
文字列の先頭から区切り文字列を捜す(_文字列,_区切り文字列候補,_区切り文字列,S,R),
前文字列と後文字列に分ける(_文字列,S,R,_前文字列,_後文字列).


文字列の先頭から区切り文字列を捜す(_文字列,_区切り文字列候補,_区切り文字列,S,R) :-
sub_atom(_文字列,S,Len,R,_区切り文字列),
member(_区切り文字列,_区切り文字列候補).


前文字列と後文字列に分ける(_文字列,S,R,_前文字列,_後文字列) :-
sub_atom(_文字列,0,S,_,_前文字列),
sub_atom(_文字列,_,R,0,_後文字列),!.