Игра «Домино»
Исходный код программы на Visual prolog:
DOMAINS
ilist=integer*
figure=figure(integer,ilist,integer) %tip dlya hraneniya kosti -Index,ee dve cifri i polozenie v stroke(esli ona uze tam)
figures=figure*
troika=integer* %poka kost eshe ne na stole, to ona ili v spiske kostei kompa, ili v spiske kostei igroka, ili v baze.
%Tam oni hranyatsya v vide troek [A,B,Index], gde A i B - cifri na kosti.
troiki=troika*
slist=string*
PREDICATES
nondeterm min(integer,integer,integer).
nondeterm max(integer,integer,integer).
nondeterm member(figure,figures).
nondeterm member_troika(troika,troiki).
nondeterm delete(troiki,troika,troiki).
nondeterm append(figures,figures,figures).
nondeterm append_troiki(troiki,troiki,troiki).
nondeterm length(troiki,integer).
nondeterm write_all(figures).
nondeterm write_index(figures,integer,integer).
nondeterm get_index(integer,troiki,troika).
nondeterm razdat(troiki,integer,troiki,integer,troiki).
nondeterm razdacha(troiki,troiki,troiki,troiki).
nondeterm bolshe(ilist,ilist).
nondeterm max_pair(troiki,integer).
nondeterm max_not_pair(troiki,ilist).
nondeterm first_step(troiki,troiki,troiki).
nondeterm check_four(integer,integer,integer,integer,string,string).
nondeterm rotate(integer,integer,string,integer,integer).
nondeterm step_comp(troiki,troiki,troiki,figures,integer,integer).
nondeterm step_comp1(troiki,troiki,troiki,figures,troika,integer,integer,string,string).
nondeterm check_step_gamer(troiki,figures,integer,integer).
nondeterm check_gamer(troiki,troiki,troiki,figures,integer,integer,integer).
nondeterm step_gamer(troiki,troiki,troiki,figures,integer,integer).
nondeterm step_gamer1(troiki,troiki,troiki,figures,troika,integer,integer,string,string).
nondeterm count_points(troiki,integer).
nondeterm write_kosti(troiki).
nondeterm game.
CLAUSES
%standartnii predicat, proveryayushii prinadlezit li element(pervii parametr) spisku(vtoroi parametr). Dlya kostei
member(X,[X|_]).
member(X,[_|Tail]):-member(X,Tail).
%to ze samoe, no dlya tipa troek [A,B,Index]
member_troika(X,[X|_]).
member_troika(X,[_|Tail]):-member_troika(X,Tail).
%standartnii predicat sliyaniya dvuh spiskov. Dlya kostei
append([],B,B).
append([H|Tail],B,[H|NewTail]):-append(Tail,B,NewTail).
%to ze sanoe, no dlya troek
append_troiki([],B,B).
append_troiki([H|Tail],B,[H|NewTail]):-append_troiki(Tail,B,NewTail).
%standartnii predicat vichisleniyu dlini spiska
length([],0).
length([_|Tail],Len):-length(Tail,L), Len=L+1.
%standartnii predicat udaleniya elementa(vtoroi parametr) iz spiska(pervii parametr)
delete([H|Tail],H,Tail).
delete([H|Tail],X,[H|NewTail]):-delete(Tail,X,NewTail).
%minimum dvuh elementov
min(A,B,A):-A<=B.
min(A,B,B):-A>B.
%maximum dvuh elementov
max(A,B,A):-A>=B.
max(A,B,B):-A
%prohod po kletkam i prosmotr est li tam kost. Esli est, to vivodit na ekran.
%Koordanata kost-eto koordanata ee centra, t.e koordanata sosednei kost budet otlichatsya na 3
write_index(_,Temp,Right):-Temp>Right,!,nl.%Esli tekushaya koordinata volshe pravogo ogranicheniya, to ostanavlivaemsya
write_index(Field,Temp,Right):-
member(figure(Index,[A,B],Temp),Field),!,%esli dannaya koordinata - centr kosti,
write("[ ",A," | i",Index,"| ",B,"] "),%to vivesti v takom vide
New = Temp+3,write_index(Field,New,Right).%pribavit k koordinate 3 i smotret dalshe
write_index(Field,Temp,Right):-New = Temp+1,write_index(Field,New,Right).%syuda popadaem tolko esli tekushaya koordinata
%ne yavlyaetsya centrom kosti, togda uvelichivaem ee na 1 i smotrim dalshe
%vivesti kosti, "lezashie na stole" na ekran
write_all(Field):-write_index(Field,-85,85).%poskolku u nas 28 kostei, koordinata pervoi kosti
%zadaetsya kak 0, to vse koordinati imeyut znacheniya v promezutke (-85,85)
%vidat element spiska (vtoroi parametr) s zadannim indeksom(pervii parametr)
get_index(0,[H|_],H).
get_index(I,[_|Tail],X):-I1 = I-1, get_index(I1,Tail,X).
%nachalnaya razdacha kostei. Tut ves ishodnii nabor delitsya na 7 kostei kompa, 7 kostei igroka i 14 kostei v baze
razdacha(Kosti,Gamer1,Gamer2,Baza):-
razdat(Kosti,7,Gamer1,27,TempKosti),%otdelit 7 kostei dlya Gamer1, vse ostavsheesya pomestit v TempKosti
razdat(TempKosti,7,Gamer2,20,Baza).%iz ostavshegosya otdelit 7 kostei dlya Gamer2, a ostatok eto baza
%predicat otdeleniya zadannogo kolichestva kostei
razdat(Kosti,0,[],_,Kosti):-!.%esli nado otdelit 0, to igroku nichigo, a vse v ostatok
razdat(Fishki,N,[H|Tail],Len,Ostatok):-%inache
random(Len,I),get_index(I,Fishki,H),%vibiraem sluchainoe chislo v promezutke ot 0 do dlinni spiska kostei
%i vibiraem kost, stoyashyuyu v spiske na etom meste
delete(Fishki,H,TempFishki),Len1 = Len-1,%udalyaem ee iz spiska, umenshaem ego dlinnu na 1
N1 = N-1,razdat(TempFishki,N1,Tail,Len1,Ostatok).%rekursivno vibiraem ostavshiesya N1 elementov
%poskolku pervii hod nachinaet tot, u kogo maksimalnii dubl(esli takoi est na rukah),
%to etot predicat sozdan dlya togo, chtobi ego nait
max_pair([],-1).%u pustogo spiska -1
max_pair([[A,A,_]|Tail],Max):-!,max_pair(Tail,TailMax),max(A,TailMax,Max).%esli na dannii moment mi rassmatrivaem dubl,
%to rekursivno naidem maksimalnii dubl v hvoste spiska i viberem maksimum iz nego i tekushego elementa
max_pair([_|Tail],Max):-max_pair(Tail,Max).%esli ze ne dubl,to ishem maksimum v hvoste
%mozet tak sluchitsya, chto na rukah ne budet ni odnogo dublya, togda ishem prosto maksimalnyuyu kost
%dlya etogo nuzna operaciya sravneniya
bolshe([A,_],[C,_]):-A>C.%esli pervii element bolshe, to i bsya kost bolshe
bolshe([A,B],[A,D]):-B>D.%esli pervii elementi ravni, a vtoroi bolshe, to i vsya kost bolshe
max_not_pair([[A,B,_]],[A,B]).%esli v spiske vsego 1 kost, to ona i est maksimalnaya
max_not_pair([[A,B,_]|Tail],[A,B]):-max_not_pair(Tail,[MaxA,MaxB]),bolshe([A,B],[MaxA,MaxB]),!.%esli ne odna, to rekursivno ishem maksimum v hvoste,
%i esli tekushaya kost bolshe etogo maksimuma, to berem ee
max_not_pair([_|Tail],Max):-max_not_pair(Tail,Max).%inache tekushii element tochno ne maksimalnii, poetomu ishem maksimum v hvoste
%predicat pervogo hoda, vibiraetsya kto budet hodit pervim
first_step(Comp,Gamer,Baza):-
max_pair(Comp,CompMax),%nahodim maksimalnii dubl i kompa
max_pair(Gamer,GamerMax),%nahodim maksimalnii dubl i igroka
max(CompMax,GamerMax,Max),%vibiraem iz nih maksimum
Max>=0,member_troika([Max,Max,I],Comp),!,%esli on bolshe 0(eto znachit, chto minimum odin dubl u igrokov imeetsya,
%to proveryaem u kompa li on
Field=[figure(I,[Max,Max],0)],%esli u kompa,to na pole pomeshaem pervuyu kost
delete(Comp,[Max,Max,I],NewComp),step_gamer(NewComp,Gamer,Baza,Field,I,I).%udalyaem ee iz spiska kostei kompa,
%i peredaem hod igroku
first_step(Comp,Gamer,Baza):-%tut vse to ze samoe, no esli maksimalnii dubl u igroka
max_pair(Comp,CompMax),
max_pair(Gamer,GamerMax),
max(CompMax,GamerMax,Max),
Max>=0,member_troika([Max,Max,I],Gamer),!,
Field=[figure(I,[Max,Max],0)],
delete(Gamer,[Max,Max,I],NewGamer),step_comp(Comp,NewGamer,Baza,Field,I,I).
first_step(Comp,Gamer,Baza):-%syuda popadaem tolko esli ni u kogo iz igrokov net dublya
max_not_pair(Comp,[CompMaxA,CompMaxB]),%togda ishem maksimalnii nedubl u kompa
max_not_pair(Gamer,[GamerMaxA,GamerMaxB]),%i u igroka
bolshe([CompMaxA,CompMaxB],[GamerMaxA,GamerMaxB]),!,%esli u kompa bolshe
member_troika([CompMaxA,CompMaxB,I],Comp),Field=[figure(I,[CompMaxA,CompMaxB],0)],%to dobavit na stol, udalit iz spiska kompa, peredat hod...
delete(Comp,[CompMaxA,CompMaxB,I],NewComp),step_gamer(NewComp,Gamer,Baza,Field,I,I).
first_step(Comp,Gamer,Baza):-%to ze samoe, tolko esli maksimalnii nedubl u igroka
max_not_pair(Comp,[CompMaxA,CompMaxB]),
max_not_pair(Gamer,[GamerMaxA,GamerMaxB]),
bolshe([GamerMaxA,GamerMaxB],[CompMaxA,CompMaxB]),
member_troika([GamerMaxA,GamerMaxB,I],Gamer),Field=[figure(I,[GamerMaxA,GamerMaxB],0)],
delete(Gamer,[GamerMaxA,GamerMaxB,I],NewGamer),step_comp(Comp,NewGamer,Baza,Field,I,I).
%predicat proveryaet mozno li postavit odny kost ryadom s drugoi,
%esli mozno to gde, i nado li ee povarachivat(otnositelno togo kak ona hranitsya v spiske)
check_four(A,_,A,_,left,yes).
check_four(A,_,_,A,right,no).
check_four(_,B,B,_,left,no).
check_four(_,B,_,B,right,yes).
%predikat povorachivaet kost, esli eto ukazano
rotate(A,B,yes,B,A).
rotate(A,B,no,A,B).
%nuzno dlya podscheta ochkov. Prosto summa vshek cifr na kostyah u igroka ili kompa
count_points([],0).
count_points([[A,B,_]|Tail],Ans):-count_points(Tail,C),Ans = C+A+B.
%vivod na ekran kostei igroka ili kompa
write_kosti([]):-nl.
write_kosti([[A,B,C]|Tail]):-write("("),write(A),write(",i"),write(C),write(","),write(B),write(") "),write_kosti(Tail).
%predicat, vipolnyayushii shag kompa. Parametri Left i Right - indeksi samoi levoi i samoi pravoi kostei na stole
step_comp(_,[],_,_,_,_):-!,write("You win!!!"),nl.%esli u igroka bolshe nichego net, to on viigral
step_comp(Comp,Gamer,Baza,Field,Left,Right):-
member(figure(Left,[AA,BB],_),Field),member_troika([A,B,I],Comp),
check_four(A,B,AA,BB,left,Rotate),%esli u kompa est takaya kost [A,B,I],chto ee mozno prisoedinit sleva k ryadu
step_comp1(Comp,Gamer,Baza,Field,[A,B,I],Left,Right,left,Rotate).%to vizivaem predicat dlya dalneishih deistvii
step_comp(Comp,Gamer,Baza,Field,Left,Right):-%to ze samoe, tolko esli mozno prisoedinit sprava
member(figure(Right,[AA,BB],_),Field),member_troika([A,B,I],Comp),
check_four(A,B,AA,BB,right,Rotate),
step_comp1(Comp,Gamer,Baza,Field,[A,B,I],Left,Right,right,Rotate).
step_comp(Comp,Gamer,Baza,Field,Left,Right):-%esli ne mozet naiti ne odnoi podhodyashei kosti, to nado brati iz bazi
length(Baza,Len),Len>0,write("Kompyuter ne mozet sdelat hod i bered kost iz bazi!"),nl,%proveryaet ne pusta li baza
random(Len,I),get_index(I,Baza,New),append_troiki(Comp,[New],NewComp),%vibiraet iz nee element,nahodyashiisya na sluchainom meste
delete(Baza,New,NewBaza),step_comp(NewComp,Gamer,NewBaza,Field,Left,Right).%udalyaet iz bazi i snova pitaetsya shodit
step_comp(Comp,Gamer,_,_,_,_):-count_points(Comp,C),count_points(Gamer,G),C
write("Kolichestvo ochkov u Vas - ",G," Kolichestvo ochkov u kompyutera - ",C),nl,
write("You lose!!!").%syda prishli tolko
%elsi komp hodit ne mozet,a baza pusta,
%togda schitaem ochki. Esli u kompa ih menshe, to igrok proigral
step_comp(Comp,Gamer,_,_,_,_):-count_points(Comp,C),count_points(Gamer,G),C>=G,
write("Kolichestvo ochkov u Vas - ",G," Kolichestvo ochkov u kompyutera - ",C),nl,
write("You win!!!"). %Esli bolshe, to viigral
%predicat dlya dalneishih deistvii, esli mi vse-taki mozem shodit
step_comp1(Comp,Gamer,Baza,Field,[A,B,I],Left,Right,left,Rotate):-%esli hotim dobavit sleva
member(figure(Left,_,X),Field),NewX=X-3,%nahodim koordinatu samoi levoi kosti, novuyu koordinatu umenshaem na 3
rotate(A,B,Rotate,NewA,NewB),%povorachivaem kak nado
append(Field,[figure(I,[NewA,NewB],NewX)],NewField),%dobavlyaem na stol
delete(Comp,[A,B,I],NewComp),%udalyaem u kompa
write("Hod kompyutera: "),nl,write_all(Field),nl,%pishem rezultat
step_gamer(NewComp,Gamer,Baza,NewField,I,Right).%i daem hod igroku
step_comp1(Comp,Gamer,Baza,Field,[A,B,I],Left,Right,right,Rotate):-%tut vse toze samoe, tolko esli klast s pravoi storoni
member(figure(Right,_,X),Field),NewX=X+3,
rotate(A,B,Rotate,NewA,NewB),
append(Field,[figure(I,[NewA,NewB],NewX)],NewField),
delete(Comp,[A,B,I],NewComp),
write("Hod kompyutera: "),nl,write_all(Field),nl,
step_gamer(NewComp,Gamer,Baza,NewField,Left,I).
%proverka parametrov, vvedennih polzovatelev. Tochnee indeksa kosti, kotoroi on hochet hodit
check_gamer(Comp,Gamer,Baza,Field,I,Left,Right):-
member_troika([A,B,I],Gamer),%nahodim ee
member(figure(Left,[AA,BB],_),Field),check_four(A,B,AA,BB,left,Rotate),%esli ee mozno pristavit sleva ot samoi levoi na stole
member(figure(Right,[AAA,BBB],_),Field),check_four(A,B,AAA,BBB,right,Rotate),!,%i sprave ot samoi pravoi
write("S kakoi storoni Vi hotite polozit kos? (left/right) "),%to sprahivaem kuda imenno nado
readln(Side),step_gamer1(Comp,Gamer,Baza,Field,[A,B,I],Left,Right,Side,Rotate).%i vizivaem predicat s uze zadasnnim mestom
check_gamer(Comp,Gamer,Baza,Field,I,Left,Right):-%esli nelzya s obeih storon
member_troika([A,B,I],Gamer),
member(figure(Left,[AA,BB],_),Field),check_four(A,B,AA,BB,left,Rotate),!,%no mozno sleva, to stavim tuda
step_gamer1(Comp,Gamer,Baza,Field,[A,B,I],Left,Right,left,Rotate).
check_gamer(Comp,Gamer,Baza,Field,I,Left,Right):-%tak ze, esli tolko sprave
member_troika([A,B,I],Gamer),member(figure(Right,[AA,BB],_),Field),
check_four(A,B,AA,BB,right,Rotate),!,
step_gamer1(Comp,Gamer,Baza,Field,[A,B,I],Left,Right,right,Rotate).
check_gamer(Comp,Gamer,Baza,Field,_,Left,Right):-%esli ze nikuda nelzya, to pishem ob oshibke
write("Takoi hod nevozmozno sdelat!"),nl,step_gamer(Comp,Gamer,Baza,Field,Left,Right).
%proverka mozet li igrok sdelat hod, chtobi uznat nado li vidavat zapros ili srazu brat kost iz bazi
check_step_gamer(Gamer,Field,Left,_):-%esli est kost i igroka, kotoruyu mozno pristorit sleva ot samoi levoi kosti na stole, to OK
member(figure(Left,[AA,BB],_),Field),member_troika([A,B,_],Gamer),check_four(A,B,AA,BB,left,_).
check_step_gamer(Gamer,Field,_,Right):- %ili ze sprava ot samoi pravoi
member(figure(Right,[AA,BB],_),Field),member_troika([A,B,_],Gamer),check_four(A,B,AA,BB,right,_).
step_gamer([],_,_,_,_,_):-!,write("You lose!!!"),nl.%esli u kompa bolshe nichego net, to igrok proigral
step_gamer(Comp,Gamer,Baza,Field,Left,Right):-
not(check_step_gamer(Gamer,Field,Left,Right)),%esli nelzya shodit
length(Baza,Len),Len>0,!,%i baza ne pusta
write("Vi ne mozete shodit, nado brat novyu kost iz bazi!"),nl,
%to kak i s kompom vibiraem iz baxi sluchainim obrazom i probuem shodit snova
random(Len,Index),get_index(Index,Baza,[A,B,I]),append_troiki(Gamer,[[A,B,I]],NewGamer),
write("Iz bazi vzyata kost (",A,",i",I,",",B,")"),nl,
delete(Baza,[A,B,I],NewBaza),step_gamer(Comp,NewGamer,NewBaza,Field,Left,Right).
step_gamer(Comp,Gamer,Baza,Field,Left,Right):-%esli ze mozem shodit
check_step_gamer(Gamer,Field,Left,Right),
write("Vash hod: "),nl,
write_all(Field),
write("Vashi kosti: "),write_kosti(Gamer),
write("Kosti kompyutera: "),write_kosti(Comp),
write("Vvedite indeks kosti, kotoroi zelaete sigrat: "),
readint(I),%to schitivaem chem igrok hochet poiti
check_gamer(Comp,Gamer,Baza,Field,I,Left,Right),!.%proveryaem mozet li on eto sdelat
%(esli mozet, to tam vizivaetsya predicat step_gamer1)
%esli ze baza pusta, to chitaem ochki, kak i u kompa
step_gamer(Comp,Gamer,_,_,_,_):-count_points(Comp,C),count_points(Gamer,G),C
write("Kolichestvo ochkov u Vas - ",G," Kolichestvo ochkov u kompyutera - ",C),nl,
write(Comp,"You lose!!!!!!!!!").
step_gamer(Comp,Gamer,_,_,_,_):-count_points(Comp,C),count_points(Gamer,G),C>=G,
write("Kolichestvo ochkov u Vas - ",G," Kolichestvo ochkov u kompyutera - ",C),nl,
write("You win!!!").
%tut toze vse kak u kompa
step_gamer1(Comp,Gamer,Baza,Field,[A,B,I],Left,Right,left,Rotate):-
member(figure(Left,_,X),Field),NewX=X-3,
rotate(A,B,Rotate,NewA,NewB),
append(Field,[figure(I,[NewA,NewB],NewX)],NewField),
delete(Gamer,[A,B,I],NewGamer),
step_comp(Comp,NewGamer,Baza,NewField,I,Right).
step_gamer1(Comp,Gamer,Baza,Field,[A,B,I],Left,Right,right,Rotate):-
member(figure(Right,_,X),Field),NewX=X+3,
rotate(A,B,Rotate,NewA,NewB),
append(Field,[figure(I,[NewA,NewB],NewX)],NewField),
delete(Gamer,[A,B,I],NewGamer),
step_comp(Comp,NewGamer,Baza,NewField,Left,I).
%glavnii predicat. Zadaet mnozestvo kostei, razdaet ih i peredaet pervii hod.
game:-
Kosti=[[6,6,1],[6,5,2],[6,4,3],[6,3,4],[6,2,5],[6,1,6],[6,0,7],
[5,5,8],[5,4,9],[5,3,10],[5,2,11],[5,1,12],[5,0,13],
[4,4,14],[4,3,15],[4,2,16],[4,1,17],[4,0,18],
[3,3,19],[3,2,20],[3,1,21],[3,0,22],
[2,2,23],[2,1,24],[2,0,25],
[1,1,26],[1,0,27],
[0,0,28]],
razdacha(Kosti,Comp,Gamer,Baza),
first_step(Comp,Gamer,Baza).
GOAL
game.
Анекдот:
Программист:
- Подскажите самые перспективные http://cicerone.com.ua. - Мне понравился результат обучения в школе Чичероне.
|