Creeaza.com - informatii profesionale despre


Evidentiem nevoile sociale din educatie - Referate profesionale unice
Acasa » scoala » informatica » c
Sah in C/C++ :

Sah in C/C++ :


Liceul Teoretic "Lucian Blaga"

- Constanta -

Sah

- proiect atestat -



Capitolul I

Argument

Jocul de sah s-a nascut cel mai probabil in extremul Orient cu multe milenii in urma, intruchipand fidela replica a unui razboi intre doua armate. Fascinat inca de mic de legenda nobilului intelept care se spune ca a creat jocul de sah pentru a alunga plictiseala imparatului Indiei si care, pentru magistrala creatie nu a solicitat decat o rasplata umila, si anume: un bob de grau pentru primul patrat al tablei de sah, doua pentru al doilea si de cate doua ori mai multe pentru fiecare din cele saizeci si patru din campurile esicherului. Mult mai tarziu am realizat ca 18 446 774 073 709 551 615 boabe de grau reprezentau, probabil recolta mondiala pe cateva zeci sau sute de ani si ca aceasta era numai una din multele legende care invaluie in mister inceputurile sahului.

Am fost de mic familiarizat cu disputa sahista, frecventand cluburi si cercuri sahiste si acordand pana si in present o fractie considerabila de timp jocului. Sahul este un exercitiu al spiritului, presupune o lupta cu un adversar in conditiile unei dispute cat se poate de echitabile. Sahul pune la incercare inteligenta, perspicacitatea si prezenta de spirit. Jocul de sah reprezinta prin excelenta unul dintre domeniile a caror cunoastere totala pare imposibila. Numarul practic infinit de mutari si variante posibile poate sa starneasca un veritabil sentiment de curiozitate (celor care se aventureaza in acest imens labirint, aparent fara iesire). Caracterul atractiv, distractiv al jocului de sah ofera oricui posibilitatea de a-si pune in valoare si de a evidentia propriile capacitati, favorizand interactiunea tuturor factorilor psihici ce contribuie si influenteaza activitatea de cunoastere, dezvoltarea curiozitatii si dorintei de a dezlega tainele acestuia.

Necesitatea realizarii unui program pe calculator pentru a inlocui clasica tabla de sah este una normala, asadar si urmareste alinierea gandirii sahiste la exigentele calculului artificial generat de un algoritm. Computerul creaza conditiile si mecanismul jocului de sah, asumandu-si importantul rol de mediator si arbitru in cadrul disputei dintre doi adversari umani.

Capitolul II

Introducere in C/C++

In anul 1970, doi programatori, Brian Kerninghan si Dennis Ritchie, au creat limbajul C. Principalul scop pentru care a fost realizat acest limbaj este rescrierea sistemului de operare UNIX, pentru a-l face portabil pe toate platformele existente. Marele avantaj al limbajului C este acela de a fi extrem de flexibil si de a permite atat programarea la nivel inalt cat si la nivel scazut. C-ul este un limbaj procedural, asadar un program scris in C incepe de obicei cu definirea structurilor de date, apoi definirea functiilor pentru lucrul cu aceste structuri.

Cresterea complexitatii programelor a dus la necesitatea elaborarii unor alte tipuri de limbaje. Astfel, destinate inteligentei artificiale, au aparut limbajele care au la baza notiunea de 'cadru' si cele care pleaca de la ideea de 'actor'. Primele implementeaza operatii asupra unor modele de entitati; celelalte presupun faptul ca obiectele nu sunt simple elemente pasive asupra carora se fac anumite prelucrari, ci, dimpotriva, ca menirea acestor obiecte consta in a realiza prelucrarile asupra lor insile.

De aici a pornit ideea de a grupa structurile de date cu operatiile care prelucreaza respectivele date. Astfel s-a nascut notiunea de obiect sau clasa. Proiectarea de programe utilizand clase se numeste programare orientata pe obiecte (OOP).

Primele limbaje orientate pe obiecte au fost SIMULA (1965) si SIMULA-2 (1967). In anii '70 a aparut si celebrul limbaj SMALLTALK. Cel mai mare dezavantaj al lor a fost faptul ca au aparut ca limbaje de sine statatoare, avand o raspandire relativ redusa. Din acest motiv, putin programatori erau dispusi in acea vreme sa renunte la limbajele consacrate doar pentru a lucra obiectual.

In anul 1980, Bjarne Stroustrup a conceput limbajul 'C with Classes'. Acest limbaj a dus la imbunatatirea C-ului prin adaugarea unor noi facilitati, printre care si lucrul cu clase. In vara 1983, C-with-classes a patruns si in lumea academica si a institutiilor de cercetare. Astfel, acest limbaj a putut sa evolueze datorita experientei acumulate de catre utilizatorii sai. Denumirea finala a acestui limbaj a fost C++.

Succesul extraordinar pe care il are limbajul C++ a fost asigurat de faptul ca a extins cel mai popular limbaj al momentului, C. Programele scrise in C functioneaza si in C++, si ele pot fi transformate in C++ cu eforturi minime.

II.1 Instructiuni conditionale

II.1.1 Conditii

In limbajul C++ intalnim doua instructiuni conditionale (if si switch), precum si o varianta "imediata" a instructiunii if. Le vom descrie pe rand insistand asupra modalitatii de folosire si a greselilor frecvent intalnite. Insa, inainte de aceasta vom detalia notiunea de "conditie" in acceptiunea limbajului C++ si vom prezenta operatorii logici acceptati.

In limbajul C++ nu exista un tip logic de sine statator cum exista in Pascal tipul boolean. Pentru un plus de flexibilitate si o mai mare putere de exprimare s-a convenit ca orice tip de variabila/expresie ce

poate fi evaluata la un tip diferit de tipul "void" sa poata fi considerata o expresie logica. Conventia este ca orice expresie/variabila/constanta care este evaluata la o valoare nenula (diferita de 0) sa fie considerata ca avand valoarea de adevar "adevarat" si orice expresie /variabila /constanta care este nula sa fie considerate ca avand valoare de adevar "fals". Pentru a clarifica acest concept vom prezenta cateva exemple de conditii. La inceput vom declara cateva variabile:

int x = 3;

char ch = 'A';

char chn = 0x0;

float r = 0.0;

unsigned long ul = 0;

Acum sa vedem cateva expresii logice formate cu variabilele de mai sus si valoarea lor de adevar:

x - este o expresie care fiind diferita de 0 (3 != 0), se va evalua la adevarat

chn - este o expresie care fiind 0 (caracterul avand codul ASCII 0) este

considerata falsa

x + ul - este o expresie a carei valoare este 3 + 0 = 3, adica adevarata

ch * 0 - este o expresie a carei valoare este 0 ('A' are codul ASCII 65, iar 65 * 0= 0), deci falsa

x / ch - este o expresie a carei valoare este 0 (3 / 65 in numere intregi are valoarea 0), deci falsa

sqrt(x) - este o expresie a carei valoare este nenula, radical din 3 este aprox. 1.732

De obicei nu vom testa pur si simplu o variabila, sau o expresie simpla, ci vom folosi operatori pentru a defini o conditie. Deoarece in acceptiunea C++ nu exista un tip logic ci orice expresie poate fi o conditie, se pot folosi absolut toti operatorii in cadrul expresiei (aritmetici, relationali, logici, pe biti, de egalitate, etc). Operatorii logici (a nu se confunda cu operatorii aritmetici, relationali, de egalitate sau pe biti care pot fi folositi in expresiile care se evalueaza pentru conditie) suportati de C++ sunt:

&& -"si" logic. Returneaza adevarat daca ambele expresii se evalueaza la valori nenule, altfel returneaza fals. Daca prima expresie este evaluata la 0 (fals), a doua expresie nu se mai evalueaza. Acest lucru poate cauza erori de programare greu de detectat in cazul in care cea de a doua expresie contine un apel de functie. Apelul va avea loc numai daca prima conditie se evalueaza la adevarat (valoare nenula).

Atentie: un singur simbol & inseamna si pe biti si este diferit de &&.

|| -"sau" logic. Returneaza adevarat daca cel putin una din expresii se evalueaza la o valoare nenula. In cazul in care prima expresie este adevarata, cea de a doua nu se mai evalueaza. Remarca este absolut similara cu cea de la si logic.

Atentie: un singur simbol | insemna SAU pe biti si este diferit de ||.

! -negatie logica; Returneaza adevarat daca expresia este nula, fals in caz contrar. (!E) este echivalent cu (E == 0).

Alti operatori mult folositi in conditii sunt operatorii de egalitatate:

== -egal. Returneaza adevarat (valoare nenula) daca cele doua expresii sunt egale, fals (0) daca cele doua expresii sunt diferite. Din punct de vedere logic (E1 == E2) este echivalent cu (!(E1 - E2))

!= -diferit. Semnificatia este opusa operatorului ==. In consecinta, din punct de vedere logic (E1!= E2) si (E1 - E2) sunt echivalente.

Ultimii operatori amintiti sunt cei relationali:

< -mai mic. Returneaza adevarat daca valoarea expresiei din stanga este mai mica decat a celei din dreapta. Normal ca ambele expresii trebuie sa fie de tip scalar/numeric (integer/real/caracter/etc) pentru ca sa se poate face comparatia.

<= -mai mic sau egal. Returneaza adevarat daca valoarea expresiei din stanga este mai mica sau egala cu cea din dreapta.

> -mai mare. Returneaza adevarat daca valoarea expresiei din stanga este mai mare ca si cea din dreapta.

>= -mai mare sau egal. Returneaza adevarat daca valoarea expresiei din stanga este mai mare sau egala cu cea din dreapta.

Acum, dupa ce am prezentat cele mai importante lucruri despre ceea ce inseamna o conditie si care sunt operatorii care pot fi folositi in definirea conditiilor, vom trece in revista instructiunile conditionale.

II.1.2 - if

Sintaxa instructiunii este:

if ( <conditie> ) <instructiune1>;

Sau in varianta cu executie alternativa (executie pentru cazul in care conditia este falsa)

if ( <conditie> ) <instructiune1>;

else <instructiune2>;

In ambele cazuri prin instructiune se intelege fie o instructiune simpla, fie una compusa (grup de instructiuni incadrat de ). Conditia poate sa contina dupa cum am mentionat mai sus orice expresie. Este bine insa sa nu se exagereze la folosirea expresiilor complexe deoarece aceasta afecteaza claritatea codului.

Un exemplu in care se poate vedea aceasta este urmatorul:

int x = 3;

int y = 4;

if(x = y)

else

printf("Conditie falsa");

In mod oarecum surprinzator pentru un neinitiat in C++ bucata de program la executie va tipari "Conditie adevarata". Aceasta deoarece conditia este x = y, adica o atribuire si nu o comparatie (comparatia ar fi fost x == y), iar atribuirea primeste ca valoare, valoarea atribuita (4 in cazul nostru).

Recomandam o folosire mai putin tipica C++, dar mult mai usor de inteles:

int x = 3;

int y = 4;

x = y;

if(x != 0) //mai normal pentru C++ ar fi fost sintaxa echivalenta if(x)

Mai facem doua remarci pentru instructiunea if. Este obligatoriu simbolul de terminare instructiune ";" inainte de else. In cazul in care avem mai multe instructiuni if/else imbricate se recomanda folosirea parantezelor acoladice pentru a ne asigura ca ramura de else se va interpreta pentru ramura de if la care ne asteptam. De exemplu:

if(conditie_a)

else

II.1.3 - operatorul conditional (if imediat) "? :"

In multe cazuri avem de atribuit o anumita valoare unei variabile in functie de o anumita conditie. Sa presupunem urmatorul scenariu. Daca "conditia_a" este adevarata atunci vrem sa atribuim variabilei x valoarea 1, daca nu valoarea 3. Evident acest lucru se poate scrie folosind instructiunea if:

if(conditia_a)

x = 1;

else

x = 3;

O alta posibilitate mult mai compacta si mai usor de scris este folosind operatorul if imediat:

x = (conditia_a) ? 1 : 3;

II.1.4 - switch

Formatul instructiunii este:

switch ( <variabila> )

Este o instructiune folosita cand se doreste ca in functie de valoarea unei anumite expresii (<variabila>) numerice sa se execute un grup de instructiuni. De obicei se foloseste in cazul in care avem mai mult de trei variante (pentru 2 variante este mai comoda varianta cu if). Ca si interpretare in cazul in care break este prezent pe toate ramurile de case, este echivalenta cu:

if(<variabila> == <constanta1>) <instructiune1>;

else if(<variabila> == <constanta2>) <instructiune2>;

else <instructiune_def>;

In cazul in care break nu este prezent pe una din ramuri se va executa in continuare instructiunea de pe ramura urmatoare. O greseala comuna este uitarea instructiunii break in totalitate, in acest caz se vor executa toate instructiunile situate mai jos de ramura de case pe care este selectata executia.

ex.

unsigned int uTest = 3; //evident in acest caz se va intra doar pe ramura pentru //valoarea 3,

//daca aceasta exista, altfel pe ramura default daca exista

unsigned uVal = 0;

switch(uTest)

Daca nu ar fi existat instructiunile break s-ar fi executat uVal = 78 si apoi uVal = 0, deoarece neexistand instructiunea break de iesire din switch executia se continua liniar ignorand selectiile din case. Desi aceasta pare un deficit, in fond este un avantaj, permitand un cod mai compact in cazul in care

conditiile din case sunt cumulative (adica pentru prima ramura se executa si codul de pe cea de a doua ramura, etc.).

II.2 Instructiuni de ciclare

In C++ instructiunile care pot fi folosite pentru a cicla (executa un grup de mai multe

instructiuni -numit si bucla de ciclare- in mod repetat) sunt:

- for

- while

- do while

Toate aceste instructiuni folosesc conditii pentru a iesi din bucla de ciclare. Reamintim ca in C o conditie este formata din orice expresie, nu exista un tip specific 'logic' pentru conditii ca si in alte limbaje de programare. Expresia care formeaza conditia este analizata si daca este diferita de zero se considera valoare 'adevarat', iar daca este egala cu zero se considera 'fals'.

Vom analiza pe rand instructiunile de ciclare si vom specifica pentru fiecare cateva modalitati tipice de folosire. Inainte insa vom reaminti cateva notiuni despre sirurile de caractere, deoarece o utilizare tipica a tuturor instructiunilor de ciclare este parcurgerea sirurilor de caractere si executarea unor anumite operatiuni pe acestea. Cele mai multe din exemple vor lucra cu siruri de caractere sau de intregi. Sirurile de caractere in C/C++ sunt stocate ca si secvente de caractere in memorie terminate prin caracterul 0. Nu este stocata lungimea in mod explicit. De exemplu cuvantul "ABC" este stocat in memorie ca un sir de caractere 'A' 'B' 'C' 0x0. Numeric in memorie se vor gasi codurile ASCII: 65 66 67 0, sau in hexazecimal 0x41 0x42 0x43 0x0. Sirurile sunt referite in general de pointeri la caracter. Deoarece in C++ un nume de matrice/vector este un pointer constant la sirul -primul element din sir de fapt, dar acesta este urmat in memorie de restul elementelor din sir- de caractere/elemente din matrice/vector, acesta se poate folosi pentru a cicla peste vectorul respectiv. De exemplu urmatorul cod declara o variabila de tip sir de caractere, apoi copiaza in sirul respectiv un alt sir, iar in final tipareste sirul..

unsigned char strBuffer[256];

strcpy(strBuffer, "Un alt sir");

printf(strBuffer);

II.2.1 - for

Sintaxa instructiunii este prezentata mai jos.

for ( [<instructiuni_initializare>] ; [<conditie_ciclare>] ; [<instructiuni_incrementare>] )

<instructiune_bucla>;

Este probabil cea mai folosita instructiune de ciclare, prin ea se pot emula toate celelalte instructiuni.

In pozitia "instructiuni_initializare" se pot include mai multe instructiuni separate prin virgula ",". Acestea pot fi declaratii de variabile, initializari, etc. Se vor executa la inceputul buclei, inainte de orice instructiune din bucla. In cadrul "instructiuni_incrementare" se respecta aceleasi reguli, doar ca aceste instructiuni se vor executa la fiecare ciclare. In mod normal aici se vor afla instructiuni care modifica contoarele folosite in ciclu si in baza carora se va testa iesirea din bucla. Testul se va face in "conditie_ciclare". Conditia se testeaza pentru fiecare executie a buclei, inclusiv prima executie. sa vedem de exemplu cum putem parcurge un sir de caractere, modificand caracterele la majuscule (in engleza UpCase):

unsigned char strSir[256];

sscanf("Introduceti un sir de caractere (cuvant/propozitie): %s", strSir); //citim

for(int iIndex = 0; (strSir[iIndex]) && (iIndex < 256); iIndex++)

strSir[iIndex] = UpCase(strSir[iIndex]);

printf("nSirul convertit la majuscule: %sn", strSir);

Ne vom concentra asupra instructiunii for. La initializare pornim un contor care va creste de la 0 pana la valoarea pe care se afla pozitia ultima in sir (caracterul 0). Variabila declarata in cadrul instructiunilor de initializare este local buclei for si nu poate fi folosita in afara ei. In conditie testam doua lucruri: caracterul din sir de pe pozitia indicata de "iIndex" sa fie diferit de 0 si sa nu depasim dimensiunea sirului. De obicei al doilea test nu se mai face, in cazul in care sirul este folosit corect, nu se va ajunge niciodata sa se depaseasca dimensiunea maxima. Daca in schimb se incerca a se copia in spatiul destinat unui sir un sir care este mai mare decat spatiul respectiv se poate ajunge in situatia in care nu mai exista caracterul 0 de terminare si atunci se va depasi zona de date alocata sirului, algoritmul mergand in continuare pana intalneste primul 0 in memoria de dupa sir (aceasta generand un "memory overwrite" si o comportare aleatoare a programului).

Sa vedem de exemplu un mic program care determina lungimea unui sir de caractere (echivalent cu strlen):

#include <stdio.h>

void main(void)

Ca si in cazul instructiunii switch este posibil sa folosim break pentru a intrerupe in mod fortat bucla. O alta instructiune de control al executiei in cadrul buclei este continue care trece controlul la inceputul buclei. De exemplu daca vrem sa parcurgem un sir de 20 de elemente si in loc de fiecare element sa setam inversul acestuia (1/x, evident doar daca acesta este nenul).

float array[20];

void main ()

II.2.2 - while

Sintaxa instructiunii este urmatoarea:

while ( <conditie> ) <instructiune>;

Este folosita pentru ciclurile in care conditia nu depinde de un contor. De exemplu unul din cazurile cele mai folosite sunt la citirea dintr-un fisier. Exemplul de mai jos prezinta un ciclu in care se citesc dintr-un fisier (c:test.txt) blocuri de 1MB si se afiseaza de fiecare data nr. de bytes (octeti) cititi (cu unele modificari s-ar putea folosi ca si un program de cautare in fisiere a unui text, sau de copiere).

const int BufferSize = 1024L * 1024L;

int *Buffer = (int *)malloc(BufferSize); //1Mb = 1024 * 1024 bytes

int fin = open("c:test.txt", O_RDONLY | O_BINARY);

int iBytesRead;

while((fin != -1) && (!eof(fin)))

close(fin);

Se remarca folosirea unor altor instructiuni de lucrul cu fisiere fata de articolul trecut. In mod normal acestea sunt preferate -mai noi si mai eficiente-, desi in cele mai multe cazuri pentru convenienta data de fprintf si fscanf se folosesc instructiunile mai vechi fopen, fclose.

Echivalentul in Pascal al instructiunii este "while do". Mentionam aceasta pentru a se evita confuzia dintre while si do while -ambele instructiuni C++. Prima testeaza conditia la inceput de bucla, a doua executa bucla si abia apoi testeaza conditia (la sfarsit de bucla). In cazul while se poate intampla ca sa nu se execute bucla nici macar o data daca la evaluarea conditiei de ciclare aceasta este mereu falsa. Ca si in cazul instructiunii for se pot folosi break si continue pentru a intrerupe executia sau a relua executia de la inceputul buclei (cu reevaluarea conditiei).

II.2.3 - do while

In cazurile in care este necesara cel putin o parcurgere a buclei inainte de testare se foloseste instrucsiunea dowhile. Sintaxa ei este redata mai jos:

do <instructiune> while ( <conditie> );

Echivalentul ei in Pascal este repeat until. Ca si la while se folosesc instructiunile break si continue pentru a controla executia in interiorul buclei. Diferenta vine din faptul ca se executa in mod sigur cel putin o data bucla, pe cand la while bucla poate sa nu se execute deloc daca se evalueaza la fals conditta in momentul atingerii instructiunii while. Mai jos dam un exemplu de program care foloseste bucla do while pentru a testa introducerea unei parole:

#include <stdio.h>

#include <string.h>

int main ()

while (strcmp(pass, control));

return 0;

In cazul in care parola se va potrivi cu cea stocata in variabila checkword, functia strcmp (compara doua stringuri) va intoarce 0 si conditia de iesire din bucla se va evalua la fals, parasindu-se bucla.

In cazul instructiunii do while la intanirea instructiunii continue nu se testeaza conditia (normal daca ne gandim ca executia se reia de la inceputul buclei si conditia se testeaza la sfarsitul buclei).

Capitolul III

Regulamentul jocului de sah

Jocul de sah este o disputa intre doi adversari pe o tabla de joc cu 64 de campuri ( 8 x 8 ) si 32 de piese (16 albe si 16 negre). Jucatorii muta alternative cate o piesa. Fiecare jucator dispune de un rege, o regina, doua turnuri, doi nebuni, doi cai si opt nebuni, pozitia initiala fiind cea din diagrama:

Liniile esicherului se numeroteaza cu cifre de la 1 la 8 iar coloanele de la a la h, ca in diagrama.

Regele muta un camp in orice directie, regina efectueaza mutari oricat de lungi pe linia, coloana sau una din diagonalele pe care se gaseste; turnurile muta numai pe aceeasi linie sau coloana, nebunii pe diagonala; caii efectueaza o mutare conjugata an forma de "L". Piesele nu pot sari peste alte piese in miscarea lor )afara de cai, care nu au nici o restrictie in acest sens) si cand intampina o piesa adversa o captureaza, eliminand+o de pe tabla. Mutarea pionului se realizeaza astfel: din pizitia initiala maxim doua campuri pe verticala, apoi numai cate unul singur. Pionul captureaza numai pe diagonala, mai exact poate captura o piesa adversa care se gaseste pe unul din campurile din fata sa , pe diagonala si la distanta de un singur camp. Spre deosebire de fuguri, pionul nu poate muta niciodata inapoi. Cand un pion ajunge pe ultima linie (a 8-a pentru alb si prima pentru negru ) se transforma intr-o figura, la alegere. Un pion deplasat cu doua campuri din pozitia initiala poate fi capturat de un pion advers situat in stanga sau in dreapta pozitiei sale finale prin pozitionarea acestuia din urma pe campul "sarit" de pion in miscarea sa initiala; procedura se numeste luarea "en passant" si poate fi efectuata numai la mutarea imediat urmatoare celei a pionului de capturat.

Regale aflat in pozitia initiala poate efectua o mutare speciala numita rocada, impreuna cu unul din turnurile sale.conditiile care trebuie indeplinite pentru ca aceasta mutare sa poata fi efectuata sunt urmatoarele: regale sa nu fie atacat nici in pozitia initiala si nici in pozitia finala, campul dintre acestea (unde va ajunge turnul ) de asemenea sa nu fie atacat de o piesa adversa, atat regale cat si turnul sa nu fi efectuat pana in momentuls respectiv nici o mutare si sa nu existe nici o piesa intre rege si turn.

Regele se va plasa la doua campuri distanta de pozitia sa initiala, pe orizontala, iar turnul din de pe flancul respective va ocupa campul dintre rege si pozitia sa initiala.

Scopul jocului este matul.

Cand regale uneia din parti este atacat de o piesa adversa se considera pozitie de sah. Jucatorul cu piesele respective are obligatia de a "apara" sahul fie mutand regale, fie capturand piesa atacatoare, fie interpunand o piesa intre rege si aceasta (aceasta din urma posibilitate nu este valabila in cazul in care regale este atacat de un cal, evident).

Este mat atunci cand regale uneia din parti este in sah si nu exista nici o mutare valida care sa apere regele.

Partida este declarata remiza cand cei doi regi raman singuri pe tabla sau cand se ajunge la o pozitie de pat. Este pat cand jucatorul care trebuie sa mute nu are nici o mutare legala disponibila, nefiindu-i atacat regele.

Capitolul IV

Incapsularea - Clasa "piese"

Incapsularea este un mecanism care leaga impreuna cod si date si le pastreaza pe ambele in siguranta fata de intervantiile din afara si fata de eventualele utilizari eronate. Mai mult incapsularea este cea care permite crearea obiectelor. Spus simplu, un obiect este o unitate logica ce incapsuleaza atat date cat si cod care sa manevreze aceste date. Intr-un obiect o parte din cod si/sau date pot fi particulare acelui obiect si inaccesibile pentru orice funcsie din afara sa. In acest fel, un obiect dispune de un nivel semnificativ de protectie care impiedica modificarea accidentala sau utilizarea incorecta a partilor proprii obiectului de catre sectiuni ale programului care nu au legatura.

In cele din urma un obiect este in fapt o variabila de un tip definit de utilizator, adica definirea unui obiect creaza un nou tip de date.

In proiectul meu am definit clasa "piese" si am creat o matrice care sa retina toate cele 32 de piese de pe tabla de sah, pentru a putea fi manipulate mai usor prin ciclarea unei variabile si nu prin apelare separata a fiecarui obiect in parte.

Iata declararea clasei "piese" :

class piese

~piese() ;

void muta(register int i,register int j);

int da_l() ;

int da_c() ;

char da_p() ;

int da_cul() ;

int da_mutare()

void transformare();

int en() ;

void pune_en()

void schimba(int a,int b,int &c1,int &d) ;

friend void afiseaza_piesa(register int i,register int j,int culoare,register char piesa);

};

Caracteristicile fiecarei piese sunt : culoarea, forma, denumirea specifica, pozitionarea pe tabla, maniera de deplasare, pozitia initiala, numarul de mutari effectuate cu piesa respectiva si chiar oportunitatea de a captura pionul prin luarea "en passant".

IV.1 Membrii privati ai clasei "piese"

Culoarea fiecarei piese este retinuta de o variabila de tip intreg. Culoarea alba este asociata lui 15 iar cea neagra lui 0 (conform modului graphic din DOS). Valoarea initializata la inceput nu se modifica in timpul rularii programului.

Denumirea specifica a fiecarei piese este acceptata de o variabila tip character care retine prima litera din denumirea uzuala a piesei ( "r" "d" "t" "n" "c" si "p" ). La o captura, se va inlocui acest character cu "a".

Pozitia de pe tabla este retinuta de doua variabile intregi associate pozitiei pe orizontala si pe verticala a piesei. Se utilizeaza valorile de la 1 la 8, intrucat esicherul are 8 randuri si 8 coloane. La o captura, piesa eliminata va primi aici niste valori aleatorii extreme de mari.

Forma si maniera de deplasare specifica fiecarei piese este reglementata, insa de functii globale si depend de variabila character corespunzatoare denumirii piesei. Am optat pentru definirea unor funtii globale pentru desenarea pieselor pe tabla pentru a pastra cat mai compact codul clasei, considerand asadar dimensiunile mai mari ale acestor functii grafice. De asemenea consider ca maiera de deplasare este mai mult legata de aplicarea regulilor jocului, decat de obiectul in sine, ea fiind elaborata intr-o maniera relationala cu celelalte piese de pe tabla.

Asadar clasa "piese" creaza obiecte generale care pot fi utilizate si la alte jocuri, ca de exemplu "Dame" sau chiar "Go".

In plus mai este definita o variabila intreaga "en_pass", care ia valoarea 1 in momentul in care un pion poate fi luat printr-o luare "en_passant".

IV.2 Membrii publici ai clasei "piese"

Membrii publici ai clasei piese sunt functii care au rolul de a manipula datele private ale obiectelor, realizand astfel legatura cu programul. Ei sunt declarati dupa atributul "public :".

Asadar, cand dorim modificarea unei variabile sau numai aflarea datei continute de aceasta este necesar sa apelam o functie speciala care va modifica valoarea respectiva sau care o va returna, pentru a o putea utilize in procesul relational al programului.

Majoritatea functiilor publice au coduri simple, urmatoarele functii, avand numai rolul de a returna valoarea uneia din datele private ale obiectului:

int da_l() ;

int da_c() ;

char da_p() ;

int da_cul() ;

int da_mutare()

int en() ;

Tipul de declarare al functiilor este cel pe care functia il returneaza.

Urmatoarea functie are rolul de a modifica valoarea variabilei "en_pass" si este apelata evident atunci cand se deschide oportunitatea de a captura pionul care descrie prima sa mutare peste doua campuri la mutarea imediat urmatoare.

void pune_en()

Functia "schimba(int a,int b, int &c1, int &d)" are rolul de a altera coordonatele piesei. Procedura este necesara in unele parti ale programului, deoarece realizeaza o operatiune pe cat de simpla, pe atat de utila, deoarece este similara unei ridicari temporare de pe tabla a piesei. Este utila o asemenea actiune cand se doreste verificarea legalitatii unor mutari pe tabla de sah (se efectueaza o "pseudomutare" dupa care se poate evalua pozitia rezultata; daca aceasta din urma este valida, mutarea este corecta). In program aceasta functie va fi apelata de un numar par de ori deoarece, dupa ce am "ridicat" piesa este imperativa repozitionarea ei logica. Primii doi parametri contin coordonatele noi pe care le va primi piesa iar celelalte doua au rolul de a retine coordonatele initiale ale ei. Acestea din urma sunt retinute in partea de program care efectueaza cele doua apelari ale functiei, deoarece dotorita operatorului "&" functia va primi de fapt niste referinte la variabilele care ii sunt pasate, putand astfel sa le modifice. Procedeul este unul special si reuseste sa depaseasca doua probleme: o functie nu poate returna decat o singura valoare si, in plus ea lucreaza cu variabile temporare a caror valori sunt distruse cand functia se incheie.

void schimba(int a,int b,int &c1,int &d) ;

IV.3 Constructor si destructor

O functie constructor este o functie speciala, membra a unei clase care are acelasi nume cu clasa din care face parte. Este un lucru obisnuit pentru unele parti ale unui obiect sa necesite initializare inainte de a fi utilizate ( numele, pozitia initiala, culoarea, numarul de mutari realizate de piesa ). Cu ajutorul functiei constructor, C++ permite obiectelor sa se initializeze singure, atunci cand sunt create. Constructorul va fi apelat implicit si nu va necesita, apelarea efectiva nicaieri in program.

Constructorul utilizat an program accepta 4 parametri cu care va initializa piesa: pozitia pe orizontala, pozitia pe verticala, culoarea si denumirea piesei.

piese(register int i, register int j, register char cul,register char ps)

Destructorul este complementul constructorului. La fel ca si acesta, el este activate implicit la distrugerea obiectului ( la incheierea programului obiectele si variabilele create in program sunt distruse ). Are acelasi nume ca si constructorul, insa precedat de un character "~". Totusi , functia destructor poate fi apelata in program. Aici vom apela destructorul la eliminarea piesei de pe tabla, cu scopul de a altera proprietatile acesteia (numele, pozitia), intrucat, deoarece utilizam o matrice de obiecte, desi este distrus obiectul, el isi pastreaza pozitia in matrice, continuand sa fie prezent in program.

Destructorul da niste valori foarte mari coordonatelor piesei, ii altereaza numele, nu inainte de a ssterge piesa de pe tabla prin afisarea ei de culoarea campului pe care a fost cand a fost capturata.

~piese() ;

IV.4 Functii "friend"

O functie friend nu este membra a unei clase insa ea are acces direct la membrii privati ai clasei. Ea este definita in afara clasei careia ii este "prietena" si redeclarata in ineriorul acesteia cu titlul de "friend".

friend void afiseaza_piesa(register int i,register int j,int culoare,register char piesa);

Proiectul "Sah.cpp" utilizeaza o singura astfel de functie, si anume functia care are rolul de a hotari forma fiecarei piese in functie de "numele" ei.

Functia "afiseaza_piesa()" utilizeaza o instructiune decizionala cazuala: "switch". Expresia are rolul de a prelua caracterul care defineste numele piesei si, in functie de valoarea acestuia apeleaza una din functiile care deseneaza piese.

void afiseaza_piesa(register int i,register int j,int culoare,register char piesa)

}

IV.5 Mutarea pieselor

Functia "muta(register int i, register int j)" este o functie membu a clasei "piese", codul ei fiind insa explicitat in afara clasei, utilizand operatorul de specificare a domeniului de apartenenta "::".

Functia accepta doi parametri, asociati pizitiei finale ocupata de piesa, si anume linia si respective coloana.

Primul pas este stergerea piesei de pe pozitia initiala, prin desenarea pe campul initial ocupat a unei piese de culoarea campului. In cazul in care se muta regele se afiseaza pe pozitia initiala o cruce. (regele are desenata o cruce pe el iar cand este mutat functia care il deseneaza lasa in urma aceasta reminiscenta). Urmatorul pas consta in modificarea coordonatelor de pe tabla ale piesei, marirea numarului de mutari cu o unitate. Este atribuita pointerului global "ultimo" adresa din memorie a obiectului mutat. In fine, urmeaza o serie de instructiuni care au rolul de a facilita luarea "en passant": daca este efectuata prima mutare a pionului, variabila "en_pass" retine valoarea 1, altfel 0. cand este efectuata luarea "en passant" se distruge ultima piesa mutata (pion) a carui adresa din memorie este retinuta de pointerul "ultim" .

void piese::muta(register int i,register int j)

l=i;

c=j;

afiseaza_piesa(l,c,culoare,piesa);

mutare++;

if(piesa=='p' && (c==8 || c==1 ))

else en_pas=0;

if(ultim->da_p()=='p' && ultim->en() ) ultim->pune_en();

ultim=this;

} //codul de mai sus e necesar verificarii mutarii 'en passant' !

};

IV.6 Transformarea pionului

Cand pionul ajunge pe campul de transformare, se apeleaza functia "transformare()". Ea va afisa in coltul din stanga sus cele patru figuri in care poate fi transformat pionul, realizand totodata un mecanism pentru selectarea piesei dorite. Sunt prezente, de asemenea o serie de comenzi care au ca rol comunicarea cu jucatorul de la tastatura. Dupa ce se stabileste piesa in care se face substitutia, pionul se transforma in figura prin modificarea denumirii sale.

void piese::transformare()

break;

case 75 : if(i>0)

break;

}

} // muta conturul asupra piesei dorite si se opreste cand este apasat ENTER

switch(i)

// transforma pionul in figura

setfillstyle(SOLID_FILL,12);

bar(51,51,500,140);// acopera spatiul pentru mesaje

};

Capitolul V

Functiile globale

Functiile globale au rolul de a veghea la modul in care sunt mutate piesele, implementand regulile jocului de sah.

Pentru a putea manipula cele 32 de piese intr-o maniera cat mai rapida, am convenit la crearea unei matrici de obiecte. Declararea ei se face in functia principala, care va fi explicata mai tirziu.

piese piesa[]=; //crearea celor 32 de piese

Se observa cum la crearea matricii de obiecte am invocat parametrii necesari activarii functiei constructor a fiecaruia din cele 32 de obiecte. Acum vom putea apela foarte usor toate obiectele, neavand nevoie decat de matrice si de o variabila de ciclare, care va lua valori corespunzatoare pozitiilor in matrice a pieselor dorite.

Functiile globale insarcinate cu verificarea pozitiilor rezultate pe tabla de sah trebuie sa cunoasca toate piesele pentru a putea extrage niste rezultate din relatiile existente intre acestea, de aceea ele vor primi ca parametru matricea de obicte.

V.1 intro()

Functia "intro()" are rol introductiv, creand designul paginilor programului. Pentru desenarea literelor din cuvantul "SAH" de pe prima pagina se utilizeaza functia "fillpoly(int varfuri, int coordonate[])", care are rolul de a umple un poligon inchis cu n varfuri ale caror coordonate x si z sunt depuse in perechi consecutive in vectorul de intregi care ii este plasat ca parametru.

Comanda "setcolor(9)" reglementeaza utilizarea culorii albastre pentru scris cat si pentru desenul figurilor geometrice. "setfillstyle(SOLID_FILL, 12);" stabileste maniera de umplere cu culoare solida a figurilor geometrice create pe ecran, iar culoarea de umplere este orange.

In continuare se "deseneaza" cele trei litere ale cuvantului "SAH", creand pentru fiecare in parte un vector care sa resina coordonatele varfurilor lor. Vectorii au dimensiunea numeric egala cu dublul numarului de varfuri. Incluzand si virgula de sub "S" se creaza 4 astfel de vecori care sunt pasati pe rand functiei "fillpoly()".

In stanga jos se creaza apoi 4 patrate de culori alternative pe care se afiseaza cate o piesa de sah.

In dreapta jos se va afisa pe orizontala mesajul "Designed by" si pornind din colt, dar pe verticala numele autorului: "George-Stefan Farcas". Acest mesaj este omniprezent in program.

La apasarea oricarei taste programul acopera prima pagina trecand la cea de-a doua, unde este afisat un mesaj:

'Acest proiect de atestat descrie un joc de sah.

La realizarea sa a contribuit prof. Coordonator

Paraschiv Liliana'

Din nou, programul asteapta apasarea unei taste si purcede la afisarea celei de a 3-a pagini, cea care va constitui suportul tablei de sah si al tuturor mesajelor de avertizare.

Se tiparesc pe ecran niste instructiuni legate de inceperea unui joc nou si de parasirea programului.

inline void intro()

V.2 nou()

Functia pentru joc nou are rolul de a reinitaliza toate cele 32 de piese, pe rand, dupa care va afisa tabla de sah goala peste cea veche. Utilizand o variabila de ciclare, functia va afisa apoi piesele pe tabla.

void nou(register piese piesa[32])

V.3 contur()

Aceasta functie are rolul de a crea un contur incadrat in patratele tablei de sah afisata pe ecran, pentru a evidentia astfel campul activ facilitand procesul de I/O (in/out). Tabla de sah este de dimensiuni 256x256 pixeli, asadar fiecare camp are dimensiunile 32x32 pixeli. Pentru o manipulare mai usoara, funcsia accepta ca parametri valorile coordonatelor de tabla de sah, convertindu-le in pixeli.

Functia este definita ca "inline". O functie "inline", cand este apelata este inlocuita spontan cu codul continut, evitandu-se

inline void contur(register int i,register int j,register int c)

V.4 Desenarea pieselor si a tablei de sah

Desenarea tablei de sah se efectueaza cu ajutorul functiei "bar()" punand pe ecran dreptunghiuri umplute de culoare gri inchis cand suma liniei cu coloana este impara si gri deschis cand suma liniei cu coloana este para. Urmatorul pas este incadrearea intr-un patrat a tablei de sah cu functia "rectangle()". In fine se afiseaza in jurul tablei literele si cifrele corespunzatoare liniilor si coloanelor tablei de sah.

void afiseaza_tabla()

else

setcolor(8);

rectangle(149,149,407,407);

outtextxy(131,i=163,'8');

outtextxy(131,i+=32,'7');

outtextxy(131,i+=32,'6');

outtextxy(131,i+=32,'5');

outtextxy(131,i+=32,'4');

outtextxy(131,i+=32,'3');

outtextxy(131,i+=32,'2');

outtextxy(131,i+=32,'1');

j=131;

i+=32;

outtextxy(j+=32,i-4,'a');

outtextxy(j+=32,i-4,'b');

outtextxy(j+=32,i-4,'c');

outtextxy(j+=32,i-4,'d');

outtextxy(j+=32,i-4,'e');

outtextxy(j+=32,i-4,'f');

outtextxy(j+=32,i-4,'g');

outtextxy(j+=32,i-4,'h');

}

Piesele sunt concepute ca niste suprafete poligonale inchise si sunt realizate cu ajutorul functiei "fillpoly()" care retine doi parametri: numarul de varfuri al poligonului si coordonatele acestor varfuri depuse intr-un vector. Functiile care deseneaza piesele primesc ca parametri pozitia de pe tabla si culoarea. Iata spre exemplu functia corespunzatoare pionului:

void pion(register int i,register int j,int culoare)

V.5 ocupat()

Functia are rolul de a investiga existenta vreunei piese pe un camp dat al tablei de sah si de a returna pozitia acesteia in matricea "piesa[]".

Pentru aceasta se cicleaza matricea pana cand se gaseste o piesa ale carei coordonate coincid cu ale campului pe tabla de sah. Daca se gaseste o o piesa care sa verifice conditia i se returneaza pozitia din cadrul matricii, altfel se returneaza conventional -1.

int ocupat(register int i,register int j,register piese piesa[32])

; //returneaza -1 dak e liber sau pozitia din matrice a piesei care ocupa capmul

V.6 mutare_valida()

Functia este creata pentru a verifica validitatea mutarii care trebuie efectuata.

In cazul in care campul dorit este ocupat de o piesa de aceeasi culoare, mutarea este ilegala si functia va returna 0.

Se realizeaza mutarea logica temporara a piesei dorite cat si redicarea de pe tabla a piesei care a dat sah regelui propriu (daca este cazul) dupa care se cauta vreun atac asupra regelui propriu. Daca regele propriu nu ramane in sah dupa efectuarea mutarii logice, se poate purcede la mutarea efectiva a piesei. Aceasta manevra este necesara pentru ca la finalul mutarii regele sa nu ramana in sah.

In cazul tuturor piesei se verifica specificitatea mutarii in functie de numele piesei. Regele va muta un camp, calul in forma de "L", nebunii pe diagonale, turnurile in linie dreapta, dama va muta precum turnul sau precum nebunul, iar pionul cate un camp in fata,sau pe diagonala, cand captureaza.

Daca piesa este un pion, programul faciliteaza luarea "en passant", verificandu-se respectarea regulamentului. Din cauza faptului ca pionul se deplaseaza intr-o singura directie, este necesara detalierea unui cod pentru fiecare din cele doua culori. Cand se intalneste o incalcare a regulilor jocului, functia returneaza 0, altfel se continua pana la sfarsitul functiei. Daca se ajunge la sfarsitul functiei, mutarea va fi considerata valida iar functia va returna 1. asadar functia are un caracter restrictiv, deoarece daca functia ar returna intotdeauna 1 ar fi posibila efectuarea oricarei mutari.

Cand se muta regina, nebunul sau turnul se verifica in plus existenta vreunei piese intre campul de plecare si cel de sosire, astfel incat piesa sa nu sara peste vreo piesa in miscarea sa.

Regele este restrictionat de atacurile adverse si de piesele proprii. Cand se doreste efectuarea rocadei se face verificarea tuturor conditiilor impuse de regulament, dupa care se efectueaza mutarea turnului inca din interiorul acestei functii. Este necesara aceasta procedura deoarece in functia principala se va muta numai piesa selectata, si anume regele.

int mutare_valida(register int i, register int j,register int &cp,register piese piesa[32])

if( sah( piesa[cp].da_cul(), piesa ) && i == ultim->da_l() && j == ultim->da_c() )

piesa[cp].schimba(i,j,a,b);

r=sah(piesa[cp].da_cul(),piesa);

if ( !d ) ultim->schimba(x,y,d,d);

piesa[cp].schimba(a,b,c,c);

if(r)

switch(piesa[cp].da_p())

}

if ( ( j-piesa[cp].da_c() ) < 0 ) // nu muta inapoi

if ( ocupat( piesa[cp].da_l() , piesa[cp].da_c()+1 ,piesa ) != -1 )

if ( i!=piesa[cp].da_l() ) // nu muta pe alta coloana

if ( ( j-piesa[cp].da_c() ) > t ) //nu muta mai mult de doua campuri

}

break;

case 0 :

}

if ( ( j-piesa[cp].da_c() ) > 0 )

if ( ocupat( piesa[cp].da_l() , piesa[cp].da_c()-1 ,piesa ) != -1 )

if ( i!=piesa[cp].da_l() )

if ( ( piesa[cp].da_c() -j ) > t )

}

break; }

break;

case 't': if ( i == piesa[cp].da_l() || j == piesa[cp].da_c() )

}

if(l<0) for( k = piesa[cp].da_l()-1; k>i ; k-- ) }

if(c>0) for( k = piesa[cp].da_c()+1; k<j ; k++ ) }

if(c<0) for( k = piesa[cp].da_c()-1; k>j ; k-- ) }

}

else

break;

case 'n': if ( abs( i - piesa[cp].da_l() ) == abs( j - piesa[cp].da_c() ) )

}

if(l<0) for( k=1 ; k<c ; k++ ) }

}

else

}

if(l<0) for( k=-1 ; k>c ; k-- ) }

}

}

else

break;

case 'c': if ( ( abs( i - piesa[cp].da_l() ) + abs( j - piesa[cp].da_c() ) ) == 3 && abs( j - piesa[cp].da_c() ) <3

&& abs( i - piesa[cp].da_l() ) <3)

else

case 'r': if(atac(i,j,piesa[cp].da_cul(),piesa))

if ( piesa[cp].da_mutare()==0 && piesa[cp].da_c()==j && ( abs(piesa[cp].da_l()-i) == 2 ))

else

if( ocupat( k, piesa[cp].da_c(), piesa) != -1 )

if( atac( k, piesa[cp].da_c(),piesa[cp].da_cul(), piesa) )

tr= ocupat( q, piesa[cp].da_c(), piesa);

if( piesa[tr].da_mutare() != 0 )

piesa[tr].muta( k, piesa[cp].da_c() );

// rocada

}

else

if ( abs( i - piesa[cp].da_l() ) >1 || abs( j - piesa[cp].da_c() ) > 1 )

break;

case 'd': char ch;//retine 't' daca regina muta pe orizontala sau pe verticala si 'n' daca regina adopta o mutare de nebun

if ( i == piesa[cp].da_l() || j == piesa[cp].da_c() ) ch='t';

else

if ( abs( i - piesa[cp].da_l() ) == abs( j - piesa[cp].da_c() ) ) ch='n';

else

switch(ch)

{

case 't' : }

if(l<0) for( k = piesa[cp].da_l()-1; k>i ; k-- ) }

if(c>0) for( k = piesa[cp].da_c()+1; k<j ; k++ ) }

if(c<0) for( k = piesa[cp].da_c()-1; k>j ; k-- ) }

}

case 'n' :

{

register int l,c,k;

l= i - piesa[cp].da_l();

c= j - piesa[cp].da_c();

if(c>0)

{ if(l>0) for( k=1 ; k<c ; k++ ) }

if(l<0) for( k=1 ; k<c ; k++ ) }

}

else

}

if(l<0) for( k=-1 ; k>c ; k-- ) }

}

}

}

break;

default: break; }

return 1;

}

V.7 atac()

Functia are rolul de a verifica existenta vreunui atac din partea unei piese de o culoare data asupra unui camp care este specificat de catre parametrii primiti. Culoarea pieselor asupra carora ne orientam atentia este diferita de cea primita ca parametru.

Se cauta o relatie pozitionala intre campul dat si fiecare piesa din matrice care nu are culoarea respectiva, luand in vedere maniera de mutare a acesteia. Mecanismul este similar cu cel al functiei "mutare_valida()", insa nu ia in discutie mutarea piesei pe campul dat. Acest mecanism este util la verificarea pozitiei de sah, deoarece regele atacat este in sah indiferent daca piesa atacatoare este sau nu legata de propriul rege.

int atac(register int i, register int j,register int cl,register piese piesa[32])

else

if(!ac) return 1;

else continue;

}

if( piesa[t].da_l() == i ^ piesa[t].da_c() == j )

else

switch( piesa[t].da_l() < i )

if(!ac) return 1;

else continue;

}

continue;

case 't':

if( piesa[t].da_l() == i ^ piesa[t].da_c() == j )

else

switch( piesa[t].da_l() < i )

if(!ac) return 1;

else continue;

}

continue;

case 'n': if( ( abs ( piesa[t].da_l()-i ) == abs (piesa[t].da_c()-j) ) && piesa[t].da_c() != j )

else

if(!ac) return 1;

else continue;

}

continue;

case 'c': if ( ( abs( i - piesa[t].da_l() ) + abs( j - piesa[t].da_c() ) ) == 3 &&

abs( j - piesa[t].da_c() ) <3 && abs( i - piesa[t].da_l() ) <3 )

return 1;

else continue;

case 'p': switch(cl)

continue;

}

}

return 0;

}

V.8 sah()

Functia cauta in matrice regele de culoarea plasata ca parametru, dupa care verifica daca acesta este sau nu atacat, returnand aceeasi valoare ca apelarea functiei "atac()" pentru campul pe care se gaseste regele.

int sah(register int cl,register piese piesa[32])

V.9 remiza()

Partida se declara remiza atunci cand pe tabla mai raman numai cei doi regi, adica cand toate celelalte piese au fost capturate.

Cand una din piese este capturata, destructorul ei ii inlocuieste valoarea variabilei "char piesa" cu litera 'a'. Functia nu face altceva decat sa numere piesele capturate din matrice, adia cele care au litera ,a' depusa in variabila "char piesa". Daca numarul de piese capturate este 30 este asadar remiza.

int remiza(register piese piesa[32])

V.10 pat()

int pat(register int cl,register piese piesa[32])

k++;}

}

if( k==32 )

return 1;

return 0;

}

V.11 mat()

Se considera pozitie de mat pozitia in care regele este atacat si jucatorul respectiv nu poate efectua nici o mutare valida. Functia cauta regele in matrice, dupa care daca acesta este atacat continua cuverificarea celei de-a doua conditii verificand pentru fiecare piesa in parte posibilitatea efectuarii cel putin a unei mutari valide, caz in care nu mai este mat. Cazul in care piesa atacatoare poate fi luata anuleaza pozitia de mat.

int mat(register int cl,register piese piesa[32])

k++;}

}

if( k==32 )

return 1;

return 0;

}

Capitolul VI 

Functia principala - main()

Functia "main()" este functia principala a programului, functia care are rolul de a decide ordinea in care sunt apelate toate celelalte parti ale programului. Aici este inclus algoritmul propriu-zis.

La incpeut se initializeaza modul grafic DOS utilizand "initgraph()" dupa ce am detectat adresa directa a memoriei RAM video.

Se efectueaza functia "intro()", dupa care se afiseaza tabla de sah. Se creaza matricea de piese.

Conditiile fiind create pentru joc, mai este necesara comunicarea cu jucatorii. Se stabileste ca primul jucator care muta este albul si se afiseaza si se afiseaza conturul primului camp activ (care se va gasi in mijlocul tablei de sah) si se initializeaza variabila "cp", care retine pozitia in matrice a piesei selectate de jucator, cu -1. Utilizam o instructiune repetitiva "while" care se incheie cand este indeplinita conditia pusa la ciclare - aici se termina programul cand variabila "gata" ia o valoare diferita de 0. Fiecare iterare a instructiunii consta in citirea unui caracter de la tastatura, cu ajutorul functiei "getche()", care nu are efect pe ecran, dupa care se efectueaza codul aferent fiecarei taste la fiecare iterare se elibereaza "spatiul de lucru" situat deaspupra tablei de sah, pentru a nu suprapune iesirile textuale.

La introdcerea tastei "BACKSPACE" programul va interoga utilizatorul asupra dorintei de a incepe un joc nou, dupa care mai citeste un caracter. Daca acesta este "y"(yes) se incepe un joc nou.

Urmatoarea etapa este reprezentata de verificarea eventualelor pozitii de sah, mat sau remiza. Aceste pozitii au efect imediat pe ercan ( ex: ' ATENTIE! este sah!' ). Daca este mat sau remiza variabila "gata" este modificata, luand valoarea 1, iar jocul se incheie, programul citind, insa in continuare taste pana la introducerea uneia din tastele "ESC" SAU "BACKSPACE".

Urmeaza acum o instructiune cazuala "switch":

Cand se apasa o sageata sau o cifra (afara de "5") se muta conturul in directia corespunzatoare.

Cand se apasa "ENTER" SAU "5" se activeaza o expresie conditionala care are rolul de a selecta piesa situata pe campul activ sau de a o depune acolo. Cand se muta o piesa se verifica legalitatea mutarii cu ajutorul functiei "mutare_valida()", dupa care se efectueaza mutarea in cazul in care aceasta este valida. Cand campul este ocupat de o piesa adversa se activeaza destructorul acesteia, ea fiind considerata captivata.

In finalul iterarii trebuie verificata legalitatea selectarii piesei (daca a fost selectata o piesa alba cand negrul este la mutare, se abandoneaza selectia).

void main()

intro();

afiseaza_tabla();

piese piesa[]=; //crearea celor 32 de piese

register int i=4,j=4,ps,k,l,cp=-1,gata=0;

register char ch;

contur(i,j,4);

register int cl; //retine culoarea care muta

cl=15;

while(ch != 27)

if(!gata)

if(mat(cl, piesa) )

if(remiza(piesa))

switch(ch)

else continue; break;

case '6':

case 77: if(i<8)

else continue; break;

case '4' :

case 75: if(i>1)

else continue; break;

case '2' :

case 80: if(j>1)

else continue; break;

case '1': if(j>1 && i>1)

else continue; break;

case '3': if(j>1 && i<8)

else continue; break;

case '7': if(j<8 && i>1)

else continue; break;

case '9': if(j<8 && i<8)

else continue; break;

case '5':

case 13:

else

if(cp==ps) continue;

else

}

else

if(mutare_valida(i,j,cp,piesa))

}

if(piesa[cp].da_cul() != cl) cp=-1; //verifica daca este la mutare

break; }

default: break; }

}

}

getch();

}

Capitolul VII

Bibliografie:

Herbert Schildt - "C++ - Manual complet", editura Teora, Bucuresti 1997

https://rac.rosoftware.com/docs/other/IntroC_part3.pdf

Borland C++ Builder 5 Online Help

https://www.unixinside.org/papers/C++-Book/cap1.html

https://ro.wikibooks.org/wiki/Sah/Reguli_de_baza

https://en.wikipedia.org/wiki/Chess





Politica de confidentialitate


creeaza logo.com Copyright © 2024 - Toate drepturile rezervate.
Toate documentele au caracter informativ cu scop educational.