While petlja

Već smo naučili dosta toga o petljama koje nam omogućavaju da ponavljamo stvari određeni broj puta.

Ponekad je, međutim, potrebno da nešto ponavljamo, ali ne znamo unapred koliko puta to treba ponoviti. Na primer, u igri Tic-tac-toe igra se odvija sve dok jedan od igrača ne pobedi ili više ne bude raspoloživih poteza, a to znači da će broj poteza varirati od igre do igre. To je jedna od situacija koja zahteva while petlju.

Primeri

Primer 1

Vratimo se na naš prvi program, konvertor temperature. Jedna od teškoća pri korišćenju ovog programa je što svaki put kada želimo da konvertujemo neku temperaturu moramo da restartujemo program. Jedna while petlja će nam omogućiti da ponovo unesemo novu temperaturu bez restartovanja programa. Prost način kako korisnik može da saopšti programu da je završio sa korišćenjem programa je da unese neku besmislenu vrednost kao na primer -1000 ( što je ispod apsolutne nule). Evo kako bi izgledao takav program:

temp = 0
while temp!=-1000:
    temp = eval(input('Enter a temperature (-1000 to quit): '))
    print('In Fahrenheit that is', 9/5*temp+32)

Pogledajmo najpre while naredbu. U njoj se kaže da ćemo ponavljati naredbe za unos i konverziju temperature, sve dok korisnik ne unese -1000. Kada unese -1000 petlja se zaustavlja. Program prvo upoređuje temp sa -1000. Ako temp nije -1000, program traži da se unese temperatura a zatim vrši konverziju. Posle toga program ponavlja petlju tako što ponovo upoređuje temp sa -1000. Ako temp nije -1000, program traži unos nove temperature, konvertuje je, i ponovo ponavlja upoređivanje. Ovaj proces se nastavlja sve dok korisnik ne unese -1000.

Potrebna nam je na početku programa naredba temp=0, jer bi nam bez nje Python interpreter javio grešku. Program bi u while naredbi pokušao da proveri je li temp različito od -1000, ali bi naišao na problem jer varijabla temp u tom trenutku ne postoji. Da to ispravimo, na početku programa deklarišemo varijablu temp dajući joj vrednost 0. Vrednost 0 ne predstavlja nikakvu posebnu vrednost. Mogli smo staviti i bilo koju drugu vrednost, osim -1000. (Ako bi stavili -1000, to bi prouzrokovalo da uslov u while petlji ne bude ispunjen pa se naredbe iz petlje ne bi nikada izvršile.)

Prirodno je što while petlju shvatamo kao stalno ponavljanje sve dok korisnik ne unese -1000. Međutim, kada konstruišemo uslov petlje treba da mislimo o tome šta treba da bude ispunjeno da bi se petlja odvijala (to jest da bi se naredbe iz petlje izvršavale).

while petlja je veoma slična if naredbi. Razlika je u tome što se blok nardbi (kada je uslov ispunjen) izvršava samo jedanput, dok se u while naredbi blok ponavlja više puta.

Primer 2

Jedan od problema gornjeg programa je što kada korisnik unese besmislenu vrednost -1000 da bi prekinuo petlju, program i za tu vrednost napravi konverziju i ne daje nam nikakvu poruku da je završio sa radom. Lepši način da se uradi gornji program je prikazan dole:

temp = 0
while temp!=-1000:
    temp = eval(input('Enter a temperature (-1000 to quit): '))
    if temp!=-1000:
        print('In Fahrenheit that is', 9/5*temp+32)
    else:
        print('Bye!')

Primer 3

Kada smo se prvi put sreli sa if naredbom napisali smo program koji je igrao jednu jednostavnu igru pogađanja brojeva. Problem sa tim programom je što je igrač imao samo jednu šansu da pogodi broj. Sada možemo if naredbu da zamenimo sa while naredbom i da dobijemo program koji omogućava korisniku da pogađa sve dok ne pogodi.

from random import randint
secret_num = randint(1,10)
guess = 0
while guess != secret_num:
    guess = eval(input('Guess the secret number: '))
print('You finally got it!')

Uslov guess != secret_num kaže da ako trenutni pokušaj nije tačan, onda treba nastaviti sa petljom. U ovom slučaju, petlja se sastoji od samo jedne naredbe, naredbe input, pa će zato program ponavljati zahtev za unos novog pokušaja, sve dok korisnik ne unese tačan broj. Potrebna nam je na početku naredba guess = 0 da bi obezbedili da se petlja izvrši po prvi put, to jest da varijabla guess ima neku vrednost za poređenje u uslovu petlje. Kolika će ta početna vrednost za verijablu guess nije važno u ovom trenutku. Potrebna nam je samo neka vrednost koja će biti različita od vrednosti za secret_num. Kada korisnik konačno pogodi traženi broj, petlja se završava i program nastavlja rad sa print naredbom iza petlje u kojoj se korisniku štampa otpozdravna poruka.

Primer 4

Možemo iskoristiti while petlju da imitiramo for petlju, kako je prikazano naniže. Obe petlje proizvode potpuno isti efekat.

for i in range(10):                 i=0
    print(i)                        while i<10:
                                        print(i)
                                        i=i+1

Setimo se da u for petlji varijabla i počinje sa 0 a završava se sa 9. Da napravimo odgovarajuću while petlju moramo da kreiramo varijablu i koja će biti u uslovu while petlje. Počinjemo tako što varijablu i setujemo na 0. Unutar while petlje imamo istu print naredbu kao i u for petlji, ali imamo i dodatnu naredbu i=i+1, da povećamo varijablu petlje ( što se u for petlji radi automatski).

Primer 5

Dole je prikazan naš stari prijatelj, program za konverziju iz Celzijusa u Farenhajte.

temp = eval(input('Enter a temperature in Celsius: '))
print('In Fahrenheit, that is', 9/5*temp+32)

Poželjno je da program koji preuzima podatke od korisnika proveri da li je uneti podatak validan. Najniža moguća temperatura je takozvana apsolutna nula i iznosi -273.15°C. Program koji sledi uzima u obzir tu činjenicu:

temp = eval(input('Enter a temperature in Celsius: '))
if temp<-273.15:
    print('That temperature is not possible.'))
else:
    print('In Fahrenheit, that is', 9/5*temp+32)

Jedan način da se gornji program poboljša je da omogućimo korisniku da ponovo unosi temperaturu sve dok ne unese ispravnu. Verovatno ste se sa nečim sličnim već susreli ako ste unosili u neki on-line formular vaš broj telefona ili broj kreditne kartice. Ako bi uneli pogrešan broj, od vas bi se tražilo da ponovite unos. Program koji sledi upravo tako i radi.

temp = eval(input('Enter a temperature in Celsius: '))
while temp<-273.15:
    temp = eval(input('Impossible.  Enter a valid temperature: '))
print('In Fahrenheit, that is', 9/5*temp+32)

Uočite da nam sada nije potrebna else naredba, kao što je gore bio slučaj kada smo koristili if naredbu. Uslov u while petlji nam garantuje da ćemo do print naredbe stići samo kada unesemo ispravnu temperaturu. Sve do tada, program će biti zaglavljen u petlji, stalno zahtevajući od korisnika da unese novu temperaturu.

Primer 6

Kao što je ranije navedeno, vrlo je korisna sposobnost čitanja koda (programa). Jedan način za razvijanje te sposobnosti je da igrate ulogu Python interpretera i da kroz program prolazite liniju po liniju. Probajmo to na sledečem kodu.

i = 0
while i<50:
    print(i)
    i=i+2
print('Bye!')

Na početku, varijabla i, dobija vrednost 0. Kao sledeće, program proverava uslov while petlje. Pošto je i jednako 0, što je manje od 50, biće izvršen kod koji je u bloku sa razmakom ispod while naredbe. U ovom kodu se najpre štampa vrednost varijable i a onda izvršava naredba i=i+2 koja dodaje 2 na i.

Varijabla i je sada 2 i program se vraća nazad na while naredbu. Ona proverava da li je i manje id 50, pa pošto je i jednako 2, što je manje od 50, ponovo se izvršava blok sa razmakom. Zato ponovo štampamo varijablu i pa na dodajemo 2 , i ponovo se vraćamo na početak while petlje da ponovo proverimo uslov. Ovako radimo sve dok varijabla i ne dobije vrednost 50.

U tom trenutku while uslov neće biti ispunjen ( True) i program će skočiti na prvu naredbu posle while bloka, u kojoj se štampa poruka Bye!. Rezultat rada ovog programa je štampanje brojeva 0, 2, 4, …, 48 posle čega sledi poruka Bye!.

Beskonačne petlje

Kada koristite while prtlje, pre ili kasnije ćete greškom poslati Python u petlju koja se nikad na završava. Evo jednog primera:

i=0
while i<10:
    print(i)

U ovom programu vrednost varijable i se nikad ne menja, pa će uslov i<10 uvek biti ispunjen. Python će neprekidno štampati nule. Da zaustavite program koji je uhvaćen u beskonačnoj petlji izaberite opciju Restart Shell u Shell meniju. Ovako možete zaustaviti sve programe pre nego što su sami izvršeni do kraja.

Ponekad je beskonačna petlja upravo ono što želite. Jednostavan način za pravljenje beskonačne petlje je sledeći kod:

while True:
    # Ovde idu naredbe koje treba ponavljati

Vrednost True se naziva Bulovskom (boolean) vrednošću i o njoj će biti reči kasnije.

Naredba za prekid petlje - break

Naredba break se koristiti da se prekine for ili while petlja pre njenog završetka.

Primer 1

Sledeći program omogućava korisniku da unese 10 brojeva. Korisnik, međutim, može da prekine i ranije ako unese negativan broj.

for i in range(10):
    num = eval(input('Unesite broj: '))
    if num<0:
        break

Ovo se može postići i while petljom, kako sledi:

i=0
num=1
while i<10 and num>0:
    num = eval(input('Unesite broj: '))

Oba metoda su u redu. U mnogim slučajevima break naredba pomaže da vaš program bude razumljiviji i manje zamršen.

Primer 2

Ranije smo koristili while petlju da ponavljamo unos temperature koju treba konvertovati. Ovde dajemo manje više originalnu verziju na levoj strani, za poređenje sa verzijom koja koristi break naredbu (na desnoj strani).

temp = 0                           while True:
while temp!=-1000:                     temp = eval(input(': '))
    temp = eval(input(': '))           if temp==-1000:
    if temp!=-1000:                        print('Bye')
        print(9/5*temp+32)                 break
    else:                              print(9/5*temp+32)
        print('Bye!')

Naredba else u while petlji

Postoji i opciono else koje možete koristiti sa break naredbom. Kod u else bloku će se izvršiti ako se petlja završi bez break događaja.

Primer 1

Evo primera koji je sličan jednom od predhodnih primera.

for i in range(10):
    num = eval(input('Unesite broj: '))
    if num<0:
        print('Program prekinut ranije')
        break
else:
    print('Korisnik je uneo svih deset brojava')

Program omogućava korisniku da unese 10 brojeva. Ako korisnik unese negativan broj, program štampa poruku Program prekinut ranije i ne traži unos novih brojeva. Ako korisnik unese samo ne-negativne brojeve program štampa Korisnik je uneo svih deset brojava.

Primer 2

Evo dva načina za proveru da li je neki ceo broj num prost ili nije. Prosti brojevi su oni brojevi koji su deljivi samo sa 1 i sa samim sobom. Program prikazan levo koristi while petlju, a program prikazan desno koristi for/break petlju:

i=2                              for i in range(2, num):
while i<num and num%i!=0:            if num%i==0:
    i=i+1                                print('Nije prost')
if i==num:                               break
    print('Prost')               else:
else:                                print('Prost')
    print('Nije prost')

Ideja u oba slučaja je da se pokuša sa svim brojevima između 2 i num-1, pa ako je bilo koji od njih delilac broja num, tada znamo da num nije prost broj. Da proverimo da li je neki broj delilac broja num, treba samo da proverimo da li je num%i jednako 0.

Ideja u verziji sa while petljom je da nastavimo ispitivanje kada nismo naišli na delioca. Ako smo prošli kroz celu petlju a da nismo našli delioca, tada će i biti jednako num što znači da je num prost broj.

Ideja kod for/break verzije je da pokušavamo deljenje sa svim potencijalnim deliocima, pa čim naiđemo na delioca znamo da num nije prost i štampamo Nije prost i prekidamo petlju. Ako kroz petlju prođemo bez prevremenog prekida, to će značiti da nismo naišli na delioca. U tom slučaju će biti izvršen else blok, odnosno program će štampati da je num prost broj.

Igra pogađanja broja, na lepši način

Modifikovaćemo igru pogađanja broja tako da program poštuje sledeća pravila:

Igrač ima samo pet pokušaja da pogodi broj. Posle svakog pokušaja program saopštava da li je pokušani broj manji ili veći od traženog broja. Program štampa odgovarajuću poruku kada igrač pobedi ili izgubi igru.

Ovde je prikazan primer kako treba da izgleda tok igre:

Unesite vaš pokušaj (1-100): 50
MANJI. 4  preostalih pokušaja.

Unesite vaš pokušaj (1-100): 25
MANJI. 3 preostalih pokušaja.

Unesite vaš pokušaj (1-100): 12
MANJI. 2 preostalih pokušaja.

Unesite vaš pokušaj (1-100): 6
VEĆI. 1 preostalih pokušaja.

Unesite vaš pokušaj (1-100): 9
MANJI. 0 preostalih pokušaja.

Izgubili ste.  Tačan odgovor je 8

Razmislimo najpre šta će nam sve trebati u ovom programu:

  • Trebaće nam slučajan broj, pa ćemo zato imati import naredbu ns početku programa i randint funkciju negde u programu.
  • Da omogućimo korisniku da pokušava sve dok ne pogodi ili ne prekorači broj dozvoljenih pokušaja. Ovo ćemo postići korišćenjem while petlje u kojoj će uslov uzimati u obzir obe mogućnosti završetka petlje.
  • Trebaće nam input naredba da dobijemo korisnikov pokušaj (broj). Pošto će se to ponavljati, ova naredba će biti unutar petlje.
  • Trebaće nam jedna if naredba za ispitivanje da li je broj manji ili veći od traženog. Pošto će se ovo ispitivanje ponavljati i ono će biti u petlji odmah iza input naredbe.
  • Trebaće nam jedan brojač da prebrojavamo broj pokušaja koje je korisnik napravio. Svaki put kada korisnik napravi pokušaj, ovaj brojač se poveča za jedan pa će zato i ova naredba biti u petlji.

Sada ćemo početi pisanje onih delova programa koji su lagani:

from random import randint

tajni_broj = randint(1,100)
brojac_pokusaja = 0

while #ovde treba da dodje uslov petlje#
    pokusaj = eval(input('Unesite vaš pokušaj (1-100): '))
    brojac_pokusaja = brojac_pokusaja + 1
    # if naredba za ispitivanje da li je pokusaj manji ili veci

U while petlji želimo da nastavimo petlju kad god korisnik ne pogodi tajni broj i kad korisnik nije iskoristio dozvoljeni broj pokuđaja:

while pokusaj != tajni_broj and broj_pokusaja <= 4:

Naredba if za proveru da li je korisnik uneo mani ili veći broj (ili je pogodio):

if pokusaj < tajni_broj:
    print('VEĆI.', 5-broj_pokusaja, 'preostalih pokušaja.\n')
elif pokusaj > tajni_broj:
    print('MANJI.', 5-broj_pokusaja, 'preostalih pokušaja.\n')
else:
    print('Pogodili ste!')

Na kraju, bilo bi lepo da korisniku javimo da je prekoračio broj pokušaja. Kada prekorači taj broj, while petlja prekida rad i program nastavlja sa sledećom naredbom posle bloka naredbi iz petlje. U tom trenutku možemo da štampamo poruku, ali samo ako je korisnik prekoračio broj pokušaja, ali ne ako je pogodio. To postižemo sa još jednom if naredbom posle petlje. To je pokazano naniže u kompletnom programu za ovu igru.

from random import randint

tajni_broj = randint(1,100)
brojac_pokusaja = 0
pokusaj = 0

while pokusaj != tajni_broj and brojac_pokusaja <= 4:
    pokusaj = eval(input(' Unesite vaš pokušaj (1-100): '))
    brojac_pokusaja = brojac_pokusaja + 1
    if pokusaj < tajni_broj:
        print('VEĆI.', 5-brojac_pokusaja, 'preostalih pokušaja.\n')
    elif pokusaj > tajni_broj:
        print('MANJI.', 5-brojac_pokusaja, 'preostalih pokušaja.\n')
    else:
        print('Pogodili ste!')

if brojac_pokusaja==5 and pokusaj != tajni_broj:
    print('Izgubili ste.  Tačan odgovor je', tajni_broj)

A evo kako bi mogao da izgleda program napisan pomocu for petlje:

from random import randint

tajni_broj = randint(1,100)

for brojac_pokusaja in range(5):
    pokusaj = eval(input('Enter your guess (1-100): '))
    if pokusaj < tajni_broj:
        print('VEĆI.', 5-brojac_pokusaja, 'preostalih pokušaja.\n')
    elif pokusaj > tajni_broj:
        print('MANJI.', 5-brojac_pokusaja, 'preostalih pokušaja.\n')
    else:
        print('Pogodili ste!')
        break
else:
    print('Izgubili ste.  Tačan odgovor je', tajni_broj)

Vežbe

9.1 Donji kod štampa brojeve od 1 do 50. Napišite ekvivalentan program koji koristi while petlju.

for i in range(1,51):
    print(i)

9.2 Napišite program koji koristi while petlju da štampa slova iz stringa, jedno slovo u liniji. Modifikujte gornji program tako da štampa svako drugo slovo iz stringa.

9.3 Dobar program proverava da li je korisnik uneo ispravan podatak. Napišite program koji traži od korisnika da unese težinu u kilogramima pa je konvertuje u funte (1 kg = 2.2 funte) . Kad god korisnik unese težinu manju od nule program treba da mu kaže da je težina neispravna i da traži ponovni unos težine. [Koristite while petlju a ne if naredbu]

9.4 Napišite program koji traži od korisnika da unese lozinku (password). Ako unese ispravnu lozinku program mu saopštava da se ulogovao u sistem. U suprotnom program traži da ponovo unese lozinu. Korisnik ima samo pet pokušaja za unos lozinke, a posle toga mu program saopštava da je izbačen iz sistema.

9.5 Napišite program koji omogućava korisniku da unese unapred nepoznat broj rezultata na nekom kolokvijumu. Korisnik signalizira da je završio kada unese negativan broj. Štampajte koliko je bilo desetki (sa brojem poena 90 ili više). Takođe štampajte i prosečan broj poena.

9.6 Modifikujte program za igranje pogađanja broja tako da budu ispravni padeži u porukama. Na primer treba „1 preostali pokušaj“ a ne „1 preostalih pokušaja“.

9.7 Setite se da za dati string s, s.index(‘x’) vraća indeks prvog pojavljivanja slova x u s, ali vraća grešku ako nema slova x u stringu s.

  • Napišite program koji traži od korisnika da unese jedan string i jedno slovo. Korišćenjem while petlje program treba da štampa indeks prvog pojavljivanja unetog slova ili poruku da string ne sadrži to slovo.
  • Napišite isti program korišćenjem for/break petlje.

9.8 Najveći zajednički delioc (NZD) dva data broja je najveći broj kojim su deljiva oba data broja. Na primer NZD(18,42) je 6 zato što je 6 najveći broj sa kojim su deljivi i 18 i 42. Napišite program koji traži od korisnika da unese dva broja i izračunava njihov NZD. Sledi jedan od načina na koji se izračunava NZD, poznat kao Euklidov algoritam.

Prvo, izračunajte ostatak kada se veći od dva broja podeli manjim
Drugo, zamenite veči broj sa manjim brojem, a manji broj sa gore izračunatim ostatkom.
Ponavljajte ovaj proces sve dok manji broj ne postane 0. Najveći zajednički delioc je poslednja vrednost dobijena za veći broj.

9.9 Jedan metod za izračunavanje kvadratnog korena broja 5, koji je star 4000- godina, može se opisati ovako

Počnite sa nekim pokušajem recimo 1. Zatim izračunamo:

(1+5/1)/2=3.

Kao sledeće, uzmemo ovo izračunato 3 i zamenimo sa njim jedinice u predhodnoj formuli. Tada ćemo dobiti:

(3+5/3)/2=7/3 ≈ 2.33.

Zatim zamenimo trojke u prethodnoj formuli sa 7/3. Dobijamo:

(7/3+5/(7/3))/2=47/21 ≈ 2.24.

Ako nastavimo ovaj proces izračunavanja formule i zamene u formuli sa dobijenim rezultatom, dobijaćemo rezultat sve bliži tačnoj vrenosti √5. Ovaj metod funkcioniše i za druge brojeve, a ne samo za 5. Napišite program koji od korisnika traži da unese neki broj, pa pomoću gornjeg metoda izračunajte približnu vrednost kvadratnog korena tog broja sa greškom manjom od 10-10. Približna vrednost je u okviru greške 10-10 kada je apsolutna vrednost razlike dve uzastopno izračunate vrednosti manja od 10-10.

9.10 Napišite program koji ima listu od deset reči, takvih da neke reči imaju ponovljena slova a neke nemaju. Napišite program koji iz takve liste slučajno bira reč koja nema ponovljenih slova.

9.11 Napišite program koji startuje sa 5 × 5 listom nula i slučajno menja tačno 10 od tih nula u jedinice.

9.12 Napišite program u kojem imate listu od sedam brojeva koji mogu biti 0 ili 1. Pronađite prvu nulu u listi i zamenite je sa jedinicom. Ako u listi nema nula štampajte poruku koja to kaže.

9.13 U jednom prethodnom zadatku smo pisali program za igranje igre Kamen-Papir-Makaze protiv kompjutera. U tom programu smo imali 5 rundi igre posle čega smo proglašavali pobednika. Sada želimo da broj rundi ne bude fiksan, već da se pobednik proglasi odmah čim ostvari 3 pobede.

9.14 Napišite program za igranje sledeće igre. Igrač počinje sa sumom od $100. U svakoj rundi igre baca se novčić a igrač pokušava da pogodi ishod bacanja. Igrač dobija $9 ako pogodi a gubi $10 za svaki promašaj. Igra se završava kada igrač ostane bez novca ili kada dostigne $200.

9.15 Napišite program za jgranje sledeće igre. Imamo listu sa nekoliko naziva zemalja iz koje program slučajno bira jednu zemlju. Igrač treba da pogodi sva slova iz naziva zemlje, tako što proba slovo po slovo. Pre svakog novog pokušaja, program štampa naziv zemlje u kojem su prikazana slova koja je igrač do tada pogodio, a crticom (-) prikazuje slova koja još nisu pogođena. Na primer, ako je zemlja Canada a igrač je pogodio slova a, d, i n, program će prikazati -ana-da. Program nastavlja rad sve dok igrač ne pogodi sva slova ili ne pogodi ni jedno.

9.16 Kreirajte 6 × 6 listu koja ima 12 jedinica na slučajno odabranim mestima. Ostali elementi liste su nule.

9.17 Kreirajte slučajnu listu od 9 × 9 elemenata koja sadrži brojeve od 1 do 9 tako da se brojevi ne ponavljaju ni u jednom redu ili koloni.