logica si culoare in programare
Si. Sau. Nu.
Inainte de a ne apuca de treaba asa vrea sa te gandesti putin la aceste trei cuvinte. Ce iti transmit ele? La ce te duc cu gandul?
Daca in gandurile tale a rasarit ideea de logica, atunci lectia aceasta va fi una usoara.
Iti voi vorbi aici despre operatori. Vei revedea operatorii cu care te-ai intalnit in lectiile trecute si vei invata altii noi.
Accentul va fi pus pe trei operatori logici cu ajutorul carora vei putea scrie cu usurinta programe mai scurte si mai clare. Practic, vei putea programa la fel de simplu cum gandesti. Singura diferenta e ca gandurile tale le vei exprima nu in cuvinte, ci in limbajul simplu, concis si lipsit de ambiguitate al programarii.
Culoare
Si ca sa iti infirm (la nivel subconstient 🙂 ) ideea ca logica ar fi ceva rigid si lipsit de culoare, am ales ca in aceasta lectie sa introduc putina culoare in ecranul nostru de 10×10 beculete (sau puncte, cum le-am mai numit).
Pana acum ecranul nostru a fost unul binar, fiecare punct de pe el putand avea doar doua stari, aprins sau stins. Pentru a trece punctul de la coordonatele (x, y) in starea aprins am folosit functia Aprinde(x, y), iar pentru a-l trece in starea stins, Stinge(x, y).
Reduse la esenta, ambele fuctii (Aprinde si Stinge) fac acelasi lucru — coloreaza un patratel de pe ecran. Prima il coloreaza cu negru, iar cea de-a doua il coloreaza cu alb.
Acest mod binar de a opera cu lucrurile nu pare sa aiba prea multe de-a face cu realitatea cotidiana, care e plina de culoare, nuante, ambiguitati si valori intermediare.
Insa calculatoarele asa lucreaza. De asta am ales sa te terorizez in lectiile de pana acum cu un ecran alb-negru. Ca sa simti la un nivel mai profund calculatorul pe care il programezi. Cei care se jeneaza de astfel de intimitati cu calculatorul nu cred ca vor putea sa ajunga programatori cu adevarat buni.
Dar de azi incolo am dat VERDE la culoare! 🙂
(si ROSU, si ALBASTRU, si TURCOAZ, si GALBEN, si GRI)
Plus NEGRU si ALB, care au fost folosite in mod implicit pana acum.
Deci in total ai la dispozitie 8 culori cu ajutorul carora iti poti dezlantui creativitatea pe care pana acum ti-am incarcerat-o intr-o temnita binara 🙂 .
Cum poti folosi aceste culori?
La fel de simplu ca si pana cum. Pentru a aprinde (deci pentru a-l colora cu NEGRU) punctul (x, y) folosesti Aprinde(x, y). Cum pana acum era posibila o singura culoare, doar coordonatele punctului erau suficiente ca parametri pentru aceasta functie. Insa daca vreau sa specific si culoarea punctului imi mai trebuie un parametru. Asa ca am introdus un al treilea parametru in functia Aprinde.
Asadar, Aprinde(x, y) va avea acelasi efect ca si Aprinde(x, y, NEGRU).
Dar ce efect vor avea urmatoarele instructiuni?:
Aprinde(1, 1, NEGRU)
Aprinde(2, 1, ALB)
Aprinde(3, 1, GRI)
Aprinde(4, 1, ROSU)
Aprinde(5, 1, VERDE)
Aprinde(6, 1, ALBASTRU)
Aprinde(7, 1, GALBEN)
Aprinde(8, 1, TURCOAZ)
Daca te-ai uitat pe imaginea de la inceputul acestui articol, ai observat pe linia de jos o serie de puncte colorate. Ei bine, ele sunt rezultatul rularii acestor 8 instructiuni.
(A se remarca faptul ca Aprinde(2, 1, ALB) este echivalent cu Stinge(2, 1).)
Operatori aritmetici
Hai sa incheiem paranteza asta lunga si sa vedem care e treaba cu operatorii. Chiar daca termenul poate iti suna prea matematic (sau, poate, muncitoresc), cu operatori ca + si – ai lucrat inca de mic si cu siguranta nu ti se par a fi lucruri dificile.
Voi face mai intai o trecere in revista a claselor de operatori pe care le-am folosit in lectiile de pana acum, dupa care voi vorbi despre operatorii logici.
Mai intai, operatorii aritmetici.
Ai folosit pana acum urmatorii operatori aritmetici: +, –, % si /. Ca sa completez lista, as mai adauga operatorul *.
Ce fac, pe scurt, fiecare dintre ei?
Operatorul + returneaza rezultatul adunarii celor doi operanzi ai lui.
Operatorul – returneaza rezultatul scaderii celui de-al doilea operand din primul operand.
Operatorul % returneaza restul impartirii primului operand la cel de-al doilea.
Operatorul / returneaza rezultatul impartirii primului operand la cel de-al doilea. Rezultatul este un numar real. Deci e posibil sa dea cu virgula 🙂 . Il poti rotunji la un numar intreg folosind functia Rotunjeste (pe care am introdus-o in lectia trecuta). (Nota: Catul impartirii numarului A la numarul B poate fi obtinut folosind urmatoarea expresie: (A-(A%B))/B. Adica mai intai scad din A restul impartirii lui la B (deci rezultatul va fi un numar divizibil cu B), dupa care impart rezultatul la B.)
Iar operatorul * returneaza rezultatul inmultirii primului operand cu cel de-al doilea.
In toate aceste explicatii, prin primul operand ma refer la cel din stanga, in vreme ce prin al doilea operand ma refer la cel din dreapta.
Gata! N-avem puteri, logaritmi sau radicali. (Iar daca avem cumva nevoie de ele, nu ne ramane altceva de facut decat sa le obtinem aproximari folosind operatorii pe care ii avem la dispozitie. Si uite asa ajungem sa vedem la ce sunt bune, de exemplu, seriile convergente… Dar asta e deja o alta discutie.)
Operatori relationali
Hai sa trecem la cea de-a doua clasa de operatori utilizati in programele de pana acum.
Au fost cazuri in care a trebuit sa comparam intre ele unele valori (valori numerice sau valori de variabile). In astfel de situatii am avut nevoie de operatori care sa ne spuna daca o valoare este egala cu o alta sau daca este mai mare sau mai mica.
Cu asta se ocupa operatorii relationali.
In lectiile de pana acum am folosit urmatorii operatori relationali: ==, >, <, <=. Pentru a completa lista, mai adaug operatorii >= si !=.
Sa-i luam pe rand si sa vedem ce fac ei.
Operatorul == retuneaza adevarat daca cele doua valori comparate sunt egale. (Nota: A nu se confunda cu operatorul =, cu ajutorul careia atribuim unei variabile o valoare numerica sau rezultatul unei expresii aritmetice.)
Operatorul > returneaza adevarat daca prima valoare este mai mare decat cea de-a doua.
Operatorul < returneaza adevarat daca prima valoare este mai mica decat cea de-a doua.
Operatorul <= returneaza adevarat daca prima valoare este mai mica decat cea dea doua sau egala cu ea.
Operatorul >= returneaza adevarat daca prima valoare este mai mare decat cea de-a doua sau egala cu ea.
Operatorul != returneaza adevarat daca prima valoare este diferita de cea de-a doua.
In caz contrar, fiecare dintre acesti operatori returneaza fals.
Ca si in cazul operatorilor aritmetici, oricare dintre operanzi poate fi o intreaga expresie (ce poate contine valori numerice, variabile si operanzi aritmetici). Pentru a controla ordinea in care se evalueaza operanzii se folosesc () (paranteze).
Spre deosebire de operatorii aritmetici, pe care ii puteam folosi pentru a calcula valori pe care sa le memoram eventual in variabile, operatorii relationali ii folosim in expresii conditionale (deci acele expresii care intervin in instructiunile daca (if) si cat timp (while)).
Operatori logici
Si iata ca am ajuns si la subiectul de care am pomenit inca de la inceputul acestui articol. Operatorii logici si, sau si nu.
Evident, acesti operatori nu fac calcule si nici nu compara valori.
Atunci unde ar fi ei utili? In construirea expresiilor conditionale ce se folosesc in instructiunile if si while.
In mod normal in cadrul acestor intructiuni se testeaza (daca este adevarata sau nu) o singura conditie. Insa daca dorim sa testam mai multe conditii ce facem?
Sa zicem ca dorim sa parcurgem pe rand toate punctele din linia cu y egal cu 1 de pe ecran si sa aprindem doar acele puncte pentru care x este mai mare decat 3 si este mai mic decat 7. Cum am putea proceda?
Sa ne uitam inca o data la conditia ce trebuie indeplinita pentru ca punctul curent sa fie aprins. Vedem ca de fapt conditia aceasta este compusa din doua subconditii: (C1) x > 3 si (C2) x < 7. Prin urmare, am putea verifica aceste doua conditii pe rand, cu ajutorul a doua instructiuni if, astfel:
if (x > 3)
{
if (x < 7)
{
Aprinde(x, y)
}
}
Daca in loc de doua subconditii am fi avut trei, ar fi fost nevoie de 3 astfel de if-uri. In plus, nici la capitolul claritate acest fragment de program nu sta prea bine.
N-ar fi frumos daca am putea scrie intr-un singur if intreaga conditie ((C1) si (C2))?
Ar fi. Si chiar se poate! Cu ajutorul operatorului && (si), care returneaza adevarat daca atat conditia din stanga lui, cat si cea din dreapta, sunt ambele adevarate.
Prin urmare, fragmentul de program anterior poate fi rescris in felul urmator:
if ( (x>3) && (x<7) )
{
Aprinde (x, y)
}
Altfel arata lucrurile acum, nu? Odata ce cunosti semnificatia fiecarui semn de acolo, e clar ca prima linie se citeste in limbaj natural ca “daca valoarea variabilei x este mai mare decat 3 si valoarea variabilei x este mai mica decat 7“.
Foarte similar stau lucrurile si pentru operatorul || (sau). Acest operator returneaza adevarat daca fie conditia din stanga lui, fie cea din dreapta, este adevarata. De asemenea, returneaza adevarat si pentru cazul in care ambele conditii sunt adevarate.
Sa folosim in scop demonstrativ un exemplu similar cu cel anterior. Doar ca de asta data ne propunem sa aprindem punctele pentru care x este mai mic sau egal cu 3 sau este mai mare sau egal cu 7.
Daca testez pe rand cele doua subconditii, fragmentul de program rezultat ar arata astfel:
if (x <= 3)
{
Aprinde(x, y)
}
if (x >= 7)
{
Aprinde(x, y)
}
Dar daca as avea mai multe astfel de subconditii? Evident, ar fi necesare mai multe if-uri. (Ca sa nu mai zic ca Aprinde(x, y) ar trebui scris in fiecare dintre aceste instructiuni de tip if.)
Cum ar arata acest fragment scris cu operatorul sau? Iata:
if ( (x<=3) || (x>=7) )
{
Aprinde(x, y)
}
Nu numai ca am scris mai putin, dar fragmentul rezultat este si mult mai clar.
Hai sa il vedem acum si pe cel de-al treilea operator logic despre care ti-am promis ca vom vorbi aici.
Nu.
Nu nu, ci nu. 🙂
Adica operatorul de negare. Acel operator prin care sa pot testa daca o anumita conditie este nu adevarata, ci falsa.
Acest operator se scrie ! (simbol cu care te-ai intalnit si in cadrul operatorului de testare a inegalitatii dintre doua valori, != (operatorul diferit)).
Spre deosebire de ceilalti doi operatori logici discutati, operatorul de negare (operatorul !) nu are doi operanzi, ci unul singur (deci nu este un operator binar, ci este un operator unar). El returneaza adevarat daca conditia este falsa, si returneaza fals in caz contrar.
Am putea sa traim si fara el, caci orice conditie ar putea fi transformata in contrara ei. Iar in cazul intructiunii daca (if) exista si blocul optional atfel (else).
Prin urmare, daca am dori sa parcurgem toate cele 10×10 puncte si sa aprindem toate punctele pentru care nu este adevarat ca y e diferit de 1, am putea scrie astfel:
if (y != 1)
{}
else
{
Aprinde(x, y)
}
Sau am putea folosi operatorul de negare, astfel:
if ( !(y!=1) )
{
Aprinde(x, y)
}
Castigul pe care il ofera acest operator nu pare sa fie unul major din punct de vedere al dimensiunii programului scris, insa el este important din motive de claritate. Nu este o raritate situatia in care este mai simplu si mai clar sa lucrez cu contrara unei conditii decat cu conditia insasi.
Niciun program de testat astazi?
Ba da! Iata mai jos caseta.
Cum “Unde e programul de verificat?”? Foloseste ceea ce ai invatat in lectiile de pana acum si contruieste-ti propriile programe de test.
Succes, si nu uita sa impartasesti cu noi realizarile tale!
Orice reactie pe care o primesc din partea ta ma incurajeaza sa continui acest proiect. L-am inceput singur, dar nu il pot continua fara ajutorul tau. Comenteaza, trimite si altora, scrie-mi intrebarile si nelamuririle tale. Arata-mi ca esti acolo si ca ma sustii.