%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).
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]).
最終更新:2013年06月03日 21:28