%----------------------------------------------------------------------------
% program NIM
% Martin Dvorak I5
% Vyhledavanim strategickych pozic ...
%----------------------------------------------------------------------------
% sude(+Cislo),liche(+Cislo)
sude(A):-V is (2*( A // 2)),A=V.
liche(A):-not(sude(A)).
%----------------------------------------------------------------------------
% min(+Cislo1,+Cislo2,-Minimum)
min(A,B,V):-A=<B,V is A.
min(A,B,V):-A>B,V is B.
%----------------------------------------------------------------------------
% strategy(+Stav,Pocet_k*(min+max)+min+s,+P,+R,-Je_vyhr)
strategy([],C,_,_,V):-((sude(C),V=1);
(liche(C),V=0)).
strategy([H|T],C2,P,R,V):-H<P,strategy(T,C2,P,R,V).
strategy([H|T],C2,P,R,V):-H>=P,
C is (H mod (P+R)),C =< (P-1),
strategy(T,C2,P,R,V).
strategy([H|T],C2,P,R,V):-H>=P,C is (H mod (P+R)),
C =< (P+P-1),C >= P,
C2O is C2+1,
strategy(T,C2O,P,R,V).
strategy([H|_],_,P,R,0):-H>=P,C is (H mod (P+R)),
C > (P+P-1).
%----------------------------------------------------------------------------
% uber(+Stav,+Kde,+Kolik,-Uspech,-Vysl,Pozice) , uspech 1 , neuspech 0
uber([H|T],C,P,1,[OH|T],InC):-InC = C,H >= P, % uspesne da 1
OH is H - P.
uber([H|_],C,P,0,_,InC ):-InC = C,H<P. % neuspesne da 0
uber([H|T],C,P,U,[H|OT],InC):-InC < C,MInC is InC+1, % posun na dalsi
uber(T,C,P,U,OT,MInC).
%----------------------------------------------------------------------------%
% udela seznam vsech moznych tahu
% moznosti(+Stav,+K,+P,+R,-Moznosti)
moznosti(Sez,K,SP,R,Vysl):-P is SP-1, % SP - pravne P
moznosti(Sez,1,K,P,SP,R,[],Vysl).
moznosti(_,MK,K,MR,_,R,V,V):-MR=R,MK=K.
moznosti(Sez,MK,K,MR,P,R,MV,V):-MR=R,MK<K,
NK is MK+1,NR is P, % dalsi hrom
uber(Sez,NK,NR,OK,OSez,1),
((OK=0,!,moznosti(Sez,NK,K,NR,P,R,MV,V));
(OK=1,!,
moznosti(Sez,NK,K,NR,P,R,[OSez|MV],V))).
moznosti(Sez,MK,K,MR,P,R,MV,V):-MR<R,MK=<K,
NR is MR+1, % dalsi sirka
uber(Sez,MK,NR,OK,OSez,1),
((OK=0,!,moznosti(Sez,MK,K,NR,P,R,MV,V));
(OK=1,!,
moznosti(Sez,MK,K,NR,P,R,[OSez|MV],V))).
%----------------------------------------------------------------------------%
% zkontroluje zda nektera z mych moznosti jak tahnout vede dle strategie
% na vyhru ve hre.
% check(+Moznosti,+P,+R,-Opt.Pos)
check([],_,_,[]).
check([H|T],P,R,V):-strategy(H,0,P,R,C),
((C=0,!,check(T,P,R,V));
(C=1,!,V=H)).
%----------------------------------------------------------------------------%
% vybere ze seznamu stav , z ktereho nejde hrat na vyhravajici pozici
% vyber(+Stavy,K,P,R,-Tah)
vyber([],_,_,_,[]).
vyber([H|T],K,P,R,V):-moznosti(H,K,P,R,Moz),
check(Moz,P,R,Out),
((Out=[],V=H); % z H nejde hrat na strategii
(Out\=[],vyber(T,K,P,R,V))).
%----------------------------------------------------------------------------%
% byla nalezena vyhr. pozice , vzda uzivatel ?
% vzdej(-OK)
vzdej(OK):-nl,write(' Nalezl jsem pozici vedouci na vitezstvi!'),
nl,write(' Chcete pokracovat ve hre (a/n) :'),read(Volba),
((Volba=a,OK=1);(Volba\=a,OK=0,write(' Vyhral jsem !'))).
%----------------------------------------------------------------------------
% nachazi optimalni tah ze stavu stav
% tah(+Stav,+K,+P,+R,-Opt,-Konec)
tah(Sez,K,P,R,OptTah,OK):-moznosti(Sez,K,P,R,Moz),
check(Moz,P,R,Opt), % muzu tahnout na o.p. ?
((Opt=[],OK1 is 1,vyber(Moz,K,P,R,V), % nemohu
((V=[],[A|_]=Moz,OptTah=A);
(V\=[],OptTah=V))
);
(Opt\=[],vzdej(OK1),OptTah=Opt)), % mohu
nl,write(' MUJ TAH: '),write(OptTah),
konec(OptTah,P,R,ja,OK2), % neni tah , vyhravam
min(OK1,OK2,OK). % priznak konce hry
%----------------------------------------------------------------------------%
% ohodnot(+Stav,+P,+R,-Vyhodnost) ,1/-1,0 znamena ze nejde ohodnotit.
ohodn([],_,_,0,Hodn):-Hodn is -1. % soucet 0 - prohravam
ohodn([],_,_,1,Hodn):-Hodn is 1. % soucet 1 - vyhravam
ohodn([],_,_,MH,Hodn):-MH\=0,MH\=1,Hodn is 0. % soucet vetsi - nelze
ohodn([H|_],_,R,_,Hodn):-H > R,Hodn is 0. % mimo obor - nelze
ohodn([H|T],P,R,MH,Hodn):-H < P,H < R, % nemohou brat => posun
ohodn(T,P,R,MH,Hodn).
ohodn([H|T],P,R,MH,Hodn):-H >= P,H =< R, % mohu dobrat hromadku
MOH is MH + 1, % pridam do souctu
ohodn(T,P,R,MOH,Hodn).
%----------------------------------------------------------------------------%
% test konce hry,chyby : konec(+Stav,+P,+R,+Odkud_volam,-Priznak)
konec(Tah,P,R,ja,0):-ohodn(Tah,P,R,0,Hodn),Hodn = -1,
nl,write(' Vyhral jsem ! '),!.
konec(Tah,P,R,on,0):-ohodn(Tah,P,R,0,Hodn),Hodn = -1,
nl,write(' Gratuluji , vyhral jste !'),!.
konec(Tah,P,R,test,0):-ohodn(Tah,P,R,0,Hodn),Hodn = -1,
nl,write(' Nesmyslne zadani !'),!.
konec(_,_,_,_,1).
%----------------------------------------------------------------------------%
% kdo vyhraje pri predem rozhodnute hre : kdo(+Stav,+P,C)
kdo([],_,C):-((liche(C),nl,write(' Vyhral by jste !'));
(sude(C),nl,write(' Prohral by jsem !'))).
kdo([H|T],P,C):-CO is (C+(H//P)),kdo(T,P,CO).
%----------------------------------------------------------------------------
% test zda je hra predem rozhodnuta: smysl(+Stav,+P,+R,-Priznak)
smysl(Sez,P,R,OK):-((P=R,nl,write(' Toto je predem rozhodnuta hra .'),
kdo(Sez,P,0),OK = 0);
(P\=R,OK = 1)).
%----------------------------------------------------------------------------
% testuje koreknost zadani : test_zac(+Stav,+P,+R)
test_zac(Sez,P,R):-((lst(Sez),length(Sez,K),K>0,P=<R,integer(P),integer(R));
(nl,write(' Nesmyslne zadani! Vlozte prosim nove.'),fail)).
%----------------------------------------------------------------------------
% vstup zadani : zacatek(-Stav,-K,-P,-R,-Priznak)
zacatek(Sez,K,P,R,OK):- repeat,
nl,write(' Vlozte pocatecni stav: '),read(Sez),
write(' Odebrat minimalne: '),read(P),
write(' Odebrat maximalne: '),read(R),
test_zac(Sez,P,R),length(Sez,K),
konec(Sez,P,R,test,OK),!.
%----------------------------------------------------------------------------%
% test korektnosti pri odebirani: test_vstup(+K,+P,+R,+Hrom,+Sir)
test_vstup(K,P,R,Hrom,Sir):-((integer(Hrom),integer(Sir),Hrom=<K,Sir>=P,
Sir=<R);
(nl,write(' Nesmyslne zadani! Vlozte prosim nove.'),
fail)).
%----------------------------------------------------------------------------
% tah soupere : vstup(+Stav,+K,+P,+R,-Jeho_tah,-Priznak)
vstup(Sez,K,P,R,OSez,OOK):- repeat,
nl,write(' Vlozte cislo hromadky :'),read(Hrom),
write(' Pocet odebiranych sirek :'),read(Sirky),
test_vstup(K,P,R,Hrom,Sirky),
uber(Sez,Hrom,Sirky,OK,OSez,1),nonvar(OK),OK=1,
!,
write(' VAS TAH: '),write(OSez),
konec(OSez,P,R,on,OOK).
%----------------------------------------------------------------------------%
% pokud neuspeje OK = 1 hra konci.
%----------------------------------------------------------------------------
% tah_hrace(+Stav,+K,+P,+R)
tah_hrace(Sez,K,P,R):-vstup(Sez,K,P,R,OSez,OK),nonvar(OK),OK = 1,
tah_programu(OSez,K,P,R).
%----------------------------------------------------------------------------%
% tah_programu(+Stav,+K,+P,+R)
tah_programu(Sez,K,P,R):-tah(Sez,K,P,R,OSez,OK),nonvar(OK),OK = 1,
tah_hrace(OSez,K,P,R).
%----------------------------------------------------------------------------%
% spusteni hry
nim:-nl,nl,nl,nl,nl,tab(32),write('NIM'),nl,
tab(19),write(' Prohrava hrac , ktery nema tah .'),nl,
zacatek(Sez,K,P,R,OK1),smysl(Sez,P,R,OK2), % kor. a smysl zadani
min(OK1,OK2,OK),nonvar(OK),OK=1,
tah_hrace(Sez,K,P,R).
%--------------------------- Konec programu ---------------------------------%