Izrada crteža pomoću petlji

Razmotrimo sledeći zadatak: neka je potrebno nacrtati 6 krugova, kao na ovoj slici:

../_images/target.png

Gledajući u sliku možemo da pretpostavimo (a moglo je da bude i rečeno u postavci) da su krugovi jednako razmaknuti. Ovo znači da je razlika poluprečnika svaka dva susedna kruga ista.

Veličinu krugova biramo tako da budu što veći, ali da mogu da stanu u dati prostor za crtanje od 300x300 piksela. Pošto je širina prozora 300 piksela, poluprečnik najvećeg kruga je 150. Kao razliku poluprečnika dva susedna kruga možemo da uzmemo \({150 \over 6} = 25\). Tako dobijamo poluprečnike 25, 50, 75, 100, 125, 150.

Na osnovu izračunatih vrednosti, mogli bismo da napišemo ovakav program:

Zamislimo da smo posle ovoga dobili novi zadatak da napravimo isti takav crtež, ali sa 5 krugova. Ovo je vrlo mala promena, zar ne? Trebalo bi da možemo da iskoristimo nešto od prethodno rešenog zadatka.

Kada započnemo rad na crtežu od 5 krugova, vidimo da vrlo malo od prethodnog programa možemo da iskoristimo. U stvari, možemo da iskoristimo samo ideju, a veličine krugova treba da izračunamo ispočetka.

Da smo program pisali drugačije, prilagođavanje bi bilo mnogo jednostavnije. Mogli smo na primer da broj krugova upišemo u promenljivu, a zatim da u svim potrebnim računanjima koristimo tu promeljivu. Taj program bi izgledao ovako:

U ovom programu je dovoljno da se izmeni samo jedan broj, pa da on crta bilo koji zadati broj krugova.

Kao što smo već pomenuli, kod mnogih crteža postoji neka pravilnost, kao što je simetrija ili neki deo koji se ponavlja (i mnoge druge, složenije pravilnosti). Ako shvatimo pravilnost na takvim crtežima i izrazimo je matematički, moći ćemo da je iskoristimo pri pisanju programa za crtanje takvih crteža, kao što smo uradili u prethodnom primeru. Na taj način dobijamo program koji je mnogo lakše izmeniti da bi se dobio neki drugi, sličan crtež. Kod crteža sa velikim brojem ponavljanja nekog dela (istovetnog ili malo izmenjenog), program koji koristi pravilnost će biti i dosta kraći.

Mnogi programi koje koriste milioni ljudi se stalno usavršavaju i dorađuju. Stalno se objavljuju nove verzije u kojima je nešto urađeno bolje. Prema tome, izmene programa su nešto potpuno normalno i nešto što se stalno dešava. Situacija je slična i sa programima koje sami pišemo. Kada napišemo neki program, lako može da se dogodi da se kasnije setimo nečega, zbog čega ćemo hteti da izmenimo deo programa koji je već napisan.

Zato, kada pišemo programe, treba da imamo na umu mogućnost da će neko (moguće i mi sami) hteti da napravi neki sličan program i da će možda želeti da upotrebi naš program kao početnu verziju.

Pogledajmo još jedan primer kako možemo da iskoristimo pravilnosti na crtežu za pisanje fleksibilnijeg programa (programa koji je lakše prilagoditi malo drugačijoj nameni).

Primer - antena

Ranije smo već imali program koji crta ovakvu antenu. Sada je program napisan tako da nije suviše teško izmeniti broj poprečnih segmenata, razmak između njih, razliku dužina uzastopnih segmenata i slično.

Deo programa koji crta poprečne segmente antene je mogao da bude napisan i ovako:

for i in range(6):
    pg.draw.line(prozor, pg.Color('darkgray'), (120 - 10 * i,  75 + 25 * i), (180 +  10 * i,  75 + 25 * i), 1 + i//2)

Ovako napisan program bi bio nešto kraći, ali prvi je jasniji, tako da svaki ima svoje prednosti. Istaknimo samo da su oba ova programa bolja od direktnog crtanja 6 linija za poprečne segmente (kao što smo to radili raije). Kada bi se ovaj deo programa sastojao od šest poziva funkcije za crtanje linije, bilo bi teže izmeniti i prilagoditi program crtanju drugačije antene.

Pravilno raspoređeni brojevi

U oba prethodna primera bilo je potrebno da nabrojimo neki niz ili nizove pravilno raspoređenih brojeva. U zadatku sa krugovima to su bili brojevi 25, 50, 75, 100, 125, 150 (poluprečnici krugova), a u zadatku sa antenom bile su nam potrebne čak četiri serije brojeva - x i y koordinate levih i desnih krajeva poprečnih segmenata antene. Konkretno, ti brojevi su:

  • x koordinate levih krajeva: 120, 110, 100, 90, 80, 70

  • y koordinate levih krajeva: 75, 100, 125, 150, 175, 200

  • x koordinate desnih krajeva: 180, 190, 200, 210, 220, 230

  • y koordinate desnih krajeva: 75, 100, 125, 150, 175, 200

Videli smo da postoje različiti načini da dobijemo potrebne vrednosti. Na primer, u zadatku sa koncentričnim krugovima, vrednosti 25, 50, 75, 100, 125, 150 mogli smo da dobijemo na bilo koji od sledećih (jednako dobrih) načina:

for r in range(25, 151, 25):
    pg.draw.circle(prozor, pg.Color("red"), centar, r, 2)
for i in range(br_krugova):
    pg.draw.circle(prozor, pg.Color("red"), centar, round(25 + i * 25), 2)
r = 25
for _ in range(br_krugova):
    pg.draw.circle(prozor, pg.Color("red"), centar, r, 2)
    r += 25

U opštem slučaju, ako treba dobiti seriju vrednosti a, a+d, a+2d, … a+(n-1)d, prethodna tri načina možemo da koristimo ovako:

for x in range(a, a + n*d, d):
    print(x)
for i in range(n):
    print(a+i*d)
x = a
for _ in range(n):
    print(x)
    x += d

Videćemo da se veliki broj zadataka sa crtanjem pravilno raspoređenih oblika može rešiti primenom ovakvih petlji.

Naglasimo još i da funkcija range sa korakom (sa tri argumenta) prima obavezno celobrojne argumente, pa u situacijama kada korak nije celobrojan njeno korišćenje nije moguće.

Kada nam je potrebno (kao u zadatku sa antenom) da napravimo nekoliko serija u jednoj petlji, prvi način je manje pogodan, pa treba birati neki od ostalih načina.

Sledeća pitanja će vam pomoći da utvrdite znanje o formiranju serija pravilno raspoređenih brojeva.

    Q-63: Upari niz brojeva sa petljom koja ga generiše. Pokušajte ponovo!
  • 100, 200, 300, 400, 500
  • for i in range(100, 600, 100)
  • 100, 300, 500
  • for i in range(100, 601, 200)
  • 100, 200, 300, 400, 500, 600
  • for i in range(100, 601, 100)
  • 200, 300, 400, 500, 600
  • for i in range(200, 601, 100)
    Q-64: Upari brojeve koji se dobijaju sa izrazom u petlji "for i in range(5):" koji ih generiše. Pokušajte ponovo!
  • 100, 150, 200, 250, 300
  • x = 100 + i*50
  • 50, 150, 250, 350, 450
  • x = 50 + i*100
  • 0, 100, 200, 300, 400
  • x = i*100
  • 100, 200, 300, 400, 500
  • x = 100+i*100

    Q-65: Koji izraz treba koristiti u petlji

    for i in range(19):
        x = ???
        ...
    

    da bi x imalo iste vrednosti kao u petlji

    for x in range(25, 500, 50):
        ...
    
  • x = 25 * i + 50
  • Ne.
  • x = (25 + i) * 50
  • Ne.
  • x = 25 * 2*i+1
  • Ne.
  • x = 25 + 50 * i
  • Tačno!

Slede zadaci za vežbu.

Merdevine

Izmenite program tako da se prečage merdevina crtaju u petlji.

Umesto 5 naredbi za crtanje linija, možete da upotrebite petlju sledećeg oblika:

for y in ???:
    pg.draw.line(prozor, pg.Color("brown"), (100, y), (200, y), 10)

Da biste na pravi način kompletirali petlju, treba da odgovorite na sledeće pitanje:

    Q-66: Koji od ponuđenih opsega daje vrednosti 50, 100, 150, 200, 250?

  • range(0, 50, 250)
  • Ne, za taj opseg prvi broj nije odgovarajući.
  • range(250, 50)
  • Ne, pokušajte ponovo.
  • range(50, 251, 50)
  • Tačno!
  • range(50, 250, 50)
  • Ne, za taj opseg poslednji broj nije odgovarajući.

Drveće

Izmenite program tako da se u tri prolaska kroz petlju crta po jedno drvo.

Program može da izgleda ovako:

pri čemu umesto upitnika treba staviti odgovarajuće izraze za x koordinatu. Kada i uzima redom vrednosti 0, 1, 2, potrebno je da izraz u prvoj naredbi uzima redom vrednosti 40, 140, 240, a u drugoj 10, 110, 210.

Rešetka

Izmenite program tako da se u jednoj petlji isrtavaju uspravne linije, a nakon toga u drugoj petlji vodoravne linije.