%
% ex83.pl - 「6. 簡単なパズル(?)を解かせる」の3.
%

% gennum1/1 - 一桁の数値生成
gennum1(0).
gennum1(1).
gennum1(2).
gennum1(3).
gennum1(4).
gennum1(5).
gennum1(6).
gennum1(7).
gennum1(8).
gennum1(9).

% 式「((A Op1 B) Op2 C) Op3 D」の結果が10であるなら真
opr10(A, Op1, B, Op2, C, Op3, D) :-
    gennum1(A),
    gennum1(B), B \= A,
    gennum1(C), C \= A, C \= B,
    gennum1(D), D \= A, D \= B, D \= C,
    ops(A, B, X, Op1),
    ops(X, C, Y, Op2),
    ops(Y, D, 10, Op3).

% ops(X, Y, Z, Op) は、式「Z is X Op Y」を意味する。
% ここで、Opは演算子である。
ops(X, Y, Z, +) :- Z is X + Y.
ops(X, Y, Z, -) :- Z is X - Y.
ops(X, Y, Z, *) :- Z is X * Y.
ops(X, Y, Z, /) :- Y \= 0, Z is X rdiv Y.
% 注: rdivは / と同様に除算であるが、結果を小数ではなく分数とする。
%     これを用いると 1 / 3 * 3 等も正確に計算される。
%     除算の際は、0で割るとエラーになるので、そのチェックも入れておく。

% 一々手でバックトラックを指示するのは面倒なので、自動的にバックトラック
% しながら、画面に表示させる述語も定義しておく。
all_opr10 :-
    opr10(A, Op1, B, Op2, C, Op3, D),
    writeln([A, Op1, B, Op2, C, Op3, D]),
    fail.
all_opr10.
