このディレクトリの索引
#  問題文
#  ぼく、一目惚れをしました。昨日学内ですれ違った彼女の名前、どうしても知りたいんです。いや、名前だけじゃない……!身長も体重も、彼女の全てが知りたい!
#  でも、僕には彼女に話しかける勇気なんてない。彼女の体重は何 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] を逆算する'(0.0,200.0,_身長,_BMI,_体重),
format('~1f\n',[_体重]).


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



'身長[cm] と BMI[kg?m2] の2つの値に基づいて 体重[kg] を逆算する'(_体重_下,_体重_上,_身長,_BMI,_体重) :-
収束条件を満たす(_体重_下,_体重_上,_体重),!.
'身長[cm] と BMI[kg?m2] の2つの値に基づいて 体重[kg] を逆算する'(_体重_下_1,_体重_上_1,_身長,_BMI,_体重) :-
'新しい体重とその時のBMIを計算して、次の体重の計算区間を得る'(_体重_下_1,_体重_上_1,_身長,_BMI,_BMI_2,_体重_下,_体重_上),
'身長[cm] と BMI[kg?m2] の2つの値に基づいて 体重[kg] を逆算する'(_体重_下,_体重_上,_身長,_BMI,_体重).


収束条件を満たす(_体重_下,_体重_上,_体重) :-
(_体重_上 - _体重_下) < 0.1,
_体重 is (_体重_上 + _体重_下) / 2.


'新しい体重とその時のBMIを計算して、次の体重の計算区間を得る'(_体重_下_1,_体重_上_1,_身長,_BMI,_BMI_2,_体重_下,_体重_上) :-
'新しい体重とその時のBMIを計算する'(_体重_下_1,_体重_上_1,_身長,_BMI_2,_体重_2),
'次の体重の計算区間を得る'(_体重_下_1,_体重_上_1,_体重_2,_BMI,_BMI_2,_体重_下,_体重_上).


'新しい体重とその時のBMIを計算する'(_体重_下,_体重_上,_身長,_BMI_2,_体重_2) :-
_体重_2 is (_体重_下 + _体重_上) / 2,
_BMI_2 is _体重_2 / ((_身長 / 100) ^ 2).


'次の体重の計算区間を得る'(_体重_下,_,_体重_2,_BMI,_BMI_2,_体重_下,_体重_2) :-
_BMI_2 =< _BMI,!.
'次の体重の計算区間を得る'(_体重_下,_体重_上,_体重_2,_BMI,_BMI_2,_体重_2,_体重_上).


文字列を得る(_文字列) :-
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,_後文字列),!.


% これはsplitをわかりやすいように簡略化した定義です。
% より完全なsplit/3の定義はこちらをご覧ください
%

split(_文,_区切り語ならび,_区切られた語ならび) :-
        区切り語ならびの変形(_区切り語ならび,SeparatersL),
        atom_chars(_文,_文字ならび),
        split_list_1(_文字ならび,SeparatersL,_区切られた語ならび).

sPLIT(_文字列,_区切り符号ならび,X) :-
        'SPLIT'(_文字列,_区切り符号ならび,Y),
        findall(U,(
                    member(U,Y),
                    \+(U = '')),
                L),
        L = X,!.

'SPLIT'(_文字列,_区切り符号ならび,X) :-
        atom_chars(_文字列,L),
        split_00(L,_区切り符号ならび,Z),
        Z = X,!.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

split_list([],SeparatersL,[]).
split_list(L1,SeparatersL,[L2|R]) :-
        \+(L1=[]),
        split_list_2(L1,SeparatersL,L2,R2),
        \+(L2=[]),
        split_list(R2,SeparatersL,R).
split_list(L1,SeparatersL,X) :-
        \+(L1=[]),
        split_list_2(L1,SeparatersL,L2,R2),
        L2=[],
        split_list(R2,SeparatersL,X).

split_list_1([],SeparatersL,[]).
split_list_1(L1,SeparatersL,[A|R]) :-
        \+(L1=[]),
        split_list_2(L1,SeparatersL,L2,R2),
        \+(L2=[]),
        atom_chars(A,L2),
        split_list_1(R2,SeparatersL,R).
split_list_1(L1,SeparatersL,X) :-
        \+(L1=[]),
        split_list_2(L1,SeparatersL,L2,R2),
        L2=[],
        split_list_1(R2,SeparatersL,X).

split_list_2([],_,[],[]).
split_list_2(L1,SeparatersL,[],R) :-
        member(L2,SeparatersL),
        append(L2,R,L1).
split_list_2([A|R1],SeparatersL,[A|R2],R) :-
        \+((member(L2,SeparatersL),append(L2,_,[A|R1]))),
        split_list_2(R1,SeparatersL,R2,R).

区切り語ならびの変形(_区切り語ならび,_降順の区切り文字ならびのならび) :-
        sort(_区切り語ならび,_昇順の区切り語ならび),
        reverse(_昇順の区切り語ならび,_降順の区切り語ならび),
        atomList2charsList(_降順の区切り語ならび,_降順の区切り文字ならびのならび).

atomList2charsList([],[]) :- !.
atomList2charsList([A|R1],[L|R2]) :-
        atom_chars(A,L),
        atomList2charsList(R1,R2).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

split_00(_文字ならび,_区切り符号ならび,X) :-
        findall([B,A],(
                    member(A,_区切り符号ならび),
                    atom_chars(A,B)),
                _区切り符号ならびの二),
        split_0(_文字ならび,_区切り符号ならびの二,X).


split_0(_文字ならび,_区切り符号ならび,['',_区切り符号,'']) :-
        member([_区切り文字ならび,_区切り符号],_区切り符号ならび),
        _文字ならび = _区切り文字ならび,!.
split_0(_文字ならび,_区切り符号ならび,['',_区切り符号|R2]) :-
        member([_区切り文字ならび,_区切り符号],_区切り符号ならび),
        append(_区切り文字ならび,R,_文字ならび),
        split_1(R,_区切り符号ならび,R2),!.
split_0(L,_区切り符号ならび,X) :-
        split_1(L,_区切り符号ならび,X).

split_1([],_,[]) :- !.
split_1(_文字ならび,_区切り符号ならび,['',_区切り符号,'']) :-
        member([_区切り文字ならび,_区切り符号],_区切り符号ならび),
        _文字ならび = _区切り文字ならび,!.
split_1(_文字ならび,_区切り符号ならび,['',_区切り符号_1,C,_区切り符号_2|X]) :-
        member([_区切り文字ならび,_区切り符号_1],_区切り符号ならび),
        append(_区切り文字ならび,R,_文字ならび),
        split_2(R,R2,_区切り符号_2,_区切り符号ならび,B),
        split_5(B,C),
        split_0(R2,_区切り符号ならび,X),!.
split_1(_文字ならび,_区切り符号ならび,[C|X]) :-
        split_2(_文字ならび,R2,_区切り符号,_区切り符号ならび,B),
        _区切り符号 = '',
        split_5(B,C),
        split_0(R2,_区切り符号ならび,X),!.
split_1(_文字ならび,_区切り符号ならび,[C,_区切り符号|X]) :-
        split_2(_文字ならび,R2,_区切り符号,_区切り符号ならび,B),
        \+(_区切り符号 = ''),
        split_5(B,C),
        split_0(R2,_区切り符号ならび,X),!.

split_2([],[],'',_,[]) :- !.
split_2(_文字ならび,R,_区切り符号,_区切り符号ならび,[]) :-
        member([_区切り文字ならび,_区切り符号],_区切り符号ならび),
        append(_区切り文字ならび,R,_文字ならび),!.
split_2([''''|R],R2,_区切り符号,_区切り符号ならび,X) :-
        split_3([''''|R],R2,_区切り符号,_区切り符号ならび,X),!.
split_2(['"'|R],R2,_区切り符号,_区切り符号ならび,X) :-
        split_32(['"'|R],R2,_区切り符号,_区切り符号ならび,X),!.
split_2([_文字|R],R2,_区切り符号,_区切り符号ならび,[_文字|X]) :-
        split_2(R,R2,_区切り符号,_区切り符号ならび,X),!.


split_3(['''',''''|R],R2,_区切り符号,_区切り符号ならび,[''''|X]) :-
        split_4(R,R2,_区切り符号,_区切り符号ならび,X),!.
split_3([_|R],R2,_区切り符号,_区切り符号ならび,X) :-
        split_4(R,R2,_区切り符号,_区切り符号ならび,X),!.

split_4(['''',''''|R],R2,_区切り符号,_区切り符号ならび,[''''|X]) :-
        split_4(R,R2,_区切り符号,_区切り符号ならび,X),!.
split_4([''''|R],R2,_区切り符号,_区切り符号ならび,X) :-
        split_2(R,R2,_区切り符号,_区切り符号ならび,X),!.
split_4([],[],'',_,[]) :- !.

split_4([_文字|R],R2,_区切り符号ならび,[_文字|X]) :-
        split_4(R,R2,_区切り符号,_区切り符号ならび,X),!.


split_5([],'') :- !.
split_5(B,C) :-
        numeric_list(B,NL),
        catch(atom_chars(C,NL),_,fail),!.
split_5(B,C) :-
        concat_atom(B,C),!.

split_32(['"','"'|R],R2,_区切り符号,_区切り符号ならび,[''''|X]) :-
        split_42(R,R2,_区切り符号,_区切り符号ならび,X),!.
split_32([_|R],R2,_区切り符号,_区切り符号ならび,X) :-
        split_42(R,R2,_区切り符号,_区切り符号ならび,X),!.

split_42(['"','"'|R],R2,_区切り符号,_区切り符号ならび,['"'|X]) :-
        split_42(R,R2,_区切り符号,_区切り符号ならび,X),!.
split_42(['"'|R],R2,_区切り符号,_区切り符号ならび,X) :-
        split_2(R,R2,_区切り符号,_区切り符号ならび,X),!.
split_42([],[],'',_,[]) :- !.

numeric_list([],[]) :- !.
numeric_list([A|R],[B|R1]) :-
        digit(A),
        char_code(A,B),
        numeric_list(R,R1),!.
numeric_list(['.'|R],[46|R1]) :-
        numeric_list(R,R1),!.
numeric_list([-|R],[45|R1]) :-
        numeric_list(R,R1),!.

number(A,B) :-
        number_codes(A,B).