%------------------------------------------------------------------
% 人工知能特論  酒井 潤 
% [i215]prolog report4
%------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                     問題1 人食い土人と宣教師                       %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% debug
% spy([move_by_boat,state_of_safty,right_shore,left_shore,move]).
% spy([right_shore,left_shore,move]).
% spy([move_by_boat,state_of_safty]).
% spy(state_of_safty).
% spy(move_by_boat).

% 宣教師と人食いの移動
% 左の岸から移動する 初期条件
% left_shore(宣教師の人数、人食い土人の人数、以前の状態を保持ずるリスト)

move :- left_shore(3,3,[]).

% 2人乗りのボートで移動できる条件
% move_by_boat(宣教師の人数、人食い土人の人数)

move_by_boat(0,1).
move_by_boat(1,0).
move_by_boat(1,1).
move_by_boat(0,2).
move_by_boat(2,0).

% 安全な状態のときの条件
% state_of_safty(宣教師の人数、人食い土人の人数)

state_of_safty(0,_).
state_of_safty(3,_).
state_of_safty(1,1).
state_of_safty(2,2).

% 左岸にボートがあるときleft  右岸にボートがあるときright
% 船が右岸から左の岸に来たときのこちらの岸

right_shore(M,C,Path):-
	% 船で移動
	move_by_boat(Ms,Cs),
	% 宣教師の人数を計算
	M1 is M+Ms,M1 =<3,
	% 人食い土人の人数を計算
	C1 is C+Cs,C1 =<3,
	% 岸の安全状態を確認
	state_of_safty(M1,C1),
	% Loopの回避
	notloop([M1,C1,'left '],Path),
	% Pathリストへ状態を保存してleft_shoreへ再起 	
	left_shore(M1,C1,[[M,C,right]|Path]).

% 左岸にボートがあるときleft  右岸にボートがあるときright
% 船が左岸から右岸に行ったときのこちらの岸

left_shore(M,C,Path) :-
	% 船で移動
	move_by_boat(Ms,Cs),
	% 宣教師の人数を計算	
	M1 is M - Ms,M1 >=0,
	% 人食い土人の人数を計算
	C1 is C - Cs,C1 >=0,
	% 岸の安全状態を確認
	state_of_safty(M1,C1),
	% Loopの回避
	notloop([M1,C1,right],Path),
	% Pathリストへ状態を保存してright_shoreへ再起
	right_shore(M1,C1,[[M,C,'left ']|Path]).

% 宣教師と人食い土人が右岸にすべてついたら終了
right_shore(0,0,Path):-
	% Loopの回避
	notloop([0,0,right],Path),
	% 経路を逆に並べ替える	
	reverse(Path,ReversePath),
	% 最終状態を追加
 	append(ReversePath,[[0,0,right]],Result),	
 	% 画面出力 
	nl,write('-path- '),nl,
	write('left shore'),
	write('                   '),
	write('right shore'),
	write('                  '),
	write('boat'),nl,
	result(Result),fail.

% 結果出力 missionary(宣教師) cannibal(人食い土人)boat(ボートの岸の位置)
result([]).
result([[M,C,B]|R]):-
	write('missionary: '),write(M),
	write('  '),
	write('cannibal: '),write(C),
		
	write(' | '),
	M1 is 3 - M,
	C1 is 3 - C,
	write('missionary: '),write(M1),
	write('  '),
	write('cannibal: '),write(C1),
			
	write(' | '),
	write('boat: '),write(B),nl,
	result(R).

% 同じ状態に戻らないようにnotloopをいれる
loop(State,Path) :- member(State,Path).
notloop(X,Y) :- loop(X,Y),!,fail.
notloop(_,_).

% member
member(X,[X|_]) :- !.
member(X,[_|R]) :- member(X,R).

% append
append([],L,L).
append([X|L1],L2,[X|L3]):-
	append(L1,L2,L3).

% リストを逆転させる
reverse([],[]).
reverse([F|R],Rs):-
	reverse(R,Z),
	append(Z,[F],Rs).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                            実行結果                                 %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

| ?- move.

-path- 
left shore                   right shore                  boat
missionary: 3  cannibal: 3 | missionary: 0  cannibal: 0 | boat: left 
missionary: 2  cannibal: 2 | missionary: 1  cannibal: 1 | boat: right
missionary: 3  cannibal: 2 | missionary: 0  cannibal: 1 | boat: left 
missionary: 3  cannibal: 0 | missionary: 0  cannibal: 3 | boat: right
missionary: 3  cannibal: 1 | missionary: 0  cannibal: 2 | boat: left 
missionary: 1  cannibal: 1 | missionary: 2  cannibal: 2 | boat: right
missionary: 2  cannibal: 2 | missionary: 1  cannibal: 1 | boat: left 
missionary: 0  cannibal: 2 | missionary: 3  cannibal: 1 | boat: right
missionary: 0  cannibal: 3 | missionary: 3  cannibal: 0 | boat: left 
missionary: 0  cannibal: 1 | missionary: 3  cannibal: 2 | boat: right
missionary: 0  cannibal: 2 | missionary: 3  cannibal: 1 | boat: left 
missionary: 0  cannibal: 0 | missionary: 3  cannibal: 3 | boat: right

-path- 
left shore                   right shore                  boat
missionary: 3  cannibal: 3 | missionary: 0  cannibal: 0 | boat: left 
missionary: 2  cannibal: 2 | missionary: 1  cannibal: 1 | boat: right
missionary: 3  cannibal: 2 | missionary: 0  cannibal: 1 | boat: left 
missionary: 3  cannibal: 0 | missionary: 0  cannibal: 3 | boat: right
missionary: 3  cannibal: 1 | missionary: 0  cannibal: 2 | boat: left 
missionary: 1  cannibal: 1 | missionary: 2  cannibal: 2 | boat: right
missionary: 2  cannibal: 2 | missionary: 1  cannibal: 1 | boat: left 
missionary: 0  cannibal: 2 | missionary: 3  cannibal: 1 | boat: right
missionary: 0  cannibal: 3 | missionary: 3  cannibal: 0 | boat: left 
missionary: 0  cannibal: 1 | missionary: 3  cannibal: 2 | boat: right
missionary: 1  cannibal: 1 | missionary: 2  cannibal: 2 | boat: left 
missionary: 0  cannibal: 0 | missionary: 3  cannibal: 3 | boat: right

-path- 
left shore                   right shore                  boat
missionary: 3  cannibal: 3 | missionary: 0  cannibal: 0 | boat: left 
missionary: 3  cannibal: 1 | missionary: 0  cannibal: 2 | boat: right
missionary: 3  cannibal: 2 | missionary: 0  cannibal: 1 | boat: left 
missionary: 3  cannibal: 0 | missionary: 0  cannibal: 3 | boat: right
missionary: 3  cannibal: 1 | missionary: 0  cannibal: 2 | boat: left 
missionary: 1  cannibal: 1 | missionary: 2  cannibal: 2 | boat: right
missionary: 2  cannibal: 2 | missionary: 1  cannibal: 1 | boat: left 
missionary: 0  cannibal: 2 | missionary: 3  cannibal: 1 | boat: right
missionary: 0  cannibal: 3 | missionary: 3  cannibal: 0 | boat: left 
missionary: 0  cannibal: 1 | missionary: 3  cannibal: 2 | boat: right
missionary: 0  cannibal: 2 | missionary: 3  cannibal: 1 | boat: left 
missionary: 0  cannibal: 0 | missionary: 3  cannibal: 3 | boat: right

-path- 
left shore                   right shore                  boat
missionary: 3  cannibal: 3 | missionary: 0  cannibal: 0 | boat: left 
missionary: 3  cannibal: 1 | missionary: 0  cannibal: 2 | boat: right
missionary: 3  cannibal: 2 | missionary: 0  cannibal: 1 | boat: left 
missionary: 3  cannibal: 0 | missionary: 0  cannibal: 3 | boat: right
missionary: 3  cannibal: 1 | missionary: 0  cannibal: 2 | boat: left 
missionary: 1  cannibal: 1 | missionary: 2  cannibal: 2 | boat: right
missionary: 2  cannibal: 2 | missionary: 1  cannibal: 1 | boat: left 
missionary: 0  cannibal: 2 | missionary: 3  cannibal: 1 | boat: right
missionary: 0  cannibal: 3 | missionary: 3  cannibal: 0 | boat: left 
missionary: 0  cannibal: 1 | missionary: 3  cannibal: 2 | boat: right
missionary: 1  cannibal: 1 | missionary: 2  cannibal: 2 | boat: left 
missionary: 0  cannibal: 0 | missionary: 3  cannibal: 3 | boat: right

no
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                     問題2 狂暴な訳あり一家                         %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% debug
% spy([move_by_boat,state_of_safty,right_shore,left_shore,move]).
% spy([right_shore,left_shore,move]).
% spy([move_by_boat,state_of_safty]).
% spy(state_of_safty).
% spy(move_by_boat).

% 2人乗りのボートで移動できる条件
% ボートを漕げるのは父親、母親、召使
% move_by_boat(Father Mother Son Daughter Dauhter Serbant Dog)
% 父親、母親、息子、娘、召使、犬の人数

% 左の岸から移動する
% move_by_boat(父親、母親、息子、娘、召使、犬の人数、状態を保持するリスト)
move :- left_shore(1,1,2,2,1,1,[]).

% 父親との組み合わせ
move_by_boat(1,0,0,0,0,0).
move_by_boat(1,1,0,0,0,0).
move_by_boat(1,0,1,0,0,0).
move_by_boat(1,0,0,1,0,0).
move_by_boat(1,0,0,0,1,0).
move_by_boat(1,0,0,0,0,1).

% 母親との組み合わせ
move_by_boat(0,1,0,0,0,0).
move_by_boat(0,1,1,0,0,0).
move_by_boat(0,1,0,1,0,0).
move_by_boat(0,1,0,0,1,0).
move_by_boat(0,1,0,0,0,1).

% 召使との組み合わせ
move_by_boat(0,0,0,0,1,0).
move_by_boat(0,0,1,0,1,0).
move_by_boat(0,0,0,1,1,0).
move_by_boat(0,0,0,0,1,1).

% 左岸と右岸の安全な状態のときのこちらの状態
% state_of_safty((父親、母親、息子、娘、召使、犬の人数)

state_of_safty(1,1,_,_,X,X).
state_of_safty(1,0,2,0,X,X).
state_of_safty(0,1,0,2,X,X).
state_of_safty(0,0,_,_,X,X).
state_of_safty(1,1,2,2,1,0).
state_of_safty(0,0,0,0,0,1).

% 左岸のにボートがあるときleft  右岸の状態right
% 船が右岸から左の岸に来たときのこちらの岸

right_shore(A,B,C,D,E,F,Path):-
	% 船で移動
	move_by_boat(As,Bs,Cs,Ds,Es,Fs),
	% 人数を計算
	A1 is A+As,A1 =<1,
	B1 is B+Bs,B1 =<1,
	C1 is C+Cs,C1 =<2,
	D1 is D+Ds,D1 =<2,
	E1 is E+Es,E1 =<1,
	F1 is F+Fs,F1 =<1,
	% 岸の安全状態を確認
	state_of_safty(A1,B1,C1,D1,E1,F1),
	% Loopの回避
	notloop([A1,B1,C1,D1,E1,F1,left],Path),
	% Pathリストへ状態の履歴を保存してleft_shoreへ再起 	
	left_shore(A1,B1,C1,D1,E1,F1,[[A,B,C,D,E,F,right]|Path]).

% 船が左岸から右岸に行ったときのこちらの岸
left_shore(A,B,C,D,E,F,Path) :-
	% 船で移動
	move_by_boat(As,Bs,Cs,Ds,Es,Fs),
	% 人数を計算
	A1 is A - As,A1 >=0,
	B1 is B - Bs,B1 >=0,
	C1 is C - Cs,C1 >=0,
	D1 is D - Ds,D1 >=0,
	E1 is E - Es,E1 >=0,
	F1 is F - Fs,F1 >=0,
	% 岸の安全状態を確認
	state_of_safty(A1,B1,C1,D1,E1,F1),
	% Loopの回避
	notloop([A1,B1,C1,D1,E1,F1,right],Path),
	% Pathリストへ状態の履歴を保存してright_shoreへ再起
	right_shore(A1,B1,C1,D1,E1,F1,[[A,B,C,D,E,F,left]|Path]).

% 宣教師と人食い土人が右岸にすべてついたら終了
right_shore(0,0,0,0,0,0,Path):-
	% Loopの回避
	notloop([0,0,0,0,0,0,right],Path),
	% 経路を逆に並べ替える	
	reverse(Path,ReversePath),
	% 最終状態を追加
	append(ReversePath,[[0,0,0,0,0,0,right]],Result),	
 	% 結果出力 path
	% write(path),nl,
	% write(Result),nl,fail.
	nl,write('-path- '),nl,
	write('left shore'),
	write('                                                      '),
	write('right shore'),
	write('                                                     '),
	write('boat'),nl,
	result(Result),fail.
	

% 結果出力 (Father Mother Son Daughter Dauhter Serbant Dog)
result([]).
result([[A,B,C,D,E,F,G]|R]):-
	write('father: '),write(A),
	write('  '),
	write('mother: '),write(B),
	write('  '),
	write('son: '),write(C),
	write('  '),
	write('daughter: '),write(D),
	write('  '),
	write('serbant: '),write(E),
	write('  '),
	write('dog: '),write(F),
	
	write(' | '),
	A1 is 1 - A,
	B1 is 1 - B,
	C1 is 2 - C,
	D1 is 2 - D,
	E1 is 1 - E,
	F1 is 1 - F,
	write('father: '),write(A1),
	write('  '),
	write('mother: '),write(B1),
	write('  '),
	write('son: '),write(C1),
	write('  '),
	write('daughter: '),write(D1),
	write('  '),
	write('serbant: '),write(E1),
	write('  '),
	write('dog: '),write(F1),
		
	write(' | '),
	write('boat: '),write(G),nl,
	result(R).

% 同じ状態に戻らないようにnotloopをいれる
loop(State,Path) :- member(State,Path).
notloop(X,Y) :- loop(X,Y),!,fail.
notloop(_,_).

% member
member(X,[X|_]) :- !.
member(X,[_|R]) :- member(X,R).

% append
append([],L,L).
append([X|L1],L2,[X|L3]):-
	append(L1,L2,L3).

% リストを逆転させる

reverse([],[]).
reverse([F|R],Rs):-
	reverse(R,Z),
	append(Z,[F],Rs).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                           実行結果                                                                      %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
| ?- move.

-path- 
left shore                                                      right shore                                                     boat
father: 1  mother: 1  son: 2  daughter: 2  serbant: 1  dog: 1 | father: 0  mother: 0  son: 0  daughter: 0  serbant: 0  dog: 0 | boat: left
father: 1  mother: 1  son: 2  daughter: 2  serbant: 0  dog: 0 | father: 0  mother: 0  son: 0  daughter: 0  serbant: 1  dog: 1 | boat: right
father: 1  mother: 1  son: 2  daughter: 2  serbant: 1  dog: 0 | father: 0  mother: 0  son: 0  daughter: 0  serbant: 0  dog: 1 | boat: left
father: 1  mother: 1  son: 1  daughter: 2  serbant: 0  dog: 0 | father: 0  mother: 0  son: 1  daughter: 0  serbant: 1  dog: 1 | boat: right
father: 1  mother: 1  son: 1  daughter: 2  serbant: 1  dog: 1 | father: 0  mother: 0  son: 1  daughter: 0  serbant: 0  dog: 0 | boat: left
father: 0  mother: 1  son: 0  daughter: 2  serbant: 1  dog: 1 | father: 1  mother: 0  son: 2  daughter: 0  serbant: 0  dog: 0 | boat: right
father: 1  mother: 1  son: 0  daughter: 2  serbant: 1  dog: 1 | father: 0  mother: 0  son: 2  daughter: 0  serbant: 0  dog: 0 | boat: left
father: 0  mother: 0  son: 0  daughter: 2  serbant: 1  dog: 1 | father: 1  mother: 1  son: 2  daughter: 0  serbant: 0  dog: 0 | boat: right
father: 0  mother: 1  son: 0  daughter: 2  serbant: 1  dog: 1 | father: 1  mother: 0  son: 2  daughter: 0  serbant: 0  dog: 0 | boat: left
father: 0  mother: 1  son: 0  daughter: 2  serbant: 0  dog: 0 | father: 1  mother: 0  son: 2  daughter: 0  serbant: 1  dog: 1 | boat: right
father: 1  mother: 1  son: 0  daughter: 2  serbant: 0  dog: 0 | father: 0  mother: 0  son: 2  daughter: 0  serbant: 1  dog: 1 | boat: left
father: 0  mother: 0  son: 0  daughter: 2  serbant: 0  dog: 0 | father: 1  mother: 1  son: 2  daughter: 0  serbant: 1  dog: 1 | boat: right
father: 0  mother: 1  son: 0  daughter: 2  serbant: 0  dog: 0 | father: 1  mother: 0  son: 2  daughter: 0  serbant: 1  dog: 1 | boat: left
father: 0  mother: 0  son: 0  daughter: 1  serbant: 0  dog: 0 | father: 1  mother: 1  son: 2  daughter: 1  serbant: 1  dog: 1 | boat: right
father: 0  mother: 0  son: 0  daughter: 1  serbant: 1  dog: 1 | father: 1  mother: 1  son: 2  daughter: 1  serbant: 0  dog: 0 | boat: left
father: 0  mother: 0  son: 0  daughter: 0  serbant: 0  dog: 1 | father: 1  mother: 1  son: 2  daughter: 2  serbant: 1  dog: 0 | boat: right
father: 0  mother: 0  son: 0  daughter: 0  serbant: 1  dog: 1 | father: 1  mother: 1  son: 2  daughter: 2  serbant: 0  dog: 0 | boat: left
father: 0  mother: 0  son: 0  daughter: 0  serbant: 0  dog: 0 | father: 1  mother: 1  son: 2  daughter: 2  serbant: 1  dog: 1 | boat: right

-path- 
left shore                                                      right shore                                                     boat
father: 1  mother: 1  son: 2  daughter: 2  serbant: 1  dog: 1 | father: 0  mother: 0  son: 0  daughter: 0  serbant: 0  dog: 0 | boat: left
father: 1  mother: 1  son: 2  daughter: 2  serbant: 0  dog: 0 | father: 0  mother: 0  son: 0  daughter: 0  serbant: 1  dog: 1 | boat: right
father: 1  mother: 1  son: 2  daughter: 2  serbant: 1  dog: 0 | father: 0  mother: 0  son: 0  daughter: 0  serbant: 0  dog: 1 | boat: left
father: 1  mother: 1  son: 2  daughter: 1  serbant: 0  dog: 0 | father: 0  mother: 0  son: 0  daughter: 1  serbant: 1  dog: 1 | boat: right
father: 1  mother: 1  son: 2  daughter: 1  serbant: 1  dog: 1 | father: 0  mother: 0  son: 0  daughter: 1  serbant: 0  dog: 0 | boat: left
father: 1  mother: 0  son: 2  daughter: 0  serbant: 1  dog: 1 | father: 0  mother: 1  son: 0  daughter: 2  serbant: 0  dog: 0 | boat: right
father: 1  mother: 1  son: 2  daughter: 0  serbant: 1  dog: 1 | father: 0  mother: 0  son: 0  daughter: 2  serbant: 0  dog: 0 | boat: left
father: 0  mother: 0  son: 2  daughter: 0  serbant: 1  dog: 1 | father: 1  mother: 1  son: 0  daughter: 2  serbant: 0  dog: 0 | boat: right
father: 1  mother: 0  son: 2  daughter: 0  serbant: 1  dog: 1 | father: 0  mother: 1  son: 0  daughter: 2  serbant: 0  dog: 0 | boat: left
father: 1  mother: 0  son: 2  daughter: 0  serbant: 0  dog: 0 | father: 0  mother: 1  son: 0  daughter: 2  serbant: 1  dog: 1 | boat: right
father: 1  mother: 1  son: 2  daughter: 0  serbant: 0  dog: 0 | father: 0  mother: 0  son: 0  daughter: 2  serbant: 1  dog: 1 | boat: left
father: 0  mother: 0  son: 2  daughter: 0  serbant: 0  dog: 0 | father: 1  mother: 1  son: 0  daughter: 2  serbant: 1  dog: 1 | boat: right
father: 1  mother: 0  son: 2  daughter: 0  serbant: 0  dog: 0 | father: 0  mother: 1  son: 0  daughter: 2  serbant: 1  dog: 1 | boat: left
father: 0  mother: 0  son: 1  daughter: 0  serbant: 0  dog: 0 | father: 1  mother: 1  son: 1  daughter: 2  serbant: 1  dog: 1 | boat: right
father: 0  mother: 0  son: 1  daughter: 0  serbant: 1  dog: 1 | father: 1  mother: 1  son: 1  daughter: 2  serbant: 0  dog: 0 | boat: left
father: 0  mother: 0  son: 0  daughter: 0  serbant: 0  dog: 1 | father: 1  mother: 1  son: 2  daughter: 2  serbant: 1  dog: 0 | boat: right
father: 0  mother: 0  son: 0  daughter: 0  serbant: 1  dog: 1 | father: 1  mother: 1  son: 2  daughter: 2  serbant: 0  dog: 0 | boat: left
father: 0  mother: 0  son: 0  daughter: 0  serbant: 0  dog: 0 | father: 1  mother: 1  son: 2  daughter: 2  serbant: 1  dog: 1 | boat: right

no
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                            解説 感想                                %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
サルとバナナの問題を参考にしてnotloopを用いることにより同じ状況
でボートが往復しないように防止した。以前にも同じ状況がでてきた場合にはfail
にするように一度成功した状態をPathという名前のリストに保持して、そのPathの
なかに一度あった状態のものがあればfailするようにした。
岸における条件でつかうため move_by_boat によりボートによって移動できる状態
を定義した。
state_of_safty も岸における条件でつかうために安全な状態として定義した。
初め下記のような条件で定義していたが デバックしてみると同じ人数で移動する
条件をstate_of_safty(X,X) としていたため 先に定義している(0,_)(3,_)と
で(0,0)(3,3)がかぶっており無駄なことしていることに気ずいた。

安全な状態のときの条件
state_of_safty(0, _).
state_of_safty(3, _).
state_of_safty(X, X).

right_shoreとleft_shoreでボートが右岸、左岸にあるときのこちらの岸の状態
の条件をつけていき条件が成り立てば反対の岸に移動できるように条件をつけて
いった。まず船で移動できる人数を探し、その人数で移動した場合の計算をし
それが安全な状態かを確認する。そしてそれが以前と同じ状態でループする場合には
failし、そうでない場合はPathリストに保持して反対の岸へ移動できるかどうか
を判定した。
終了条件をすべてこちらの岸へだれもいなくなった状態であれば終了とし画面出力
するようにした。

画面出力の場合リストに最後の状態から保持していってるため順序が逆になっている
そのためリストを逆順にならびかえるreverseを定義しリストを逆順に並びかえた。

reverse([],[]).
reverse([F|R],Rs):-
	reverse(R,Z),
	append(Z,[F],Rs).

最終条件になったときまだPathリストへ(0,0,right)の状態が保持されていないため
appendで並び替えた最後に加える。これをすることにより次の順序を見つけるため
のバックトラックさせるためPathのリストへ保持しておく。

並び替えたリストの引数が何がしめされているかわかるように一つ一つ摘出して
画面出力していった。

-path- 
left shore                   right shore                  boat
missionary: 3  cannibal: 3 | missionary: 0  cannibal: 0 | boat: left 
missionary: 3  cannibal: 1 | missionary: 0  cannibal: 2 | boat: right

pathがこちらの岸の状態の順序を示す一つの方法で全部で4通り順序があった。
missinonary が宣教師で cannibal が人食い土人 left shore ,rightshore
はそれぞれ左岸、右岸である。boat はいまボートがどちらの岸にあるかを示している。



問題3の方は、問題1と同様な考えて行った。しかし2人乗りのボートで移動できる
状態と安全な状態を作るの苦労した。犬は召使がいないと他の家族を殺してしまう
という条件があったため、召使といっしょに犬以外の人がボートに乗ってしまうと
犬が岸に残されてしまい、そこにいる家族を殺してしまうと思っていたが、犬だけ
が岸にのっこていてもいいということに気ずくのに大変苦労した。何度もデバック
して確かめていき岸にいる人数の計算をトレースしていった。なぜfailしてしまう
のか一つ一つおっていくことにより、発見することができた.
また安全な岸の状態をつくる場合でも、つねにこちらの岸の状態だけを考えていた
ためにすぐにfailしてしまうことがおおかた。下に説明を書きます。

娘を殺すことができる父がいるが、母がいるために娘を殺せない。
息子を殺すことができる母がいるが、父がいるために息子を殺せない。
召使は犬といるか二人ともいないかのどちらかであるので安全。

state_of_safty(1,1,_,_,X,X).

娘を殺す父がいて母がいないが、二人とも娘もいなので安全。
そして右岸には母がいるが息子が二人ともいないので安全。
召使は犬といるか二人ともいないかのどちらかであるので安全。

state_of_safty(1,0,2,0,X,X).

息子を殺す母がいて父がいないが、二人とも息子もいなので安全。
そして右岸には父がいるが息子が二人ともいないので安全。
召使は犬といるか二人ともいないかのどちらかであるので安全。

state_of_safty(0,1,0,2,X,X).

父と母がいないため息子と娘は殺されない。
右岸にも父と母がいるため息子と娘がいてもころされない。
召使は犬といるか二人ともいないかのどちらかであるので安全。

state_of_safty(0,0,_,_,X,X).

父と母がいるので息子と娘は殺されない。
右岸は犬だけなので安全

state_of_safty(1,1,2,2,1,0).

犬だけなので安全
右岸には父と母がいるので息子と娘は殺されない。

state_of_safty(0,0,0,0,0,1).

デバックしていてこれに気ずくのに時間がかかった。まずmove_by_boatと同様に
犬が一匹だけで岸にいても良いということに気ずかなかった。そして父親がいて
娘がいないのを初め下記のように定義していたため、state_of_safty(1,0,0,1,X,X).
という条件ができてしまい、右岸の状態で父がいなく母と息子1一人という状態
ができていた。そのためにfailしていた。

state_of_safty(1,0,0,_,X,X).

後は問題1と同様にPathのリストに加えて、順序を画面出力するための定義をした。
father,mother,daughter,serbant,dog,は
それぞれ父親、母親、娘、召使、犬のこちらの岸での人数である.
left shore  right shore はそれぞれ左岸、右岸である。
またboatはとちらの岸にあるかということである。
結果は2通りの順路があることなった。

-path- 
left shore                                                      right shore                                                     boat
father: 1  mother: 1  son: 2  daughter: 2  serbant: 1  dog: 1 | father: 0  mother: 0  son: 0  daughter: 0  serbant: 0  dog: 0 | boat: left
father: 1  mother: 1  son: 2  daughter: 2  serbant: 0  dog: 0 | father: 0  mother: 0  son: 0  daughter: 0  serbant: 1  dog: 1 | boat: right

書いていたことを知り。こうしておくとデバックするときにコピーしてすぐに
実行できることをしり、デバックでの記述が早く行うことができた。

% debug
% spy([move_by_boat,state_of_safty,right_shore,left_shore,move]).
% spy([right_shore,left_shore,move]).
% spy([move_by_boat,state_of_safty]).
% spy(state_of_safty).
% spy(move_by_boat).

今回までのprolog演習で、パターンマッチング、ユニフィケーション、木構造、
バックトラックというprologの特徴を理解できた。また、prologの性質以外にも
いままで、プログラムを書いていてあまり気にしていなかった効率のよい
プログラムを書くということなどを知った。今回の演習ではバックトラックを
カットを用いて他の選択を消すことや条件がかぶってしまっているようなものを
削除することによって効率の良いプログラムを書くことができた。またデバック
の重要さがよくわかった。デバックによって早期にバグを見つけることができた。


%------------------------------------------------------------------
% 人工知能特論  酒井 潤 
% [i215]prolog report3
%------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                              問題2ー1                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% islistでなければ成功する
% islistであればfailとなり失敗する

islist([ ]).
islist([_ | _]).

isnotlist(X) :-islist(X),!,fail.
isnotlist(_).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                            実行結果                                 %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% | ?- isnotlist([]).
%
% no
% ?- isnotlist(a).
%
% yes
% | ?- isnotlist([a,b,c]).
% 
% no
% | ?- isnotlist(jun).
% 
% yes
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                              問題2ー2                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%数のリストを正のリストPと負のリストNに分ける
%リストのHEADが0以上ならPのリストへいれ再起
%リストのHEADが0より小さいときはNのリストへいれ再起

split([],[],[]).
split([HX|RX],[HX|RP],N):-HX>=0,split(RX,RP,N).
split([HX|RX],P,[HX|RN]):-HX<0,split(RX,P,RN).


%カットを使う場合 split2として定義する

split2([],[],[]).
split2([HX|RX],[HX|RP],N):-HX>=0,!,split2(RX,RP,N).
split2([HX|RX],P,[HX|RN]):-split2(RX,P,RN).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                            実行結果                                 %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% | ?- split([3,-1,0,5,-2],P,N).
% 
% N = [-1,-2],
% P = [3,0,5] ? ;
% 
% no
% | ?- split([3,-1,0,5,-2,3,-1,2,-1,4,-2,-6],P,N).
% 
% N = [-1,-2,-1,-1,-2,-6],
% P = [3,0,5,3,2,4] ? ;
% 
% no
% | ?-  split([23,-12,345,-222],P,N).
% 
% N = [-12,-222],
% P = [23,345] ? ;
% 
% no
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                              問題2ー3                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%XとYがリストであるときにZが左集合の関係であるような述語difference(X,Y,Z)


% メンバーシップ
% Xがリストに入っていたら真である。

member(X,[X|_]).
member(X,[_|R]):-member(X,R).

% リストの共通部分をつくる述語をjoinとし定義する
% 1つめのリストの先頭が2つめのリストの中にあれば
% その共通部分のリストとする

join([],_,[]).
join([HX|RX],Y,[HX|RZ]):-member(HX,Y),join(RX,Y,RZ).
join([_|RX],Y,Z):-join(RX,Y,Z).

% remove

remove(X,[X|RY],RY).
remove(X,[HY|RY],[HY|RZ]):-remove(X,RY,RZ).

% removelist

removelist([],Y,Y).
removelist([HX|RX],Y,Z):-remove(HX,Y,A),removelist(RX,A,Z).

% XとYがリストであるときにZが左集合の関係であるような述語difference(X,Y,Z)
% 共通部分joinで導出した後removelistでそのリストを削除する

difference(X,Y,Z):-join(X,Y,A),!,removelist(A,X,Z).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                            実行結果                                 %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% | ?- difference([a,b,c,d],[b,d,e,f],X).
% 
% X = [a,c] ? 
% 
% no
% 
% | ?- difference([a,b,c,d,e,f,g,h],[b,d,f,r],X).
% 
% X = [a,c,e,g,h] ? 
% 
% no
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                              問題2ー4                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% append 
append([],Y,Y).
append([H|X],Y,[H|Z]):-append(X,Y,Z).

% 木構造を表すリスト
% 初めのものがリストかどうか判定し場合わけをしていく
tree2words(T,Z):-
	word(T,_,Z).
word([W|[]],B,Z):- 
	isnotlist(W),
	append(B,[W],Z).
word([L|R],B,Z):-
	isnotlist(L),
	word(R,B,Z),!.
word([L|[]],B,Z):-
	word(L,B,Z),!.
word([L|R],B,Z):-
	word(L,B,B1),!,
	word(R,B1,Z),!.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                            実行結果                                 %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 
% | ?- tree2words([s,[np,[pron,she]],[vp,[tv,loves],[np,[pron,you]]]],X).
% 
% X = [she,loves,you] ? ;
% 
% no
% 
% | ?- tree2words([s,[np,[pron,sakai]],[vp,[tv,loves],[np,[pron,myself]]]],X).
% 
% X = [sakai,loves,myself] ? ;
% 
% no
% 
% 
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                           解説 感想                                 %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% 問題2ー1では、ツリー構造を考え入力されるものをprintを使いトレースする
% ことで求めることができた。isnotlistの入力にリストで入力してしまい
% 間違えていたがislistでリスト判定するということがわかりうまく解を
% 求めることができた。
%
% islist([ ]).
% islist([_ | _]).
% 
% isnotlist(X) :- print(X),islist(X),!,print(X),fail.
% isnotlist(_).
% | ?- isnotlist(a).
% 
% yes
% | ?- isnotlist([a]).
% [a][a]
% no
% | ?- 
% 
% 問題2ー2ではdebugをすることにより間違っているか正しいものかを判断する
% ためのtoolとして有効に使うことができた。また再起で呼び出されそれが
% ユニフィケーションしている手順をトレースすることができ、よりリストの
% 再起処理を理解することができた。
% 
% | ?- split([3,-1,0,5,-2],P,N).
%  + 1  1  Call: split([3,-1,0,5,-2],_111,_125) ? 
%  + 2  2  Call: split([-1,0,5,-2],_401,_125) ? 
%  + 3  3  Call: split([0,5,-2],_401,_596) ? 
%  + 4  4  Call: split([5,-2],_790,_596) ? 
%  + 5  5  Call: split([-2],_983,_596) ? 
%  + 6  6  Call: split([],_983,_1175) ? 
%  + 6  6  Exit: split([],[],[]) ? 
%  + 5  5  Exit: split([-2],[],[-2]) ? 
%  + 4  4  Exit: split([5,-2],[5],[-2]) ? 
%  + 3  3  Exit: split([0,5,-2],[0,5],[-2]) ? 
%  + 2  2  Exit: split([-1,0,5,-2],[0,5],[-1,-2]) ? 
%  + 1  1  Exit: split([3,-1,0,5,-2],[3,0,5],[-1,-2]) ? 
% 
% N = [-1,-2],
% P = [3,0,5] ? 
% 
% yes
% 
% splitのカットの場合をsplit2として定義した。!の位置をリストの先頭が0
% 以上の判定のあとに置き、split2が呼び出され HX>=0 が失敗したら制御は下の
% split2へいく。HX>=0 が成りたち ! を越えた場合は次のsplitへの選択にはいかない
% 
% split2([],[],[]).
% split2([HX|RX],[HX|RP],N):-HX>=0,!,split2(RX,RP,N).
% split2([HX|RX],P,[HX|RN]):-split2(RX,P,RN).
% 
% 問題の2ー3では、memberをもちい共通部分を導出するjoinをつくりそのjoin
% で導出されたものをremovelistをもちいて削除している。初めはremovelistの 
% 削除するものの位置をを変えていただけだが、このままだと
% difference([a,b,c,d],[b,d],X)というもので解が[a,c]とでるが
% difference([a,b,c,d],[b,d,e,f],X).にたいして解がでてこない。
% debugしてみるとXに値がユニフィケーションされず入っていない。
% そのため削除するものをjoinとしてremovelistでそのリストを削除することにした
%  
% {Warning: [A] - singleton variables in join/3 in lines 95-96}
%
% またこのようなコンパイル時のエラーは[A]の部分を[_]とすることにより
% エラーをなくすことができることが多かった。
% 
% 問題2ー4ではリストの初めがリストでなかった場合、その次のものがまだ
% リストの場合はまた再起する。空の場合はappendして加えていく。
% 初めがリストの場合も、次がリストか空の場合に分け初めがリストなので
% ふたたび再起する。再起する際に他の選択にならないのでcutをもちいて他の
% 選択を消す。そして木の構造に合わせてappendしていく。
% 初めは問題の意味 を間違えてしまい。葉の部分のファクトを書き、
% それを付け加えていき構文にしてしまっていた。
%
% 今回のレポートはデバックによりバグをみつけ理解していくことが多かった
% またcutを用いることにより他の選択を切ることができ、きれいで早く判定できる
% プログラムを書くことができた。何度もコンパイルしていきWarningの意味も
% わかっていきプログラムの訂正がはやく行えるようになった。
% 

%------------------------------------------------------------------
% 人工知能特論  酒井 潤 
% [i215]prolog report2
%------------------------------------------------------------------

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                              問題1                                 %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% XはYの親である
parent(lamech,noah).
parent(methuselah,lamech).
parent(enoch,methuselah).
parent(jared,enoch).
parent(mahalaleel,jared).
parent(cainan,mahalaleel).
parent(enos,cainan).
parent(seth,enos).
parent(adam,seth).

% 条件1
% XはZの祖先である
ancestor(X,Z) :-
    parent(X,Z).

% 条件2
% XはZの祖先であるのは
% XがYの親であり
% YがZの祖先であるようなYが存在するとき
ancestor(X,Z) :-
    parent(X,Y),
    ancestor(Y,Z).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                               実行結果                               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
%                             
% | ?- ancestor(X,noah).
%
% X = lamech ? ;
%
% X = methuselah ? ;
% 
% X = enoch ? ;
% 
% X = jared ? ;
% 
% X = mahalaleel ? ;
% 
% X = cainan ? ;
% 
% X = enos ? ;
% 
% X = seth ? ;
% 
% X = adam ? ;
% 
% no
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                       プログラムの解説、感想                         %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% ancestor(X,Z):-
%     parent(X,Y).
% ancestor(X,Z):-
%     parent(X,Y1),
%     parent(X,Z).
% accestor(X,Z):-
%     parent(X,Y1),
%     parent(Y1,Y2),
%     ...........
% 
% と続けていっていくと家系図の決まった深さの祖先しか発見できない。
% ancestor自身を使うことによって再起的に定義することができる。
% このように再帰的に定義することができるものがあれば
% プログラムもきれいに書けると思う。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                問題2                                %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                              問題2の1                              %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%入力がリストであるかどうかを判断する
%リストが分解でき残りを再帰的に定義し空になったらリストである 
islist([]).
islist([_|X]):-
    islist(X).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                               実行結果                               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% | ?- islist([a]).
% 
% yes
% 
% | ?- islist([[a,b],[c,[d]],e]).
% 
% yes
% 
% | ?- islist(a).
% 
% no
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                              問題2の2                              %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% リストCの中にある、Aで指定した要素をBで指定した要素に一つだけ書き換えた
% 結果がDである
% リストを先頭と残りにわけ、先頭とAが一致したら結果にBを入れ解をだす。
% 一致しなければその先頭をそのまま結果にいれ、残りが空でなければ
% 再起的に定義し、一致したら再び解を出す。

exchange1(_,_,[ ],[ ]).
exchange1(A,B,[HC|C],[HD|D]):-      
	A == HC,
	HD = B,
	D = C.
exchange1(A,B,[HC|C],[HD|D]):-
        HD = HC,
        C \== [],
	exchange1(A,B,C,D).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                               実行結果                               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% | ?- exchange1(jaist,prolog,[i, love,jaist],X).
% 
% X = [i,love,prolog] ? ;
% 
% no
% | ?- exchange1(jave,lisp,[prolog,is,fun],X).
% 
% nos
% 
% | ?- exchange1(tigers,giants,[tigers,is,stronger,than,tigers],X).
% 
% X = [giants,is,stronger,than,tigers] ? ;
% 
% X = [tigers,is,stronger,than,giants] ? ;
% 
% no
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                             問題2の3                                %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% リストCの中にある、Aで指定した要素をBで指定した要素に全て書き換えた
% 結果がDである
% 先頭と一致したら先頭をAにする、しなければそのままの値を結果に入れる
% そして再起的に定義しリストが空になって解をだす
% 
exchange2(_,_,[ ],[ ]).
exchange2(A,B,[HC|C],[HD|D]):-
	HC == A,
        HD = B,
	exchange2(A,B,C,D).
exchange2(A,B,[HC|C],[HD|D]):-
	HC \==A,
	HD = HC,
	exchange2(A,B,C,D).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                               実行結果                               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 
% | ?- exchange2(thePeople,jaist,[the,government,of,thePeople,by,thePeople,
% for,thePeople],X).
% 
% X = [the,government,of,jaist,by,jaist,for,jaist] ? ;
% 
% no
% 
% | ?- exchange2(man,woman,[i,am,a,gay],X).
% 
% X = [i,am,a,gay] ? ;
% 
% no
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                             問題2の4                                %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% リストの要素に指定したXが含まれていたら削除する
% Xがリストの先頭ならば、削除する
% データを削除した結果のリストZLに先頭要素Yを追加し再起的に定義する
 
remove(X,[X | YL],YL).
remove(X,[Y | YL], [Y | ZL]) :-
 	remove(X,YL,ZL).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                               実行結果                               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 
% | ?- remove(x,[a,b,c,d],X).
% 
% no
% | ?- remove(c,[a,b,c,d],Z).
% 
% Z = [a,b,d] ? ;
% 
% no
% | ?- remove(c,[a,b,c,d,c],Z).
% 
% Z = [a,b,d,c] ? ;
% 
% Z = [a,b,c,d] ? ;
% 
% no
% | ?- remove(z,[a,b,c,d],Z).
% 
% no
% | ?- remove(X,[a,b,c,d,e],[a,b,d,e]).
% 
% X = c ? ;
% 
% no
% | ?- 
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                             問題2の5                                %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% 削除リストから指定したリストの全ての要素を削除する
% 削除するリストを分解し、はじめの先頭だけを削除する
% 次の残りの先頭を再起的に受け渡し削除していく。
%   

removelist([X|B],YL,ZL):-
    B=[ ],
    remove(X,YL,ZL).
removelist([X|B],YL,ZL):-
    remove(X,YL,R),
    removelist(B,R,ZL).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                               実行結果                               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% | ?- removelist([b,c],[a,b,c,d,e],Z).
% 
% Z = [a,d,e] ? ;
% 
% no
% | ?- removelist([a,z],[a,b,c,d,e],Z).
% 
% no
% | ?- removelist(X,[a,b,c,d,e],[a,c,e]).
% 
% X = [b,d] ? ;
% 
% X = [d,b] ? ;
% 
% no
% | ?- 
% 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                    プログラムの解説、感想                            %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 再帰的表現を用いたリスト処理をつかうことによってプログラムを簡単に
% 有用にプログラミングすることができることがわかった。
% またリストの構造を理解することができた。
% プログラムでの重要なところは再帰的に呼び出したときの終了条件にリストを
% 空にするという条件をつけてやること。これをつけないとプログラムがEXIT
% しないというエラーがでてしまう。またバックトラックを考えて分岐条件を
% 考えてやらないと、求める解が出てこない場合があった。分岐条件をつけないと
% 再起をやらなくていいがしてしまい解に意味のない解がでてしまったり、
% 再起しなくて解がでてこないということがよくあった。
% リストの分解し、結果が成り立つということを仮定してやると考えやすかった
% 

%------------------------------------------------------------------
% 人工知能特論 酒井 潤 
% [i215]prolog report1
%------------------------------------------------------------------

% Xは男性である
male(toshimasa).
male(keijirou).
male(toshihisa).
male(yasukatu).
male(toshiie).
male(yoshiyuki).
male(nagatane).
male(toshinaga).
male(toshitune).

% Xは女性である
female(tatu).
female(tune).
female(matu).
female(kou).
female(maa).

% XはYの親である
parent(toshimasa,toshihisa).
parent(toshimasa,yasukatu).
parent(toshimasa,toshiie).

parent(toshimasa,yoshiyuki).

parent(tatu,toshihisa).
parent(tatu,yasukatu).
parent(tatu,toshiie).

parent(tatu,yoshiyuki).

parent(tune,keijirou).
parent(toshihisa,keijirou).

parent(toshiie,kou).
parent(toshiie,toshinaga).
parent(toshiie,maa).
parent(toshiie,toshitune).

parent(matu,kou).
parent(matu,toshinaga).
parent(matu,maa).
parent(matu,toshitune).

% XはYの夫である
husband(toshimasa,tatu).
husband(toshihisa,tune).
husband(toshiie,matu).
husband(nagatane,kou).

% XはYの父である
father(X,Y) :- 
	male(X),
	parent(X,Y).

% XはYの母である
mother(X,Y) :- 
	female(X),
	parent(X,Y).

% XはYの息子である
son(X,Y) :- 
	male(X),
	parent(Y,X).

% XはYの娘である
daughter(X,Y) :- 
	female(X),
	parent(Y,X).

% XはYの妻である
wife(X,Y) :- 
	husband(Y,X).

% XはYの兄弟である
brother(X,Y) :- 
	male(X),
	father(Z,X),
	father(Z,Y),
	X\==Y.

% XはYの姉妹である
sister(X,Y) :- 
	female(X),
	father(Z,X),
	father(Z,Y),
	X\==Y.

% XがYの叔父(伯父)である
% 父の兄弟は叔父(伯父)である
uncle(X,Y) :- 
	parent(A,Y),
	brother(X,A).

% もう一つの条件として
% 母の姉妹の夫は叔父(叔父)である
uncle(X,Y) :- 
	parent(A,Y),
	sister(Z,A),
	husband(X,Z).



% XがYの叔母(伯母)である
% 母の姉妹は叔母(叔母)である
aunt(X,Y) :- 
	parent(A,Y),
	sister(X,A).

% もう一つの条件として
% 父の兄弟の妻は叔母(伯母)である
aunt(X,Y) :-
	parent(A,Y),
	brother(Z,A),
	wife(X,Z).

% XがYの祖父または祖母である
grandparent(X,Y) :- 
	parent(X,Z),
	parent(Z,Y).


% XがYの祖父である
grandfather(X,Y) :- 
	father(X,Z),
	parent(Z,Y).

	
% XがYの祖母である

grandmother(X,Y) :-
	mother(X,Z),
	parent(Z,Y).

% XがYの従兄弟である
cousin(X,Y) :- 
	parent(A,Y),
	father(Z,A),	
	father(Z,B),
	B\==A,
	parent(B,X).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                            実行結果                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% | ?- uncle(X,toshinaga). 
%
% X = toshihisa ? ;
%
% X = yasukatu ? ;
%
% X = yoshiyuki ? ;
%
% no
%
%
%
% | ?- brother(X,toshihisa).
%
% X = yasukatu ? ;
%
% X = toshiie ? ;
%
% X = yoshiyuki ? ;
%
%
%
% no
%
% | ?- grandfather(X,Y).
%
% X = toshimasa,
% Y = keijirou ? ;
%
% X = toshimasa,
% Y = kou ? ;
%
% X = toshimasa,
% Y = toshinaga ? ;
%
% X = toshimasa,
% Y = maa ? ;
%
% X = toshimasa,
% Y = toshitune ? ;
%
% no
%
%
% | ?- cousin(X,keijirou). 
%
% X = kou ? ;
%
% X = toshinaga ? ;
%
% X = maa ? ;
%
% X = toshitune ? ;
%
% no
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                   プログラム解説 感想                              %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 今回のレポートの問題の手順通りに進めていくうちにPrologは新しい
% ファクトや述語を加えていき拡張することができることがよくわかった
% プログラムのファクトと述語から導出していくことにより解を導くため
% 真であるとわかっていることはすべて書き下される。そのため今回の
% レポートでのbrother,sister,の道術やuncle,auntでの導出ではXとYは
% 異なるものであるということを追加しなければ自分自身も導出されて
% しまう。
%
% 一度述語定義したもの読み方を変えてはいけない。
% 例えば (parent(X,Y)はXはYの親である)などである。
% プログラムを書いている中でこのような述語定義を逆に読んでしまい、
% 導出がうまくできないことが多かった。またレポートでのファクトの
% 名前のローマ字を一字でも間違えてしまうと、導出がうまくいかない。
% そのためparentの導出はできる。しかしuncleでの導出でparent
% の解が一字違うため導出できないということになりそれに気づくのに
% 時間がかかってしまった。
% 難しかったのはuncle,auntの導出であるが家系のツリー構造を理解し
% プログラムの前で書かれている述語を3段論法などで、導出して
% やることにより求めることができた。また導出の理解も深まった。
%
% プログラムの結果の解が二つ出てきてしまうのを修正するところも苦労した。
% brother、sister、 uncle、 aunt、などparentを用いて導出していると
% parentは男と女の二つの意味があり、解も二つでてしまう。そのため、
% parentの代わりにfatherなどを用いることにより、一つの解を求めることできた。
%
% brother(X,Y) :- 
% 	male(X),
% 	father(Z,X),
% 	father(Z,Y),
% 	X\==Y.
% のところでもX\==Yの位置をfatherの前におくとbrother(X,Y).という質問で
% XとYが同じ解がでてきてしまう。これはXとYの判定をしたあとに同じ父
% がいるという条件でXやYに何もはいっていないためXとYが同じものを
% 指していることであると思われる。そのためXやYになにかが入っていれば
% いいがそうでないときにこのようなことがおこった。それは回避するために
% X\==Yを最後においたことによりそのようなことが起らなくなった。
%
% この家系図だけで、解が正しくするようにするのは簡単であるが
% 他の新しい家系ができてもいいようにプログラムをするところが難しかった
% このようにしてプログラムを作成することができた。