「prolog勉強14日目 NimをPrologで書いてみた」の編集履歴(バックアップ)一覧に戻る

prolog勉強14日目 NimをPrologで書いてみた - (2013/06/03 (月) 21:28:04) のソース

%prolog勉強14日目 
% nimをプレイするCPUをPrologで自力で書いてみる。C++なら一瞬で書ける問題がprologで書くと何か凄く難しい。 
% 普通に書いてもよいのですが今回はレジスターマシン的な発想でかつ、 
% 整数論的にs(s(,,,s(0),,,))的に山に残ってる石の数を認識してコードを書いてみました 
% 本当は取らない山二つの数をxorしてその値が残りの山より小さいなら残りの山をその値まで取ればいいのですがまあ趣味的に書いてみました 
% 単なる勉強用なので入力チェックやエラー処理はあまりしてません 
% prologは難しいから普及してないんじゃなかろうか?後Prolog的思考パターンでプログラムを組むのも専門的な教育を受ける必要がある気がする。

 xor_hit(X,Y,Z):-Calc is X xor Y xor Z,Calc=:=0.
 
 
 dell(Yamas,No,Dell,Result,ReYama):-nth0(No,Yamas,Size),Size<1,!,fail.
 dell([X,Y,Z],No,Dell,Result,ReYama):-
 	(No=:=0 -> X1 is X-1,Y1 is Y,  Z1 is Z  ;true),
 	(No=:=1 -> X1 is X,  Y1 is Y-1,Z1 is Z  ;true),
 	(No=:=2 -> X1 is X,  Y1 is Y,  Z1 is Z-1;true),
 	Dell1 is Dell+1,
 	(xor_hit(X1,Y1,Z1) ->
 		Result is Dell1,ReYama=[X1,Y1,Z1];
 		dell([X1,Y1,Z1],No,Dell1,Result,ReYama)).
  
 
 
 dell_search([0,0,0],ReYama,No,-1,-1):-!,fail.
 dell_search([X,Y,Z],[X1,Y1,Z1],3,1,0):-Y=<X,Z=<X,X1 is X-1,Y1 is Y  ,Z1 is Z,  !.
 dell_search([X,Y,Z],[X1,Y1,Z1],3,1,1):-X=<Y,Z=<Y,X1 is X  ,Y1 is Y-1,Z1 is Z,  !.
 dell_search([X,Y,Z],[X1,Y1,Z1],3,1,2):-X=<Z,Y=<Z,X1 is X  ,Y1 is Y,  Z1 is Z-1,!.
 
 dell_search(Yamas,ReYama,No,Result,ReNo):-
 		(dell(Yamas,No,0,Result,ReYama)->ReNo is No;
 			No1 is No+1,dell_search(Yamas,ReYama,No1,Result,ReNo)).
 
 %プレーヤのターン
 
 user_input(Yamas,Te):-
 	repeat,
 	format('Input mountain No And number taken from a mountain.~n'),
 	read(Te),
 	length(Te,2),
 	[X,Y]=Te,
 	integer(X),
 	integer(Y),
 	0=<X,
 	X=<2,
 	nth0(X,Yamas,Size),
 	1=<Y,
  	Y=<Size,
 	!.
 	
 
 play([X,Y,Z],0):-X<1,Y<1,Z<1,!,format('your loss.~n').
 play([X,Y,Z],1):-X<1,Y<1,Z<1,!,format('your win.~n').
 play(Yamas,0):-
 	user_input(Yamas,Te),
 	[X,Y,Z]=Yamas,
 	[No,Size]=Te,
 	(No=:=0 -> X1 is X-Size,Y1 is Y,     Z1 is Z     ;true),
 	(No=:=1 -> X1 is X,     Y1 is Y-Size,Z1 is Z     ;true),
 	(No=:=2 -> X1 is X,     Y1 is Y,     Z1 is Z-Size;true),
 	play([X1,Y1,Z1],1).
 play(Yamas,1):-
  	dell_search(Yamas,ReYama,No,Result,ReNo),
 	[X,Y,Z]=ReYama,
 	format('CPU Get ~d ~d Yama(~d ~d ~d)',[ReNo,Result,X,Y,Z]),
 	play(ReYama,0).
 
 nim:-format('Nim Please input three numbers.~n'),
  	read(Yamas),
 	play(Yamas,0).





次は小町山を解くプログラム。
http://www.geocities.jp/m_hiroi/prolog/prolog14.html
こちらのサイトの問題1を解いた。
模範解答のコード行数の少なさと私の書いたコードのコード行数の多さからみて私がprolog的発想に向いてないことは明白かもしれない。


 main:-
 	search([1,2,3,4,5,6,7,8,9],0,0,[]).
 
 %ゴールに到達
 search([],Sum,0,Perm):-!,Sum=:=100,reverse(Perm,Ans),write(Ans),nl,fail,read(A).
 
 search([],Sum,N,Perm):-
 		Sum1 is Sum+N,
 		search([],Sum1,0,[N,'+'|Perm]).
 search([],Sum,N,Perm):-
 		Sum1 is Sum-N,
 		search([],Sum1,0,[N,'-'|Perm]).
 
 %この数字を検討する
 search([X|Rest],Sum,0,Perm):-
 	search(Rest,Sum,X,Perm).
 
 %区切らず数字を繋げる
 search([X|Rest],Sum,N,Perm):-
 	N>0,
 	N1 is N*10+X,search(Rest,Sum,N1,Perm).
 search([X|Rest],Sum,N,[]):-
 	!,
 	N>0,
 	search(Rest,N,X,[N]).
 
 %この時点で区切って足す
 search([X|Rest],Sum,N,Perm):-
	Sum1 is Sum+N,
	search(Rest,Sum1,X,[N,'+'|Perm]).
 %この時点で区切って引く
 search([X|Rest],Sum,N,Perm):-
 	Sum1 is Sum-N,
 	search(Rest,Sum1,X,[N,'-'|Perm]).