Nim

Selles vanas idamaade mängus võtavad mängijad vaheldumisi laule asetatud tikke. Korraga võib võtta ühe või kaks tikku (kuid midagi peab võtma); võidab see, kes võtab viimase tiku.

Seda mängu on lihtne õpetada ka Proloogile. Eesmärgiks on teha laud puhtaks, ja lubatud on võtta kas üks või kaks tikku:

võiduseis(0).
lubatud(1).
lubatud(2).
Laual olevate tikkude arv (Seis) muutub mängu ajal. Käigul olles püüab Prolog alati võtta niimitu tikku, et tagada endale võiduseis. Kui järgmise käiguga saab kogu laua tühjendada, on seis ilmselt võiduseis. Kui see pole võimalik, tuleb lauale jätta seis, mis ei ole võiduseis, s.t. ükskõik kuimitu tikku vastane ka ei võtaks, tekkiv seis pole võiduseis:
võidetav(Seis,Käik) :-
lubatud(Käik),
Seis1 is Seis - Käik,
võiduseis(Seis1),
!.
võidetav(Seis,Käik) :-
lubatud(Käik),
Seis1 is Seis - Käik,
pole_võidetav(Seis1).
pole_võidetav(Seis) :-
Seis > 2,
Seis1 is Seis - 1,
Seis2 is Seis - 2,
võidetav(Seis1,_),
võidetav(Seis2,_).
Käike kirjeldab kahekohaline predikaat käik; selle esimene argument ütleb, kelle käik (arvuti/inimene) see on. Kui arvuti käigul olles märkab, et laud on puhas, jääb tal üle vaid vastast õnnitleda; kui aga laual on veel tikke, kuid need on võimalik kõik ära võtta (1 või 2), teebki Prolog nii:
käik(arvuti,0) :-
nl,
write('Õnnitlen, võitsid!'),
nl.
käik(arvuti,Seis) :-
lubatud(Seis),!,
nl,
write('Võtan kõik ja olen võitnud!'),
nl.
Kui laual on rohkem kui kaks tikku, otsib Prolog leida sellist käikku, et selle järel seis oleks võidetav; kui sellist käiku pole, valib ta juhusliku arrvu tikke:
käik(arvuti,Seis) :-
lubatud(Käik),
võidetav(Seis,Käik),
!,
Seis1 is Seis - Käik,
write('Võtan '),
write(Käik),
write(', jääb '),
write(Seis1),
write(', sinu käik!'),
nl,
käik(inimene,Seis1).
käik(arvuti,Seis) :-
Käik is random(2)+1,
Seis1 is Seis - Käik,
write('Võtan '),
write(Käik),
write(', jääb '),
write(Seis1),
write(', sinu käik!'),
nl,
käik(inimene,Seis1).
Inimese käigul olles küsib arvuti inimeselt tema poolt võetavate tikkude arvu ja kontrollib, kas see on lubatud; kui on, on järgmisena tema käik, kuid kui pole, hoiatab inimest ja kordab küsimust:
käik(inimene,Seis) :-
write('Mitu võtad? '),
read(Käik),nl,
lubatud(Käik),
Seis1 is Seis - Käik,
käik(arvuti,Seis1).
käik(inimene,Seis) :-
write('See käik ei ole lubatud!'),
nl,
käik(inimene,Seis).
Algseisu ja alustaja valiku jätab arvuti viisakalt inimesele:
mäng :-
algseis(Seis),
alustaja(Alustaja),
käik(Alustaja,Seis).
alustaja(Alustaja) :-
write('Kumb algab (inimene/arvuti)? '),
read(Alustaja).
algseis(Seis) :-
write('Mitmega algame ? ,
read(Seis).
Mäng on huvitavam, kui mängija näeb ekraanil seisu, seega võiks inimese käigu esimese lause kirjeldada veidi põhjalikumalt:
käik(inimene,Seis) :-
write('Seis on: '),
joonista(Seis),nl,
write('Mitu võtad? '),
read(Käik),nl,
lubatud(Käik),
Seis1 is Seis - Käik,
käik(arvuti,Seis1).
Tikkude joonistamiseks kirjuta Prolog ekraanile tähti "I":
joonista(0):-
nl,!.
joonista(Seis):-
write('I '), Seis1 is Seis - 1,
joonista(Seis1).
Inimesed pole mängu ajal tavaliselt vait (kuigi peaks): kui neil õnnestub midagi, siis nad kiitlevad, vastasmängijat püütakse teda halvustades segadusse ajada jne. Ka Prologile võib õpetada sellise "inimlikku" mänguviisi, kus ta valib juhuslikult mingi hooplemise või märkuse (mõnikord on ka vait) :
käik(arvuti,Seis) :-
lubatud(Käik),
võidetav(Seis,Käik), %arvuti teab, et ta suudab võita!
!,
Seis1 is Seis - Käik,
write('Võtan '),
write(Käik),
write(', jääb '),
write(Seis1),
write(', sinu käik!'),
nl,
hooplemine,
nl,
käik(inimene,Seis1).
käik(arvuti,Seis) :-
Käik is random(2)+1,
Seis1 is Seis - Käik,
write('Võtan '),
write(Käik),
write(', jääb '),
write(Seis1),
write(', sinu käik!'),
nl,
märkus, %arvuti ei suuda võita, kuid tahaks siiski midagi ütelda
käik(inimene,Seis1).
hooplemine:-
N is random(4),
hooplemine(N,Tekst),
write(Tekst),
nl.
hooplemine(0, 'Selle mängu ma võidan kindlasti!').
hooplemine(1, 'Ma mängin paremini!').
hooplemine(2, 'Ära püüagi mind võita!').
hooplemine(3, '').
märkus:-
N is random(4),
märkus(N,Tekst),
write(Tekst),
nl.
märkus(0, 'Mängid üsna hästi!').
märkus(1, 'Täna mul ei vea!').
märkus(2, 'Sa võid isegi võita!').
märkus(3, '').

Ülesandeid:
1. Sellest mängust on olemas ka keerukamaid versioone:
- laual on mitte üks, vaid mitu rida tikke, võtma peab endiselt 1 või 2, kuid kahe tiku võtmisel mõlemad samast reast; võidab taas see, kes võtab kogu laualt viimase tiku;

mängu algul valitakse juhuslik arv N (N > 1) ja võtta võib kuni N tikku (s.t. ülalkirjeldatud versioonis N=2).

Täiusta programmi selliste versioonide mängimiseks!


Küsimused, probleemid: ©2004 Jaak Henno