#!/usr/local/bin/prologcgi

:-s_charset(_,utf8).
top_call:-
        char_conversion('Ａ','A'),char_conversion('Ｂ','B'),
        char_conversion('Ｃ','C'),char_conversion('　',' '),
        char_conversion('（','('),char_conversion('）',')'),
        get_params([A,B,C,D]),
        html_call([
        "Content-Type: text/html; charset=utf-8

         <html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'></head>
         <body><center><H1>Hello Prolog World!  ＜ 論理パズル「三人の女神」 ＞</H1>
          出展 BlueBacks 【論理パズル「出しっこ問題」傑作選 】小野田博一著<br><br>	
         <a href='puttxt.exe?goddesses.cgi' target='source'>このページのソース表示</a>
         <INPUT TYPE='button' VALUE='RETURN' onClick='history.back()'><br><br><br>
         <h2>Ａ，Ｂ，Ｃ三人の女神が次のように語っていますが<br>最も美しい女神のみが真実を述べています。<br>それは誰？</h2><br> 
         <form action='goddesses.cgi' method='POST'>
           <table>
              <tr><td>女神Ａ：「最も美しいのは <input type='text' name='a' size='30' value='",A,"'>」　<br></td></tr>
              <tr><td>女神Ｂ：「最も美しいのは <input type='text' name='b' size='30' value='",B,"'>」　<br></td></tr>
              <tr><td>女神Ｃ：「最も美しいのは <input type='text' name='c' size='30' value='",C,"'>」　<br></td></tr>
              <tr><td><input type='checkbox' name='check' value='exp'>推論過程説明<br></td><td><input type='submit' value='推論実行'></td></tr>
           </table>
          </form>
          <h4>次の文字を利用して各々の主張を入力してください</h4> 
          <h5>Ａ　Ｂ　Ｃ　（　）　かつ　または　ではない　です　ならば(⇒)　であれば(⇔)</h5><br>",
              call(resolve(A,B,C,D)),	
	  "</center></body></html>" ]).

get_params([A,B,C,D]):- 
	get_parame(a,A),get_parame(b,B),get_parame(c,C),
	get_parame(check,D0),(D0==''->D=no;D0=D).

get_parame(A,B):- get_param(A,B),!.
get_parame(a,'Ｂではない'):-!.
get_parame(b,'Ｃではない'):-!.
get_parame(c,'Ｃです'):-!.
get_parame(_,'').

resolve(A,B,C,D):- 
    errormode(_,0),
    atom_appends([ 'h(Res,Ａ,Ｂ,Ｃ,',D,'),
					e(''A'',A,',D,',(Ａ であれば ',A,'),''',A,'''),
					e(''B'',B,',D,',(Ｂ であれば ',B,'),''',B,'''),
					e(''C'',C,',D,',(Ｃ であれば ',C,'),''',C,'''),
					ans(Res)'],X),
    spacer(X,Y),
    errorset( term_atom(T,Y), succ),
    setof(T,call(T),L),list(L),!.
resolve(A,B,C,D):- write('<h2>解がありません！</h2><br>'),nl.

ans(X):-write_listnl(['<br><h2>それは<font size="8" color ="Red">',X,'</font>です</h2><br>']).

spacer(X,Y):- name(X,L),spacein(L,LL),name(Y,LL).
spacein([],[]):-!.
spacein([A|L],[32,A,32|LL]):-s_member(A,"ＡＢＣABC"),!,spacein(L,LL).
spacein([A|L],[A|LL]):- spacein(L,LL).

s_member(A,[A|_]):-!.
s_member(A,[_|L]):- s_member(A,L).

%% プログラム始め

h(X,A,B,C,no):- !,仮説(X,A,B,C).

h(X,A,B,C,_):- 
	仮説(X,A,B,C),
	write_listnl(['<h3>【最も美しい女神を<font size="6" color ="blue"> ',X,'</font>と仮定すると】</h3>']),
	write_listnl(['<h5>女神Ａの主張は',A,'　女神Ｂの主張は',B,'　女神Ｃの主張は',C,'でなければなりません </h5>']).

仮説('A',真,偽,偽).
仮説('B',偽,真,偽).
仮説('C',偽,偽,真).

真:-true.
偽:-fail.

e(Who,_,no,X,_):-!,X.
e(Who,What,_,X,EXP):- write_list(['女神',Who,'の主張(',EXP,')は',What,'のはず']),X,!,write(' ===> そのとおりだ！<br>'),nl.
e(Who,What,_,X,_):- write(' ===>　だが、そうではない！<br> <font color="red">この仮定は誤りだった</font><br>'),nl,fail.

%% 演算子 %%
:- op(500,yfx,かつ).
かつ(A,B):-A,B.

:- op(500,yfx,または).
または(A,B):-A.
または(A,B):-B.

:- op(300,xf,ではない).
ではない(X):- \+(X).

:- op(1100,xf,です).
です(X):- X.

:- op(1000,xfy,ならば).
ならば(A,B):- \+(A),!.
ならば(A,B):- B.

:- op(1100,xfy,であれば).
であれば(A,B):- ならば(A,B),ならば(B,A).

/*
％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％
％％％％％    論理パズル「三人の女神」のプログラム説明      ％％％％％％
％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％％

＜ 三人の女神 ＞
  出展 BlueBacks 【論理パズル「出しっこ問題」傑作選 】小野田博一著

Ａ，Ｂ，Ｃ三人の女神が次のように述べています。

女神Ａ：「最も美しいのはＢではない」
女神Ｂ：「最も美しいのはＣではない」
女神Ｃ：「私が最も美しい」

最も美しい女神のみが真実を述べています。
それは誰？

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
０）命題論理の基礎

　　論理記号（　¬ ∧ ∨ ⇒ ⇔　）、命題変数、論理式、真理値表

１）「ある女神が最も美しい」とする命題Ｘは、真か偽の論理値をとる。
　　　女神Ａが最も美しいとする命題をＡ、
　　　女神Ｂが最も美しいとする命題をＢ、
　　　女神Ｃが最も美しいとする命題をＣ とする

　　　そして、最も美しいのは（日本語の感覚では）一人なのだからつぎの
　　　３つの組み合わせしかない。解はこのうちのどれかである。
　　　Ａ，Ｂ，Ｃの各命題変数のとり得る値の組には３つの仮説が立てられる。

    　第１の仮説： A=true,B=fail,C=fail     %Ａが最も美しい
    　第２の仮説： A=fail,B=true,C=fail     %Ｂが最も美しい
    　第３の仮説： A=fail,B=fail,C=true     %Ｃが最も美しい

２）「最も美しい女神のみが真実を述べている」という規則を論理式として現す。

　　「最も美しい女神」（１の命題が真）の場合はその主張は必ず真である。
　　「最も美しい女神でないもの」（１の命題が偽）の場合はその主張は必ず偽である。
　　すなわち、「ある女神が最も美しい」の論理値とその主張内容の論理値は等しい（同値）
　　ということをこのルールは定めている。これを論理式で表す。
　　これを、各女神の言明の論理値と仮に呼ぶ。

     女神Ｘの言明：　Ｘの論理値⇔Ｘの主張の論理値   ---> 式の値が真であることがこのルール

     （「最も美しい女神は必ず真実を述べ、そうでない女神は真実を述べるとは限らない」
        のであれば、 Ｘの論理値 ⇒Ｘの主張の論理値 --- この式の値が真である、となる ）

３）よって、各女神の言明はつぎのようにあらわすことができる。
   
　　　女神Ａ：「最も美しいのはＢではない」   A⇔¬B
　　　女神Ｂ：「最も美しいのはＣではない」   B⇔¬C
　　　女神Ｃ：「私が最も美しい」             C⇔C

４）各女神の言明の論理積が真であるものが解である。

　　　(A⇔¬B)∧(B⇔¬C)∧(C⇔C)

５）これは真理値表をもちいて機械的に解くことができる。

   A B C  ¬A ¬B ¬C   A⇔¬B  B⇔¬C  C⇔C   (A⇔¬B)∧(B⇔¬C)∧(C⇔C)
   ------+------------+----------------------++---------------------------
① T F F |  F   T   T |   T       F      T   ||        F
② F T F |  T   F   T |   T       T      T   ||        T      解
③ F F T |  T   T   F |   F       T      T   ||        F

★よって、最も美しい女神はＢということになる。


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

「最も美しい」が複数を認めれば別の解もある。
A B C  ¬A ¬B ¬C   A⇔¬B  B⇔¬C  C⇔C   (A⇔¬B)∧(B⇔¬C)∧(C⇔C)
------+------------+----------------------++---------------------------
T T T |  F   F   F |   F       F      T   ||        F
T T F |  F   F   T |   F       T      T   ||        F
T F T |  F   T   F |   T       T      T   ||        T   解
T F F |  F   T   T |   T       F      T   ||        F
F T T |  T   F   F |   T       F      T   ||        F
F T F |  T   F   T |   T       T      T   ||        T   解
F F T |  T   T   F |   F       T      T   ||        F
F F F |  T   T   T |   F       F      T   ||        F

「最も美しいのは一人のみ」を式で表すとこうなる（前記の３仮説の表現）

A B C  ¬A ¬B ¬C  (A∧¬B∧¬C)∨(B∧¬A∧¬C)∨(C∧¬A∧¬B)
------+------------+----------------------+---------------------------
T T T |  F   F   F | F ∨ F ∨ F ===> F
T T F |  F   F   T | F ∨ F ∨ F ===> F
T F T |  F   T   F | F ∨ F ∨ F ===> F
T F F |  F   T   T | T ∨ F ∨ F ===> T
F T T |  T   F   F | F ∨ F ∨ F ===> F
F T F |  T   F   T | F ∨ T ∨ F ===> T
F F T |  T   T   F | F ∨ F ∨ T ===> T
F F F |  T   T   T | F ∨ F ∨ F ===> F

上記二つを合成すると、組み合わせ仮説なしに解を導くことができる
(A∧¬B∧¬C)∨(B∧¬A∧¬C)∨(C∧¬A∧¬B)∧(A⇔¬B)∧(B⇔¬C)∧(C⇔C)
===========================================　=========================
 一人のみ　　　　　　　　　　　　　　　　　　　　各女神の言明

５）Ｐｒｏｌｏｇで容易に記述できる。
   ここでは、論理記号の入力を容易にするため、
   (¬   ∧  ∨  ⇒  ⇔ ）
   not and, or, imp, eq としている。

and(A,B):-A,B.                  % ∧

or(A,B):-A.                     % ∨
or(A,B):-B.

:- op(300,fx,not).
not(X):-X,!,fail.               % ¬
not(_).

:- op(1000,xfy,imp).
imp(A,B):-not(A),!.             % ⇒
imp(A,B):-B.

:- op(1000,xfy,eq).
eq(A,B):-imp(A,B),imp(B,A).     % ⇔

hypo('A',true,fail,fail).
hypo('B',fail,true,fail).
hypo('C',fail,fail,true).

bind(true).
bind(fail).

%% 問い合わせ
?- hypo(Ans,A,B,C), (A eq not B) and (B eq not C) and ( C eq C ).

?- bind(A),bind(B),bind(C),
  (A and not B and not C) or (B and not A and not C) or (C and not A and not B) 
  and (A eq not B) and (B eq not C) and ( C eq C ).

%% Prolog おわり

*/
