start     Articole     Despre mine    

Sa ne jucam cu numere aleatoare

Ce simti atunci cand auzi cuvantul aleator? Nu cumva simti o oarecare conotatie negativa in el? Te gandesti, cel mai probabil, la ceva intamplator, impredictibil, incert. Si nu esti departe de adevar. Insa ceea ce probabil nu stii in clipa asta este faptul ca numerele aleatoare sunt niste prieteni de nadejde pentru un programator de jocuri.

Fara numere aleatoare jocurile de calculator ar fi de o predictibilate trista. Cum sa joci ghiceste numarul daca stii deja despre ce numar e vorba, cum sa joci x si zero daca stii deja unde va muta calculatorul, cum sa joci mastermind daca deja stii culorile si pozitiile bilelor?

Din fericire, exista numere aleatoare. Hai sa vedem ce sunt ele si cum le poti folosi.

Un numar aleator este un numar ce nu poate fi prezis. Daca luam lucrurile la modul foarte strict, nu exista nimic cu adevarat aleator in lumea asta. Oricine crede ca realitatea in care traim e guvernata de niste legi precise (chiar daca necunoscute in totalitate) va fi de acord cu aceasta ultima afirmatie.

Numerele aleatoare cu care operam intr-un program de calculator sunt in realitate doar numere pseudo-aleatoare. Adica doar par greu de prezis, insa in spatele lor stau niste expresii matematice fixe si lipsite de ambiguitati.

Hai sa luam un exemplu simplu. Sa consideram o serie de numere in care primul numar este 3, iar urmatorul numar din serie il obtinem calculand restul impartirii la 13 a sumei dintre numarul curent si 7. Prin urmare, primele 10 numere dintr-o astfel de serie vor fi urmatoarele:

3, 10, 4, 11, 5, 12, 6, 0, 7, 1, …

Desi procedeul de calcul este foarte clar, seria de numere pe care o obtinem pare (cel putin la prima vedere) aleatoare. La o a doua vedere, insa, observam ca seria e departe de a fi impredictibila.

OK, exemplul a fost unul simplu si care a avut drept scop doar sa te faca sa simti un pic ce sta in spatele metodelor de a obtine numere pseudoaleatoare. Metodele serioase din acest domeniu chiar produc serii de numere foarte greu (a se citi “practic imposibil”) de prezis. (Nu voi intra in detalii pe acest subiect in articolul de fata.)

O astfel de metoda este cea care sta in spatele functiei predefinite NrAleator, pe care de azi inainte o poti folosi in simulatorul nostru online pentru a produce numere aleatoare intregi in intervalul [0, Nmax], unde Nmax este un parametru pe care il transmiti functiei NrAleator atunci cand o apelezi. Adica pentru a genera un numar aleator intre 0 si 9 (inclusiv) va trebui sa scrii NrAleator(9). (Dar daca vrei sa produci un numar aleator intre 1 si 10? Evident, folosesti expresia 1+NrAleator(9).)

Bun, acum hai sa ne jucam!

Ce ai spune sa coloram aleator intregul ecran de 10×10 puncte?

Daca ai parcurs cu atentie lectiile anterioare, atunci exercitiul acesta ar trebui sa nu-ti puna mari dificultati.

Hai sa vedem pas cu pas ce ar trebui sa facem.

In primul rand, trebuie sa parcurgem pe rand toate punctele de pe ecran. (Am mai facut asta. Aici doar repet.) Si cum putem face asta? Pai ecranul e organizat ca o matrice, deci cu linii si coloane. Ceea ce inseamna ca il putem parcurge fie linie cu linie, fie coloana cu coloana (si punct cu punct in cadrul liniei, respectiv coloanei).

Cand auzi “sa parcurgem” la ce te gandesti? La un while, desigur. Si nu numai atat, ci la o structura de genul urmator:

i = 1;
while (i<=10)
{
  // instructiuni de executat
  …
  i = i+1;
}

Adica o structura de program in care variabila i ia pe rand valorile 1, 2, 3, 4, 5, 6, 7, 8, 9, 10. Si pentru fiecare dintre aceste valori ale variabilei i se va executa blocul de instructiuni ce va fi pus in loc de cele 3 puncte din secventa de program.

Iar daca vreau sa parcurg ecranul linie cu linie, iar in cadrul fiecarei linii sa parcurg pe rand toate punctele de la stanga la dreapta, atunci nu-mi ramane de facut altceva decat ca in cadrul unei secvente de program de genul celei de mai sus sa introduc (in locul punctelor de suspensie) o secventa similara (dar folosind o alta variabila, si nu tot variabila i).

Adica ceva de genul urmator:

i = 1;
while (i<=10)
{

  j = 1;
  while (j<=10)
  {
    // instructiuni de executat
    …
    j = j+1;
  }

  i = i+1;
}

Ei bine, programul e acum aproape gata. Mai lipsesc doar instructiunile de declarare pentru variabilele i si j, precum si instructiunile prin care sa aprind punctul curent (adica punctul de pe linia i si coloana j de pe ecran) folosind o culoare selectata aleator dintre cele 8 disponibile (inclusiv alb).

Cum pot, deci, selecta culoarea?

Am functia NrAleator(Nmax), care imi returneaza un numar intreg aleator intre 0 si Nmax inclusiv. Iar mie imi trebuiesc aici numere intre 0 si 7 (corespunzator celor 8 culori, in ordinea urmatoare: ALB, NEGRU, ROSU, VERDE, ALBASTRU, GRI, GALBEN, TURCOAZ). Voi putea genera un astfel de numar cu NrAleator(7).

Si voi putea aprinde punctul de la coordonatele (j, i) in culoarea respectiva astfel: AprindeNrCul(j, i, NrAleator(7));. (Sau puteam sa folosesc o variabila temporara numita, de exemplu, culoare, si sa scriu asa: var culoare = NrAleator(7); AprindeNrCul(j, i, culoare);.) Deja te-ai intalnit cu functia AprindeNrCul in articolul trecut, unde ai vazut implementarea ei explicita. Avand in vedere utilitatea ei practica, am hotarat s-o introduc in cadrul functiilor predefinite pe care le ai la dispozitie de aici inainte.

Hai sa vedem intreg programul:

var i;
var j;

i = 1;
while (i<=10)
{

  j = 1;
  while (j<=10)
  {

    AprindeNrCul(j, i, NrAleator(7));

    j = j+1;
  }

  i = i+1;
}

Simplu si eficient, dupa cum poti vedea testandu-l mai jos.

(Browserul tau nu suporta Canvas!…)

Ce e foarte interesant la acest program e ca la fiecare apasare a butonului de executie rezultatul este altul. Atentie: Exista riscul ca rularea acestui program sa produca dependenta :-)!

Exercitiu: Cum ai face ca ecranul virtual sa contina o repartitie aleatoare de doar 3 culori (si anume ROSU, GALBEN si ALBASTRU)? Astept rezultatele in sectiunea de comentarii de mai jos.

 

Daca exista ceva ce nu ai inteles din acest articol, atunci iti recomand cu caldura cartea Cum programezi un joc de la zero, pe care o poti cumpara in format electronic de aici. In plus, eu sunt aici si imi face placere sa raspund intrebarilor tale.





13 comments
SimionRadu
SimionRadu

cea mai simpla solutie ;)


var i;

var j;


function AprindeNrCul3(x, y, nc)

{

if (nc == 0)

    Aprinde(x, y, GALBEN);

  else if (nc == 1)

    Aprinde(x, y, ALBASTRU);

  else if (nc == 2)

    Aprinde(x, y, ROSU);

}

i = 1;

while (i<=10)

{


  j = 1;

  while (j<=10)

  {


    AprindeNrCul3(j, i, NrAleator(2));


    j = j+1;

  }


  i = i+1;

}


Florea Calin
Florea Calin

function RGB()

{

var n=NrAleator(7)+2

  if(((n%2)==0)&&(n<8))

  {

    return n

  }

  else

  {

    return RGB()

  }

}


var c

  var l=1

  while(l<=10)

  {

    c=1

    while(c<=10)

    { 

      AprindeNrCul(c,l,RGB())

      c=c+1

    }

    l=l+1

  }


Cred ca e cam lung programu.

lupixxx
lupixxx

Solutia este sa modifici parametrul functiei NrAleator(7) in NrAleator(2), asta daca si albul este considerat o culoare.

Florin Birleanu
Florin Birleanu moderator

@lupixxx @Florin Birleanu Wow! O solutie neasteptata! Bravo! :-)


Totusi, solutia ta nu aprinde toate punctele din ecran (ci unele raman albe (si anume atunci cand nu se indeplineste conditia din "if")). Cum ai putea face sa le aprinzi pe toate?


(Chiar ai talent pentru rogramare!)

lupixxx
lupixxx

@Florin Birleanu @lupixxx

Atunci cand x=0 nu vrem sa se incrementeze j, ca sa nu treaca la patratica urmatoare, ci vrem o alta generare aleatoare dintre cele 3 culori.

while (j<=10)

{ x=NrAleator(7);

    if (x%2==0 && x!=0) 

    { 

      AprindeNrCul(j, i, x);

      j = j+1;

    }

  }


problema este ca atunci cand x==0, se executa un ciclu while degeaba. Ca sa evitama asta, si la fiecare executie sa avem o culaore valida, ma gandeam sa "fortam" x sa ia valorile 1,2 sau 3.


{ x=NrAleator(7);

    x=x-(x%2);

    if (x!=0) 

    { 

      AprindeNrCul(j, i, x);

      j = j+1;

    }

Daca x e par, valaorea lui va ramane aceeasi. Daca e impar, scadem 1, il facem par.


Insa aplicatia tot face un while degeaba daca x=0. Ma gandaem sa facem x=x+2 in acest caz, dar nu restrang caracteristica de aleatorism?

Florin Birleanu
Florin Birleanu moderator

@lupixxx @Florin Birleanu Dar hai sa ne gandim si asa: Ne intereseaza sa obtinem la fiecare pas in cele doua while-uri fix una dintre culorile urmatoare: ROSU - 2, ALBASTRU - 4, GALBEN - 6. 


Dar functia NrAleator(Nmax) ne genereaza doar numere (intregi) intre 0 si Nmax inclusiv. 


Insa putem face observatia ca avem urmatoarele coduri pentru culorile dorite:

ROSU: 2*(1+0)

ALBASTRU: 2*(1+1)

GALBEN: 2*(1+2)


Deci putem genera aleator unul dintre numerele din multimea {2, 4, 6} cu expresia 2*(1+NrAleator(2)), nu-i asa?... :-)

Florin Birleanu
Florin Birleanu moderator

@lupixxx Solutia propusa de tine intr-adevar face ca in loc de 8 culori sa avem doar 3. Dar culorile astea trei vor fi: ALB, NEGRU si ROSU. Cum ai face, insa, sa ai ROSU, GALBEN si ALBSTRU? :-) (Mai trebuie niste mici adaosuri in program...)

lupixxx
lupixxx

@Florin Birleanu @lupixxx
Pentru ca alb este cunloarea 0, trebuie sa evitam ca urmatorul nuamar aleator sa fie 0, deci: AprindeNrCul(j, i, (1+NrAleator(3)))

lupixxx
lupixxx

@Florin Birleanu @lupixxx var i;

var j;

var x;


i = 1;

while (i<=10)

{j = 1;

while (j<=10)

  { x=NrAleator(7);

    if (x%2==0 && x!=0) 

    AprindeNrCul(j, i, x);

    j = j+1;

  }

  i = i+1;

}

Florin Birleanu
Florin Birleanu moderator

@lupixxx @Florin Birleanu OK, in felul asta scapi de ALB. Dar tot nu ai rezolvat ce am zis in comentariul anterior :-) (caci acum vei avea NEGRU, ROSU, VERDE). 


Mai incearca! :-) Exercitiile astea iti vor dezvolta gandirea de programator.

tracius01
tracius01

un alt efect secundar este să-ți golești piscina de numere aleatorii (nimic îngrijorător zic eu :)) )