前書き(予防線)
ガチProlog初心者です。(4時間くらいしか触っていない。)
コードが出来た瞬間にやる気ゲージが尽きたのでリファクタとかはしていません。
そのため書き方が冗長だったり、
もっといい書き方があるかもしれません。
問題
A,B,C,Dがトライアスロン(※)をしました。
それぞれの証言から順位を推理してください。
※:水泳→自転車→マラソンの順で争う競技。マラソンの順位が最終的な順位
【証言】
A「水泳も自転車も順位は同じだったけど、マラソンで二人に抜かれちゃった。」
B「自転車でDを抜いて、そのあとはゴールまで Dには抜かれてないよ。」
C「水泳で3位だったけど、ゴールするまで3位より上になったことはなかったよ。ちぇ。」
D「自転車で調子が悪くて 4位に落ちちゃったけど、結局水泳と同じ順位でゴールできた。」
プログラム
a_testimony(A_Swi, A_Cyc, A_Mar) :-
A_Swi =:= A_Cyc,
A_Mar =:= A_Cyc + 2.
b_testimony(B_Cyc, B_Mar, D_Cyc, D_Mar) :-
B_Cyc < D_Cyc,
B_Mar < D_Mar.
c_testimony(C_Swi, C_Cyc, C_Mar) :-
C_Swi =:= 3,
C_Cyc >= 3,
C_Mar >= 3.
d_testimony(D_Swi, D_Cyc, D_Mar) :-
D_Cyc =:= 4,
D_Swi =:= D_Mar.
all_testimony(A_Mar, B_Mar, C_Mar, D_Mar) :-
between(1, 4, A_Swi),
between(1, 4, A_Cyc),
between(1, 4, A_Mar),
between(1, 4, B_Swi),
between(1, 4, B_Cyc),
between(1, 4, B_Mar),
between(1, 4, C_Swi),
between(1, 4, C_Cyc),
between(1, 4, C_Mar),
between(1, 4, D_Swi),
between(1, 4, D_Cyc),
between(1, 4, D_Mar),
A_Swi =\= B_Swi, A_Swi =\= C_Swi, A_Swi =\= D_Swi,
B_Swi =\= C_Swi, B_Swi =\= D_Swi, C_Swi =\= D_Swi,
A_Cyc =\= B_Cyc, A_Cyc =\= C_Cyc, A_Cyc =\= D_Cyc,
B_Cyc =\= C_Cyc, B_Cyc =\= D_Cyc, C_Cyc =\= D_Cyc,
A_Mar =\= B_Mar, A_Mar =\= C_Mar, A_Mar =\= D_Mar,
B_Mar =\= C_Mar, B_Mar =\= D_Mar, C_Mar =\= D_Mar,
a_testimony(A_Swi, A_Cyc, A_Mar),
b_testimony(B_Cyc, B_Mar, D_Cyc, D_Mar),
c_testimony(C_Swi, C_Cyc, C_Mar),
d_testimony(D_Swi, D_Cyc, D_Mar).
program :-
findall(A_Mar-B_Mar-C_Mar-D_Mar, all_testimony(A_Mar, B_Mar, C_Mar, D_Mar), Bag),
print(Bag).
結果
[3-1-4-2]
参考にした(勉強に利用した)サイト
ChatGPT先生にもお世話になりました。
といってもbetweenの存在とリストぐらいしか知識を得ていません。
その他
論理的な解き方が知りたい方は以下のサイトを見てください。
元ネタ