Pagina 3 din 6

Curs5, Functiile partea a doua

Scris: 28 Apr 2012, 13:28
de Manu
Marti, 24 aprilie 2012 ne-am intalnit pentru a cincia oara in cadrul cursului de programare in BGT.
Am vorbit in continuare despre functii, subiect inceput inainte cu o saptamana.

Primul lucru asupra caruia ne-am oprit a fost parametri optionali, cu valoare implicita.
O functie poate avea oricati parametri optionali, cu conditia ca acestia sa fie plasati ca ordine dupa parametri obligatorii.
Functiile definite inainte cu o saptamana aveau toate parametri obligatorii, daca nu completam vreunul interpretorul semnala eroare inca de la lansarea fisierului .BGT.
Pentru a defini un parametru optional cu valoare implicita, trebuie ca la scrierea variabilei locale dintre parantezele rotunde sa scriem in completare dupa nume = valoare (semnul egal si o valoare de tipul variabilei).

Sa presupunem ca avem nevoie de numere aleatorii intre o valoare minima specificata de noi si una maxima care in majoritatea cazurilor sa fie un milion.
Pentru a ne fi putin usurata munca, definim o functie random2() care sa aiba al doilea parametru optional, adica nefiind completat sa fie considerata valoarea 1000000:

Cod: Selectaţi tot

int random2(int nrmin, int nrmax=1000000)
{
return random(nrmin, nrmax);
}
Avand asadar functia random2() definita mai sus, putem scrie atat un cod care sa returneze un numar intre, sa zicem la nimereala, 7 si 15 scriind ceva la ambii parametri, cat si intre 7 si un milion scriind ceva doar pentru primul parametru:

Cod: Selectaţi tot

void main()
{
int aleatoriu;
aleatoriu=random2(7, 15);
alert("Salut!", "Un numar intre 7 si 15 este "+aleatoriu+".");

aleatoriu=random2(7);
alert("Salut!", "Un numar intre 7 si un milion este "+aleatoriu+".");
exit();
}
Pentru a fi clar, reamintim ca pot exista oricati parametri optionali, dar niciodata un parametru obligatoriu dupa unul optional.


Un al doilea lucru prezentat in cadrul intalnirii trecute a fost despre parametri cu transfer prin referinta.
Poate nu suntem tentati sa folosim foarte des o astfel de facilitate, dar sunt cazuri in care avem nevoie.
Am vazut inainte cu o intalnire ca schimbam o variabila atribuindu-i valoare returnata de o functie.
Tot asa putem schimba valoarea unei variabile scris ca parametru al unei functii definite.
O functie poate returna o singura valoare, dar avand posibilitatea modificarii valorii prin referinta, teoretic putem schimba oricate variabile.

Sa presupunem prin absurd ca avem nevoie de o functie care sa adune la o valoare tot timpul 2:

Cod: Selectaţi tot

void adunarecu2(int &out nr)
{
nr+=2;
}
Trebuie observat modul in care am definit variabila locala de la parametrul functiei, intre tip si nume fiind semnul AND / ampersand, urmat de cuvantul "out". Aceasta secventa, "&out", spune ca trebuie in urma rularii codului din blocul de cod ca insasi valoarea scrisa la parametru sa fie modificata ca valoare.

Utilizam in scriptul de mai jos functia creata: adunarecu2():

Cod: Selectaţi tot

void main()
{
int x=10;
alert("Salut!", "Valoarea lui x este "+x+".");
adunarecu2(x);
alert("Salut!", "Valoarea lui x este acum "+x+".");
exit();
}
Mai dam un exemplu in care se inverseaza valorile a doi parametri, fapt pentru care este cu adevarat utila schimbarea unei valori prin referinta, nu prin returning.
Codul este comentat:

Cod: Selectaţi tot

// Definim doua variabile globale:
int x=5, y=7;

void main()
{
// Aratam intai valoarea celor doua variabile:
alert("Salut!", "Valoarea lui x este "+x+", iar valoarea lui y este "+y+".");
// Aplicam functia de inversare, functie definita dupa inchiderea blocului main:
inversare_valori(x, y);
alert("Salut!", "Acum, dupa inversare, valoarea lui x este "+x+", iar valoarea lui y este "+y+".");
exit();
}

void inversare_valori(int &out nr1, int &out nr2)
{
// Atribuim lui temp1 valoarea primului parametru sa o tinem minte:
int temp1=nr1;
// Atribuim lui temp2 valoarea celui de-al doilea parametru sa o tinem minte:
int temp2=nr2;
// Atribuim lui nr1 valoarea lui temp2:
nr1=temp2;
// Atribuim lui nr2 valoarea lui temp1:
nr2=temp1;
}

Un al treilea lucru despre care am vorbit doar teoretic este recursivitatea functiilor.
O functie este recursiva daca se poate chema pe ea insasi, formand o ciclicitate.
In BGT / C++ exista aceasta posibilitate, de a se tot chema o functie pe ea pana o conditie este indeplinita. Nu insistam cu exemple deoarece inca nu am invatat if-ul, astfel incat ne este greu sa decidem cand sa se incheie bucla, repetarea functiei.


Dintre cele trei probleme despre care am vorbit in aceasta intalnire, cea in legatura cu parametrii impliciti / optionali este cea mai importanta, celelalte doua putand fi exersate si intelese si mai tarziu.


Ca tema de casa propun:

1. Sa se creeze o functie numita alert2() cu doi parametri. Aceasta functie sa poata afisa implicit ca titlu al ferestrei cu buton Ok string-ul "La revedere!", iar corpul sa fie obligatoriu de scris.
Codul urmator ar trebui sa functioneze nemodificat daca functia alert2() este creata corect:

Cod: Selectaţi tot

void main()
{
alert2("Salut!", "Bine ai venit, speram sa iti placa jocul nostru!");

alert2("Te mai asteptam sa incerci acest joc!");
exit();
}
Asadar, in cea de-a doua fereastra afisata ar trebui sa apara ca titlu: "La revedere".

2. Sa se creeze o functie random2() care sa aiba implicit ca numar minim numarul 0, astfel incat daca scriem doar un parametru valoarea returnata sa fie intre 0 si valoarea acestuia.
Codul urmator trebuie sa returneze un numar intre 0 si 5 daca functia random2() este creata corect:

Cod: Selectaţi tot

void main()
{
int aleatoriu=random2(5);
alert("Salut!", "Un numar aleatoriu intre 0 si 5 inclusiv este "+aleatoriu+".");
exit();
}
Daca mai sunt nedumeriri, putem in continuare sa clarificam prin exemple in alte posturi din acest topic.

Imprimarea acestei intalniri este la link-ul urmator:
Download Fisier MP3 05._Curs_BGT_-_Functiile_Partea2.mp3 (43,5 MB)

curs 5 tema

Scris: 29 Apr 2012, 16:43
de Eddy
1.

Cod: Selectaţi tot

void main()
{
alert2("Salut!", "Bine ai venit, speram sa-ti placa jocul nostru!");
alert2("Te mai asteptam sa incerci acest joc!");
exit();
}

void alert2(string c, string t="La revedere"!)
{
alert(t, c);
}
2.

Cod: Selectaţi tot

void main()
{
int aleatoriu=random2(5);
alert("Salut!", "Un numar aleatoriu intre 0 si 5 inclusiv este "+aleatoriu+".");
exit();
}

int random2(int nrmax, int nrmin=0)
{
return random(nrmin, nrmax);
}

Scris: 29 Apr 2012, 17:45
de Manu
Din nou perfect, nu s-a strecurat nici cea mai mica inadvertenta.
Asadar, functia random2() trebuie sa aiba ca prim parametru numarul maxim si ca al doilea parametru numarul minim, alta solutie nu era ca numarul minim sa fie optional. Suna putin ciudat sa specificam numarul maxim inaintea celui minim, dar consideram ca aceasta functie va fi folosita in majoritatea cazurilor cu numarul minim 0, astfel incat foarte rar va trebui sa scriem doi parametri.

Pentru a posta cod pe forum, este indicat sa folosim tagul [code] ... [/code], astfel incat nu va fi niciodata riscul ca sa fie interpretat ceva ca fiind cod BB.
Asadar, pentru a aparea "Cod:" la inceput si fontul sa fie diferit pentru evidentiere, pun mai jos un sablon pentru postare coduri:

[code]void main()
[
// Aici instructiuni...
}[/code]

In cazul codului BB, avem diverse taguri incadrate intre paranteze drepte, la fel cum in HTML sunt parantezele unghiulare.
Pentru a scrie un text ingrosat folosim:
[b]Aici textul.[/b]
Pentru a crea un link scriem:
[url=http://www.pontes.ro/]Site-ul Pontes[/url]

In acest post am dezactivat codul BB pentru a ramane si tagurile ca text normal. Pentru a dezactiva codul BB exista sub edit-ul de scriere check boxul: "Dezactiveaza codul BBCode in acest mesaj".

mentiune

Scris: 30 Apr 2012, 00:50
de Cornel
as atrage atentia asupra faptului ca, in constructia actuala, tema 1 are un mic inconvenient: se inverseaza titlul cu corpul la primul alert; prin urmare, ar putea fi acolo un simplu alert("salut", "Bine ai venit etc etc"), si pe urma alert2 in forma sa scrisa de
Eddy

Scris: 30 Apr 2012, 23:40
de Manu
Ai dreptate, vad ca mi-a scapat, ar fi trebuit sa formulez altfel, de fapt sa inversez cele doua stringuri la primul alert2(). Am vrut sa fie folosit tot alert2() si la prima fereastra, asta pentru a vedea cumva utilitatea unei functii cu parametru optional.

Ne auzim maine seara la if-uri si, daca apucam, while-uri.

BGT Curs 6 - If si While

Scris: 03 Mai 2012, 04:00
de Manu
Marti, 01 mai 2012, a avut loc a sasea intalnire in cadrul cursului de programare in BGT.

Am vorbit despre if si while.

Ne folosim de if atunci cand vrem sa evaluam daca o expresie este adevarata sau falsa, in functie de aceasta urmand sau nu executarea instructiunilor dintr-un bloc de cod imediat urmator.
Pentru a delimita cat mai clar conditia de evaluat, o punem intre paranteze rotunde ca in exemplul de mai jos:

Cod: Selectaţi tot

void main()
{
int x=5, y=10;
if(x<y)
{
alert("Salut!", "Se pare ca x este mai mic decat y.");
}
exit();
}
Asadar, blocul de cod imediat urmator if-ului se executa in cazul de mai sus deoarece x fiind 5 si y fiind 10, este adevarat ca x este mai mic decat y.

Daca am schimba valoarea lui x in 11, blocul de cod nu s-ar mai executa, mesajul generat de alert() nu ar mai aparea si s-ar ajunge direct la functia exit().

Exista posibilitatea sa decidem efectuarea altor actiuni, executarea unui alt bloc de cod daca nu se indeplineste conditia, daca if-ul determina ca falsa expresia pe care o evalueaza.
Vorbit liber ar suna cam asa:
Daca x mai mic decat y:
Spune ca x este mai mic decat y.
Altfel:
Spune ca x nu este mai mic decat y, adica este mai mare sau egal.

Cod: Selectaţi tot

void main()
{
int x=11, y=5;
if(x<y)
{
alert("Salut!", "Se pare ca x este mai mic decat y.");
}
else
{
alert("Salut!", "Se pare ca x nu este mai mic decat y.");
}
exit();
}
In exemplul de mai sus se evalueaza o conditie, daca se determina ca adevarata ni se spune acest lucru, daca se determina ca falsa, else (= altfel), ni se spune ca nu este adevarata.

Putem insa crea mai multe ramuri ale if-ului, de exemplu pentru codul de mai sus sa avem mesaje diferite pentru toate cele 3 posibilitati, x mai mic, egal sau mai mare decat y.
Vorbit liber acest lucru ar suna astfel:
Daca x mai mic decat y:
Spune ca x e mai mic decat y.
Sau daca x este egal cu y:
Spune ca x este egal cu y.
Altfel:
Spune ca x este mai mare decat y.

Cod: Selectaţi tot

void main()
{
int x=11, y=5;
if(x<y)
{
alert("Salut!", "Se pare ca x este mai mic decat y.");
}
else if(x==y)
{
alert("Salut!", "Se pare ca x este egal cu y.");
}
else
{
alert("Salut!", "Se pare ca x este mai mare decat y.");
}
exit();
}
Codul de mai sus este sinonim cu:
Daca x mai mic decat y:
Spune ca x e mai mic decat y.
Sau daca x este egal cu y:
Spune ca x este egal cu y.
Sau daca x mai mare decat y:
Spune ca x este mai mare decat y.

Cod: Selectaţi tot

void main()
{
int x=11, y=5;
if(x<y)
{
alert("Salut!", "Se pare ca x este mai mic decat y.");
}
else if(x==y)
{
alert("Salut!", "Se pare ca x este egal cu y.");
}
else if(x>y)
{
alert("Salut!", "Se pare ca x este mai mare decat y.");
}
exit();
}

Pe scurt, o schema a if-ului este urmatoarea:

Cod: Selectaţi tot

if(expresia1 de evaluat)
{
// aici cod de executat daca expresia1 este adevarata.
}
else if(expresia2 de evaluat)
{
// aici cod de executat daca expresia2 este adevarata.
}
else if(expresia3 de evaluat)
{
// aici cod de executat daca expresia3 este adevarata.
}
else
{
// aici cod de executat daca niciuna dintre cele 3 expresii evaluate anterior nu au fost adevarate.
}

Putem folosi urmatorii operatori cand comparam doua valori:
  • < - este mai mic decat;
  • <= - este mai mic sau egal;
  • == - este egal;
  • != - nu este egal;
  • > - este mai mare decat;
  • >= - este mai mare sau egal;
  • ! inaintea unei conditii - este negatie, se decide adevarat daca expresia propriu-zisa este falsa.
Putem evalua cu if-ul si conditii multiple, in care sa fie necesar ca toate sau doar unele sa fie adevarate pentru ca intreaga expresie evaluata sa fie considerata adevarata.
Vorbit liber ar suna cam asa:
Daca x mai mic decat y si k mai mare decat l
Executa cod.

Cod: Selectaţi tot

void main()
{
int x=5, y=6, k=8, l=7;
if(x<y && k>l)
{
alert("Salut!", "Conditia dubla a fost indeplinita.");
}
exit();
}
Asadar pentru ca alert-ul de mai sus sa apara, trebuie ca ambele conditii sa fie indeplinite, a fost folosit operatorul logic && (= si). Acesta mai poate fi scris si "and":
if(x<y and k>l)

Un exemplu in care doar una din doua conditii trebuie sa fie adevarata ar fi urmatorul:
Daca x este mai mic decat y sau k este egal cu l:
Executa cod.

Cod: Selectaţi tot

void main()
{
int x=6, y=5, k=8, l=8;
if(x<y || k==l)
{
alert("Salut!", "Una dintre conditii este indeplinita, fapt suficient sa apara acest mesaj.");
}
exit();
}
Asadar pentru ca alert-ul de mai sus sa apara, trebuie ca cel putin una din cele doua conditii sa fie indeplinita, a fost folosit operatorul logic || (= sau). Acesta mai poate fi scris si "or":
if(x<y or k==l)


In cadrul acestei intalniri am mai vorbit despre while (= in timp ce).
O bucla while face ca un bloc de cod sa se execute repetitiv atata vreme cat o expresie este evaluata ca adevarata.
In ceea ce priveste expresia de evaluat, sunt valabile informatiile prezentate la if.

Cod: Selectaţi tot

void main()
{
int x=5, y=10;
while(x<y)
{
// aici un cod de repetat atata vreme cat x e mai mic decat y.
wait(5);
}
exit();
}
Observam ca in codul de mai sus acel while va executa blocul de cod la infinit, asta deoarece nu avem nici o metoda prin care x sa nu mai fie mai mic decat y, astfel incat conditia sa nu mai fie ineplinita si astfel sa se ajunga la exit().
Lansand codul de mai sus, nu am vedea nimic deoarece nu exista nici o instructiune pentru a fi creata o fereastra care sa fie activa pe durata while-ului.

Am utilizat in blocul de cod si instructiunea wait(5), o asteptare de 5 milisecunde la fiecare repetare a blocului de cod, astfel incat procesorul sa poata rasufla. Daca ar fi omisa intr-un while o astfel de instructiune in care procesorul sa astepte cate 5 milisecunde la fiecare repetare a blocului de cod, am ajunge la o suprasolicitare a acestuia, practic fiind posibil sa nu se mai poata utiliza calculatorul.

In blocul de cod al unui while pot fi scrise oricate instructiuni, precum:
- daca se apasa o anume tasta sa se intample ceva,
- daca este o anume ora sa se intrerupa fortat while-ul si sa se ajunga la urmatoarele instructiuni aflate dupa respectivul bloc de cod.
- daca se constata pierderea ultimei vieti intr-un joc, acesta sa se inchida etc.


Pana acum noi cream scriptulete care se executau cat de repede se putea, singura metoda de a vedea ceva fiind alert() care tinea in loc executia pana la apasarea butonului OK.
De acum vom utiliza un while care va tine programul activ cata vreme o conditie este indeplinita.
In blocul de cod aferent acestui while vom avea if-uri si instructiuni diverse, desigur ca si posibilitatea intreruperii buclei sau inchiderii programului.

O modalitate de a crea un while care sa ruleze pana este intrerupt fortat, ar fi:
while[true]
Aceasta inseamna pentru totdeauna, acel adevarat nu mai poate fi facut fals deoarece nu este propriu-zis rezultatul unei evaluari de conditie.

Pentru a intrerupe un while fortat atunci cand o alta conditie este evaluata de un if ca adevarata, putem folosi instructiunea speciala:
break;

Mai jos este un cod care va servi ca sablon in cursurile noastre viitoare.
Codul este comentat, poate fi luat cu copy - paste:

Cod: Selectaţi tot

void main()
{
// Cream o fereastra:
show_game_window("Un joc de proba");

// cream bucla care va tine fereastra creata activa, nu lasa sa se ajunga imediat la exit():
while(true)
{
// punem un if care va verifica daca se apasa tasta Q:
if(key_pressed(KEY_Q))
{
alert("La revedere!", "Acum jocul se va inchide, while-ul va fi spart imediat dupa apasarea butonului OK.");
break; // intrerupem fortat bucla.
}

wait(5); // este instructiunea esentiala pentru ca procesorul sa rasufle.
} 
exit();
}
Asadar, in scriptul de mai sus avem o fereastra si un while care ruleaza atata vreme cat nu se apasa tasta Q.
Blocul de cod al lui while se repeta pana se apasa Q.


Ar mai fi cateva detalii de surprins, acestea fiind cuprinse in imprimarea cursului.
Nu am insistat de exemplu in acest rezumat asupra modului de negatie, adica o expresie sa fie considerata adevarata atunci can conditia / conditiile nu sunt indeplinite, adica conditie!=true sau !(conditie).


Pentru tema propun:
Avand sablonul definit in ultimul cod, sa se creeze un simulator simplu de zaruri.
Daca se apasa tasta Enter (= KEY_RETURN), sa fie generate doua valori random care sa fie atribuite unor variabile globale int zar1 si int zar2.
Cele doua valori sa fie afisate intr-un random sau spuse prin JAWS.
Pentru a decide daca vom vedea zarurile sau le vom auzi cu vocea JAWS-ului, sa avem o variabila globala numita, sa zicem int speak_mode, care daca are valoarea 0 sa fie alert(), daca are valoarea 1 sa auzim vocea.
Asadar, modificand manual valoarea lui speak_mode din 1 in 0 sau din 0 in 1 sa schimbam modul de feedback.
Pentru a spune JAWS un mesaj, sa se foloseasca instructiunea:
screen_reader_speak_interrupt(1, "stringul");
Functia screen_reader_speak_interrupt() face ca un screen reader sa spuna ceva intrerupand ceea ce se vorbea anterior si cere doi parametri:
- un numar de la 1 la 4 care inseamna screen reader-ul ales, 1 este pentru JAWS.
- al doilea parametru este string-ul de verbalizat, poate fi folosit exact cea ce se pune la corp in alert().

Imprimarea acestei intalniri este la link-ul urmator:
Download Fisier MP3 06._Curs_BGT_-_If_si_While.mp3 (50,5 MB)

tema

Scris: 07 Mai 2012, 00:32
de Cornel
dupa furtuna de acu' cateva ore, am o conexiune foarte slaba - din 5 in 5 minute se intrerupe; deci varianta mea ar fi:

Cod: Selectaţi tot

int zar1=random(1, 6);
int zar2=random(1, 6);
int speak_mode;

void main()
{
show_game_window("sa dam cu zarul!");
while(true)
{
if (key_pressed(KEY_Q))
{
alert("la revedere!", "acum jocul se va inchide, while-ul va fi spart imediat dupa apasarea butonului ok.");
break;
}
else if (key_pressed(KEY_RETURN))
{
da_cu_zaru();
}
wait(5);
}
exit();
}

void da_cu_zaru()
{
if (speak_mode==1)
{
alert("salut", "ai dat: " + zar1 + ", " + zar2 + ".");
}
else
{
screen_reader_speak_interrupt(1, "ai dat: " + zar1 + ", " + zar2 + ".");
}
}
desigur, daca cele doua variabile int zar1 si zar2 vor fi locale adica mutand randurile in functie, dand enter va fi alt rezultat.

Scris: 07 Mai 2012, 02:17
de Manu
Este bine, de remarcat ca ai decis sa faci o functie separata, nu ai pus tot codul in if-ul pentru tasta RETURN.
Trebuie sa deschidem de fiecare data programelul pentru a avea alte zaruri.
Nu prea are sens sa fie incarcate variabilele zar1 si zar2 deja cu random() de la inceput, trebuie sa primeasca o valoare diferita la fiecare apasare a enterului, poate ca la cerinta nu am fost destul de clar.
Asadar, ar fi mai bine ca sa fie copiate primele doua randuri in functia ta void, dar fara cuvantul int daca le lasam declarate global.
Variabila speak_mode a fost declarata fara a fi incarcata cu vreo valoare, asta inseamna ca va avea un numar aleatoriu, asa se intampla la C++, se atribuie o valoare aleatorie la declarare daca nu se specifica ceva. In cazul de fata merge prin JAWS pentru ca aceasta optiune este la else, adica daca speak_mode nu este egal cu 1.
Poate ar fi mai bine sa fie inca o variabila locala pentru mesaj, ca sa nu il repetam textual si in alert() si in screen_reader_speak_interrupt().
Eu insist sa fie folosite pentru rigoare propozitiile cu litere mari, desigur ca aici nu conteaza decat daca este ales alert() ca mod de output al rezutatului.

Un cod propus de mine ar fi:

Cod: Selectaţi tot

int zar1, zar2; // nu le atribuim o valoare inca, pentru ca se vor modifica la apasarea Enter-ului.
int speak_mode=1; // pentru a vorbi JAWS.

void main()
{
show_game_window("Simulator virtual de zaruri");
while(true)
{
if (key_pressed(KEY_Q))
{
alert("La revedere!", "Acum jocul se va inchide, while-ul va fi spart imediat dupa apasarea butonului OK.");
break;
}
if (key_pressed(KEY_RETURN))
{
da_cu_zarul();
}
wait(5);
}
exit();
}

void da_cu_zarul()
{
zar1=random(1, 6);
zar2=random(1, 6);
string message = "ai dat: " + zar1 + ", " + zar2 + "."
if (speak_mode==1)
{
alert("Salut!", message);
}
else
{
screen_reader_speak_interrupt(1, message);
}
}
Nu prea are rost cand se cauta dupa taste in while sa fie folosit else if, poate ramane tot cate un if separat pentru fiecare tasta, vom discuta putin la curs daca ne amintim despre acest amanunt.
Am lasat variabilele ca fiind globale, desi in cazul de fata nu are sens, pot fi declarate in functia da_cu_zarul() deasupra lui string message, dar pentru obisnuinta... Uneori avem nevoie de ele si in alte locuri, de exemplu am putea seta tasta R sa repete ultimele zaruri aruncate. Daca ar fi declarate local, nu am putea face acest lucru.

Se poate aduce o mica imbunatatire, tot ca tema:
La tasta R sa fie repetata ultima aruncare.
O sugestie: sa fie declarata global variabila message, asta pentru ca la repetare sa nu mai scriem din nou intre ghilimele mesajul.

Rezolvare a temei, simulator simplu de zaruri

Scris: 11 Mai 2012, 00:15
de Manu
Mai jos este un model de rezolvare a temei.
Am facut un simulator simplu de zaruri. La tastele Enter se arunca zarul, la r se repeta ultima aruncare, la c se schimba modul de output (prin JAWS sau prin fereastra alert), fara sa se anunte verbal sau vizual acest lucru:

Cod: Selectaţi tot

int x=0, y=0;
int speak_mode=1;
string message="";

void main()
{
show_game_window("Simulator virtual de zaruri");

while(true)
{
// Daca se apasa Alt+F4 sa se inchida:
if(key_down(KEY_LMENU)&&key_pressed(KEY_F4))
{
break;
}

// Daca se apasa unul dintre Enter-uri, sa fie aruncate zarurile:
if(key_pressed(KEY_RETURN)||key_pressed(KEY_NUMPADENTER))
{
x=random(1, 6);
y=random(1, 6);
message=""+x+", "+y+".";
spune_zarurile();
}

// Daca se apasa r, sa se repete ultimele zaruri aruncate:
if(key_pressed(KEY_R))
{
spune_zarurile();
}

// Daca se apasa c, sa fie schimbat modul de output al mesajelor:
if(key_pressed(KEY_C))
{
if(speak_mode==1)
{
speak_mode=0;
}
else
{
speak_mode=1;
}
}

wait(5);
}

exit();
}

// Functia spune_zarurile:
void spune_zarurile()
{
if(speak_mode==1)
{
screen_reader_speak_interrupt(1, message);
}
else
{
alert("Zarurile:", message);
}
}
Daca sunt nelamuriri in privinta codului de mai sus, le vom clarifica aici in urma intrebarilor si sau comentariilor.

Curs 7 - switch, do ... while si for

Scris: 13 Mai 2012, 02:20
de Manu
Marti, 8 mai 2012 ne-am intalnit pentru a saptea oara in cadrul cursului de programare in BGT.
Am vorbit despre switch and case, do ... while si for.


Switch este foarte similar if-ului, doar ca face mai usoara verificarea unor conditii in functie de valoarea unei variabile.

Sa presupunem ca programam un joc in care, printre altele, trebuie sa avem o variabila energie si una viteza_de_reactie, cea de-a doua modificandu-se in functie de prima.
De exemplu, avand valoarea variabilei energie 100 la inceput, valoarea variabilei viteza_de_reactie sa fie de 0, daca energie este 90, viteza_de_reactie este 1, daca energie este 80, viteza_de_reactie este 2, ... daca energie este 10, viteza_de_reactie sa fie 9, iar in momentul in care energie ajunge la 0, jocul se termina. Practic sa presupunem ca energie este un procent, adica energie = 100 inseamna ca e suta la suta, iar valorile variabilei viteza_de_reactie inseamna numarul de secunde intre pumni. Este normal ca cu cat energia scade, numarul de secunde intre posibilii pumni plasati de jucator sa creasca, deci valoarea variabilei viteza_de_reactie sa creasca.
Desigur ca am putea crea acest lucru folosind if-ul, dar cu switch-ul este mult mai usor, prezint mai jos cum ar suna acest lucru vorbit:

Schimba in functie de valoarea variabilei energie
In cazul 100:
viteza_de_reactie este 0.
In cazul 90:
viteza_de_reactie este 1.
In cazul 80:
viteza_de_reactie este 2.
Tot asa pana in cazul 0, cand jocul se termina.

Codul fara o aplicare practica, doar pentru a ilustra sintaxa:

Cod: Selectaţi tot

int energie=100, viteza_de_reactie=0;

// Specificam sa fie considerate in cazuri valoarea variabilei energie:
switch(energie)
{
case 100:
viteza_de_reactie=0;
break;
case 90:
viteza_de_reactie=1;
break;
case 80:
viteza_de_reactie=2;
break;
case 70:
viteza_de_reactie=3;
break;
case 60:
viteza_de_reactie=4;
break;
case 50:
viteza_de_reactie=5;
break;
case 40:
viteza_de_reactie=6;
break;
case 30:
viteza_de_reactie=7;
break;
case 20:
viteza_de_reactie=8;
break;
case 10:
viteza_de_reactie=9;
break;
case 0:
alert("Hopa!", "Nu mai ai deloc energie, jocul se termina!");
exit();
default:
// sa nu se intample nimic...
}
Asadar, presupunand ca intr-un joc acest switch and case este intr-o bucla while alaturi de toate celelalte coduri care tin de actiunea jocului, de fiecare data cand una din valorile divizibile cu 10 ale variabilei energie este detectata, este schimbata si valoarea variabilei viteza_de_reactie. Putem presupune ca energie scade atunci cand primim un pumn sau cand ne impiedicam etc. Pe langa faptul ca se schimba viteza_de_reactie, poate vrem sa punem si cate un sunet care sa ilustreze gafaiala, astfel incat scaderea energiei sa fie specificata cumva si sonor.

La fiecare sfarsit de cod al unui case am pus instructiunea break, asta pentru ca la o rulare a switch-ului sa nu mai fie verificate si celelalte valori. Aici este o diferenta fata de if, practic cand este detectata ca adevarata o ramura a lui switch, sunt verificate si celelalte daca nu se scrie break pentru a sari peste restul ramurilor. In cazul lui if, daca una din ramuri este detectata ca fiind adevarata, nu mai sunt verificate si urmatoarele, fapt pe care l-am explicat in cursul anterior.

Mai exista ca un ultim case: default.
Acest default este echivalentul lui else-ul if-ului, daca nici una din situatii nu este detectata, se poate specifica ce sa se intample default (implicit), noi nu am pus acum nici un cod, ci doar un comentariu.

De mentionat ca in BGT pot fi verificate cu switch doar valorile unor variabile de tip numar - int, float sau double.


Do ... while este un uloop foarte asemanator cu while.

Cream intai un while pe care il transformam apoi in do ... while sa vedem care ar fi diferenta.

In urmatorul cod vom avea un while care va repeta blocul de cod aferent atata timp cat valoarea lui x este mai mica decat valoarea lui y, il incrementam in blocul de cod pe x cu 1, dupa care ne uitam la valoarea lui x.

Cod: Selectaţi tot

int x=0, y=0;

while(x<y)
{
x++;
}
alert("Salut!", "Valoarea lui x este "+x+".");
Vom observa ca alert-ul va afisa valoarea lui x ca fiind 0, asta pentru ca nu a fost indeplinita deloc conditia while-ului, x nu era mai mic decat y, ambele fiind egale cu 0, deci nu a apucat sa se intample nici macar o data incrementarea lui x cu 1.

Reformulam codul acum cu do ... while, dupa care vom explica mai amanuntit cum stau lucrurile:

Cod: Selectaţi tot

int x=0, y=0;

do
{
x++;
}
while(x<y);
alert("Salut!", "Valoarea lui x este "+x+".");
Vom observa ca valoarea lui x ajunge sa fie 1, asadar se intampla o data incrementarea lui x cu 1.

Do ... while, fata de while, face ca blocul de cod sa ruleze cel putin o data, indiferent ca este sau nu indeplinita conditia din instructiunea while.
Randul cu while din final va avea si ";" (punct si virgula), este practic o instructiune.

Pentru a avea un looping activ pana la apasarea tastei q putem scrie:

Cod: Selectaţi tot

do
{
// Aici codul de repetat.
}
while(!key_pressed(KEY_Q));
Adica fa blocul de cod pana se apasa tasta q. In aceasta situatie practic nu exista nici o diferenta intre formularea cu while si cea cu do ... while.

Acest do ... while este ca si cum i-am spune cuiva:

Fa urmatorul lucru!
Da-mi un pumn!
Atata timp cat vreau, dar nu vreau.

Din start atata timp cat vreau e fals, deci din start eu stiu ca nu vreau, dar pentru ca a auzit acest lucru abia la sfarsit, el a apucat sa imi dea un pumn.
Cu while simplu nu as fi primit nici un pumn:

Atata tim cat vreau, dar nu vreau:
Da-mi un pumn!

Deci din start nu vreau si nu apuca sa imi dea nici macar un pumn. Daca as vrea, conditia ar fi adevarata si mi-ar tot da pumni repetitiv pana nu as mai vrea.


For-ul este cea mai complexa bucla.
Prin for repetam un bloc de cod la fel ca si cu while, doar ca putem specifica prin 3 instructiuni de cate ori sa se intample acest lucru.

Avem o variabila la care ii atribuim o valoare initiala insemnand punctul de start, apoi specificam limita (pana cand sa se intample for-ul), in cele din urma, o atreia instructiune spune cum sa se modifice valoarea variabilei.

Vorbit ar suna cam asa:

Pentru x start la 0, pana cand ix mai mic decat 10, creste-l pe x cu cate 1:
Se face o actiune de 10 ori.

Cod: Selectaţi tot

for(int x=0; x<10; x++)
{
// Aici codul de repetat.
}
Asadar, am declarat o variabila locala int x cu valoarea initiala 0.
Am spus ca blocul de cod sa se intample pana cand x este mai mic decat 10.
In cele din urma am spus ca x sa creasca cu cate 1.

Desigur ca s-ar putea face acelasi lucru si cu while:

Cod: Selectaţi tot

int x=0; // cream variabila x cu valoarea initiala 0.
while(x<10) // atata timp cat x mai mic decat 10:
{
// Aici codul care se repeta de 10 ori.
x++; // aici creste x cu cate 1.
}
Cu toate ca for-ul este formulabil si prin while, preferam sa il folosim pe acesta, fiind mult mai usor sa declaram intr-un singur rand toate cele 3 instructiuni.

Pun mai jos un cod intreg care simuleaza un cronometru.
La inceput vom fi intrebati cate secunde sa ruleze cronometrul, dupa care se va auzi JAWS spunand fiecare secunda:

Cod: Selectaţi tot

void main()
{
// Cream o fereastra principala:
show_game_window("Cronometru simplu in BGT creat cu for-ul");

// atribuim unei variabile de tip string o valoare scrisa in input_box():
string text=input_box("Limita", "Cate secunde sa ruleze cronometrul?");

// Atribuim unei variabile de tip int valoarea string-ului de mai sus convertita de la string la int:
int max=string_to_number(text);

// Cream for-ul care va rula efectiv cronometrul:
for(int x=1; x<=max; x++)
{
wait(1000); // asteptare de o secunda.
screen_reader_speak_interrupt(1, ""+x); // Jaws il anunta pe x care tot creste cu cate 1.
}

exit();
}

Instructiunile din for pot fi formulate in diverse feluri, de exemplu:
Prima instructiune sa creeze o variabila cu orice valoare initiala.
A doua instructiune poate verifica si o conditie precum: valoarea mai mare decat o alta valoare.
A treia instructiune poate sa se modifice in diverse moduri: sa creasca din doi in doi x+=2, sa scada din 3 in trei x-=3 etc.

Transformam acum cronometrul de mai sus intr-un timer:

Cod: Selectaţi tot

void main()
{
// Cream o fereastra principala:
show_game_window("Timer simplu in BGT creat cu for-ul");

// atribuim unei variabile de tip string o valoare scrisa in input_box():
string text=input_box("Startul", "Cate secunde sa ruleze timer-ul?");

// Atribuim unei variabile de tip int valoarea string-ului de mai sus convertita de la string la int:
int max=string_to_number(text);

// Cream for-ul care va rula efectiv cronometrul:
for(int x=max-1; x>=0; x--)
{
wait(1000); // asteptare de o secunda.
screen_reader_speak_interrupt(1, ""+x); // Jaws il anunta pe x care tot creste cu cate 1.
}

exit();
}
A se observa ca am scris int x=max-1. Daca scriem de exemplu 10 pentru start, dupa ce trece o secunda si JAWS face primul anunt, acesta trebuie sa fie 9, finalul fiind la 0. Si in cazul cronometrului anuntul incepea de la 1, nu 0, si mergea pana la 10.


Ca tema propun modificarea cronometrului astfel incat anunturile sa se intample din 3 in 3 secunde, dar timpul efectiv de rulare sa fie real.
Daca aceasta tema este rezolvata de cineva cu succes, voi cere o completare care sa particularizeze putin cronometrul.


Imprimarea cursului 7 despre switch, do ... while si for este la link-ul urmator:
Download Fisier MP3 07._Curs_BGT_-_Switch_Do-While_For.mp3 (36,0 MB)

Scris: 13 Mai 2012, 16:00
de Ghita Potra
Am încercat o rezolvare a temei pe care i-am trimis-o lui Manu, nefiind într-u totul corect rezolvată, mi-a mai trasat o sarcină pe care sper să o fi rezolvat corect, rezultatul ar fi : cronometrul anunţă corect, anunţă 3 după trei secunde, nu ştiu dacă rezolvarea este ceea ce ar fi aşteptat Manu, dar, merge. Am să postez rezolvarea temei aşa cum mi-a sugerat Manu şi cei care vor mai încerca să nu mai facă aceleaşi greşeli ca mine.

Codul ar fi:

Cod: Selectaţi tot

void main()  
{ 
 show_game_window("Cronometru simplu in BGT creat cu for-ul");  
 string text=input_box("Limita", "Cate secunde sa ruleze cronometrul?");  
wait(3000);
 int max=string_to_number(text);  
for(int x=3; x<=max; x+=3) 
 { 
 wait(3000);
 screen_reader_speak_interrupt(1, ""+x);
 }   exit();
}

Scris: 13 Mai 2012, 16:29
de Manu
Ai gasit solutia pentru ca JAWS sa inceapa sa spuna de la 3 dupa 3 secunde, doar ca ai pus un rand in plus care face ca primul anunt sa fie de fapt dupa 6 secunde.
Acel wait(3000) dinaintea for-ului nu are sens, deoare ce el pana sa anunte 3, trebuie sa treaca oricum si prin wait(3000) de dinaintea functiei screen_reader_speak_interrupt().

Asadar, dau urmatorul cod corect, cel al lui Ghita Potra fara un rand, apoi cer inca un lucru putin mai complicat:

Cod: Selectaţi tot

void main()  
{ 
 show_game_window("Cronometru simplu in BGT creat cu for-ul");  
 string text=input_box("Limita", "Cate secunde sa ruleze cronometrul?");  
int max=string_to_number(text);  
for(int x=3; x<=max; x+=3) 
 { 
 wait(3000); 
 screen_reader_speak_interrupt(1, ""+x); 
 }   exit(); 
}
Sa se introduca o noua variabila de tip int, numita sa zicem interval, care sa faca cronometrul sa anunte din x in x secunde, unde x sa fie valoarea variabilei interval. Practic va trebuie ca variabila interval sa fie prezenta in locurile unde in cazul de mai sus aparea sau avea influenta valoarea 3.
Valoarea variabilei interval ar fi bine sa fie preluata dintr-un input_box, deci mai trebuie si o variabila intermediara de tip string.
Daca nu rezolva nimeni, voi pune eu intr-un final codul complet.
Daca cineva incearca sa rezolve si se impiedica la un punct, mai bine intreaba aici decat sa nu mai faca deloc. Gasirea solutiilor in programare tine de creativitate, este bine ca prin incercari sa se exerseze treptat aceasta creativitate.

Parerea mea este ca distanta dintre a nu sti programare ()sintaxa) pana la a sti programare (sintaxa) este mai scurta decat cea de la a sti programare (sintaxa) pana la a programa ceva. Asadar, trebui eexersat mult individual, cautat, scormonit dupa solutii etc, etc. Succes!

Scris: 14 Mai 2012, 10:47
de Ghita Potra
Am încercat şi rezolvarea celei de a doua părţi a temei, dar nu am reuşit decât parţial, zic eu, dacă aş reuşi să iau y-ul înainte de for ar merge, cel puţin aşa cred, merge şi aşa dar ciudat. Pun mai jos aşazisul cod:

Cod: Selectaţi tot

void main()  
{ 
 
show_game_window("Cronometru simplu in BGT creat cu for-ul");  
 string text=input_box("Limita", "Cate secunde sa ruleze cronometrul?");  
 int max=string_to_number(text);  //
 string interval=input_box("Intervalul", "Va fi de ... secunde.");        
        int y=string_to_number(interval);
for( y=y; y<=max;y+=y) 
 { 
 wait(y*1000);
 screen_reader_speak_interrupt(1, ""+y);
 }
exit();
}

Scris: 14 Mai 2012, 17:02
de Manu
Ar fi bine rezolvata tema, nu inteleg de ce ar trebui ca variabila declarata in for sa fie numita tot y, de ce nu ai ramas cu x-ul ca inainte. Asadar, inlocuind in trei locuri y cu x, mai precis unde si inainte era x, totul ar fi in regula.
Asteptam sa fad daca cineva rezolva cum trebuie wait-ul, ai facut-o asa cum trebuie, o inmultire la parametru, sa nu uitam ca poate fi parametru un calcul aritmetic, o functie etc.
In concluzie, e bine in principiu, rescrie codul si pune iar aici sa vedem un cronometru finalizat.

Scris: 14 Mai 2012, 18:27
de Ghita Potra
Fără ajutor nu îl rezolvam cum trebuie, mie îmi plăcea aşa cum mergea termina mult mai repede!
Şi acum codul făcut cu ajutorul tău cu mulţumirile de rigoare:

Cod: Selectaţi tot

void main()  
{ 
show_game_window("Cronometru simplu in BGT creat cu for-ul");  
string text=input_box("Limita", "Cate secunde sa ruleze cronometrul?");  
int max=string_to_number(text);  //
string interval=input_box("Intervalul", "Va fi de... secunde:");        
int y=string_to_number(interval);
for(int x=y; x<=max;x+=y) 
{ 
wait(y*1000);
screen_reader_speak_interrupt(1, ""+x);
} 
exit(); 
}