6. Kontrola toka

Aaa, kontrola toka. Ovdje „sve dolazi na svoje“. Iako je ovo poglavlje nešto kraće i lakše od prethodnog, poglavlja o metodama, vidjet ćemo da će otvoriti čitav svijet mogućnosti u programiranju. Nakon ovog poglavlja, bićete zaista u stanju napisati interaktivan program; programi koje smo pisali prije ovog poglavlja „govorili“ različite stvari na osnovu onoga što smo unijeli putem tastature/tipkovnice, ali nakon ovog poglavlja ćete biti u stanju napisati i one programe koji će „uraditi“ različite stvari. No, prije nego dođemo do toga, moraćemo naučiti da pravimo razliku među objektima u našim programima. Trebaće nam...

Metode poređenja

Hajde da „protutnjimo“ kroz ovaj podnaslov, kako bi smo mogli što prije preći na „Grananje“, podnaslov gdje ćemo naći sve ono što je zanimljivo. Dakle, da bi utvrdili da li jedan objekat veći ili manji od drugog, koristimo metode [>] i [<], kao u slijedećem primjeru:

puts 1 > 2

puts 1 < 2

Ispis:

false

true

Kako vidite, tu nije bilo nikakvih problema. Slično prethodnom primjeru, saznaćemo da li je neki objekat veći ili jednak, odnosno manji ili jednak drugom koristeći metode [>=] i [<=]

puts 5 >= 5

puts 5 <= 4

Ispis:

true

false

Konačno, želimo li saznati da li su dva objekta jednaka ili ne, koristeći metode [==] (što znači „jesu li ovi objekti jednaki?”) i [!=] (što znači „jesu li ovi objekti različiti?”). Da ne bi došlo do zabune, važno je napomenuti da metoda [=] služi za dodijeljivanje vrijednosti varijabli, a metoda [==] za prethodno navedenu svrhu. Ove dvije metode se ne smiju izjednačiti.

puts 1 == 1

puts 2 != 1

Ispis:

true

true

Moguće je, naravno, uporediti i string objekte (tekst). Kriterij za poređenje znakova je njihov leksikografski red, što praktično znači njihov red u riječniku – u abecedi. Imenica (u engleskom jeziku) 'cat' dolazi prije imenice 'dog' i u riječniku, pa tako će biti i u ovom primjeru:

puts 'cat' < 'dog'

Ispis:

true

Postoji jedna mala caka: način na koji računari obično funkcionišu jer da poredaju prvo velika slova, pa tek onda mala. (Tako se redaju znakovi i u fontovima [font fajlovima]: prvo dolaze sva velika slova, a onda mala.) To bi značilo da riječ 'Zoo' dolazi prije 'ant', pa ako želite upitati koja riječ dođe prije u riječniku, pobrinite se da koristite ili samo mala, ili samo velika slova u riječi,...ili da ih „provučete“ kroz metodu -capitalize- [k.p.: sjećate li se metoda koje se bave kapitalizacijom?].

Poslijednja napomena prije nego pređemo na „Grananje“: Rezultati koje nam daju metode poređenja 'true' [tačno] i 'false' [netačno] nisu string tip objekta, nisu obični tekst,...to su specijalni objekti true i false. [k.p.: logički tip podatka, nazvan još i Boolean.] (Naravno, ako bi smo upotrijebili true.to_s, onda bi rezultat bio 'istinski' istinit, jer bi nam -puts- dao string kao rezultat. 'true' i 'false' redovno se pojavljuju u svim programima kod kojih nailazimo na...

Grananje

Grananje je jako jednostavan, ali jako moćan koncept u programiranju. Ustvari, tako je jednostavan da se kladim da ga uopšte ne moram posebno objašnjavati; jednostavno ću vam pokazati na primjeru:

puts 'Hello, what\'s your name?'

name = gets.chomp

puts 'Hello, ' + name + '.'

if name == 'Chris'

puts 'What a lovely name!'

end

Ispis:

Hello, what's your name?

Chris

Hello, Chris.

What a lovely name!

Ali, ako upišemo neko drugo ime…

Ispis:

Hello, what's your name?

Chewbacca

Hello, Chewbacca.

To bi bilo grananje. Ako je tačno [true] ono što dolazi poslije uslova [if], onda će biti izvršen kod između [if] i [end], a ako poslije uslova odgovor bude netačan [false] onda taj dio koda neće biti izvršen. Jednostavno.

Uvrstio sam kod između [if] i [end] jer sam mislio da će tako biti lakše pratiti grananje. Skoro svi programeri to rade, bez obzira koji programski jezik koriste. Možda vam se sada čini da to i nije od velike pomoći, međutim, kad se stvari zakomplikuju, vidjet ćete kako je velika razlika.

Često se desi da bismo željeli da program učini jedno, ako je uslov zadovoljen [true] ili drugo ako nije [false]. Za tu svrhu imamo [else]:

puts 'I am a fortune-teller. Tell me your name:'

name = gets.chomp

if name == 'Chris'

puts 'I see great things in your future.'

else

puts 'Your future is... Oh my! Look at the time!'

puts 'I really have to go, sorry!'

end

Ispis:

I am a fortune-teller. Tell me your name:

Chris

I see great things in your future.

Ako pokušamo s drukčijim imenom...

Ispis:

I am a fortune-teller. Tell me your name:

Ringo

Your future is... Oh my! Look at the time!

I really have to go, sorry!

Grananje je neka vrsta odabira puta u kodu: dali da krenemo putanjom onih kod kojih je name == 'Chris', ili da odaberemo neku drugu putanju [else].

Baš kao što postoje grančice da grani jednog drveta, tako i grane u programiranju imaju grane koje se nalaze unutar njih samih:

puts 'Hello, and welcome to 7th grade English.'

puts 'My name is Mrs. Gabbard. And your name is...?'

name = gets.chomp

if name == name.capitalize

puts 'Please take a seat, ' + name + '.'

else

puts name + '? You mean ' + name.capitalize + ', right?'

puts 'Don\'t you even know how to spell your name??'

reply = gets.chomp

if reply.downcase == 'yes'

puts 'Hmmph! Well, sit down!'

else

puts 'GET OUT!!!'

end

end

Ispis:

Hello, and welcome to 7th grade English.

My name is Mrs. Gabbard. And your name is...?

chris

chris? You mean Chris, right?

Don't you even know how to spell your name??

yes

Hmmph! Well, sit down!

Dobro, ako ispravim ono u čemu sam pogriješio...

Ispis:

Hello, and welcome to 7th grade English.

My name is Mrs. Gabbard. And your name is...?

Chris

Please take a seat, Chris.

Ponekad će možda biti teško razaznati na koje mjesto postaviti sve te if, else, end. Ja sebi olakšam tako što odmah napišem [if], a ispod njega [end]. Dakle kad sam pisao pređašnji program, isprva je izgledao ovako:

puts 'Hello, and welcome to 7th grade English.'

puts 'My name is Mrs. Gabbard. And your name is...?'

name = gets.chomp

if name == name.capitalize

else

end

Nakon toga sam dodao komentare, dijelove koda u programu koje će računar ignorisati prilikom izvršavanja programa:

puts 'Hello, and welcome to 7th grade English.'

puts 'My name is Mrs. Gabbard. And your name is...?'

name = gets.chomp

if name == name.capitalize

# Gospođa je u ovom slučaju pristojna.

else

# ...a u ovom izgubi živce.

end

Sve što dođe poslije znaka # smatra se komentarom (osim, naravno, ako taj znak ne pišete unutar stringa). Nakon toga sam komentare zamijenio pravim kodom. Neki vole ostaviti komentare, ali ja, kako napredujem u Ruby, sve manje ih koristim. Da budem iskren, smatram da većinom odvlače pažnju od pravog koda. Stvar je ličnog izbora, hoćete li koristiti komantare,...sami ćete pronaći svoj stil. Onda, moj slijedeći korak u pisanju ovog koda bio je:

puts 'Hello, and welcome to 7th grade English.'

puts 'My name is Mrs. Gabbard. And your name is...?'

name = gets.chomp

if name == name.capitalize

puts 'Please take a seat, ' + name + '.'

else

puts name + '? You mean ' + name.capitalize + ', right?'

puts 'Don\'t you even know how to spell your name??'

reply = gets.chomp

if reply.downcase == 'yes'

else

end

end

Nanovo sam napisao [if], [else] i [end] odmah, u isto vrijeme. To mi stvarno pomaže da se bolje snalazim u kodu, jer se mogu fokusirati na manje dijelove koda ispunjavajući dio koji se nalazi između [if] i [end]. Druga pogodnost ovog pristupa je što računar može razumjeti program u svakoj njegovoj fazi. Svaku od verzija programa, iako nedovršenu, računar će moći da izvrši – neće biti grješaka. Dakle, još uvijek nedovršeni, ali programi koji ipak funkcionišu. Na taj način sam mogao ujedno i testirati program, dok ga pišem, što mi je pomoglo da izađem na kraj sa stvarima na koja je još trebalo poraditi. Kad je testiranje bilo završeno, onda sam znao da je posao dobro odrađen.

Slijedi nekoliko caka koje će vam pomoći s grananjem, ali i nekim drugim tipovima kontrole toka:

Kruženje

Često će biti potrebno narediti računaru da ponovi neki postupak nekoliko puta, što je nešto u čemu bi računari trebali da su stvari dobri.

Kad kažete računaru da ponavlja nešto, morate se pobrinuti i da mu kažete kad da stane. Njima nikad ne dosadi da to rade, tako da, ako im ne kažete da stanu, oni neće prestati. Da bismo se pobrinuli da se ovo ne desi, naređujemo računaru da ponavalja određenu metodu sve dok se ispunjava određeni uslov, dok je on [true] ili jednak zadanoj vrijednosti. Ovako bi to otprilike izgledalo:

command = ''

while command != 'bye'

puts command

command = gets.chomp

end

puts 'Come again soon!'

Ispis:

Hello?

Hello?

Hi!

Hi!

Very nice to meet you.

Very nice to meet you.

Oh... how sweet!

Oh... how sweet!

bye

Come again soon!

To bi, dakle, bilo kruženje. (Vjerovatno ste primjetili prazan string na početku ispisa; rezultat je to koji daje prvi –puts-, prije prvog -gets-. Kako biste preuredili kod, pa da se riješimo prve linije. Pokušajte! Nije li rezultat bio isti kao i kod originalnog programa (iznad), samo što nije sadržavao prazne linije u ispisu?)

Kružne petlje, siguran sam da i sami možete zamisliti, dozvoliće da se uradi dosta zanimljivih stvari. Međutim, mogu prouzrokovati dosta problema, napravite li grješku u kodu. Šta ako se desi da grješka u kodu uzrokuje beskonačno ponavljanje? Ako mislite da se ovo desilo, pokušajte kombinaciju tipki CTRL + C.

Prije nego se nastavimo igrati sa kružnim petljama, hajde da naučimo par stvarčica koje će nam olakšati posao.

Malo logike...

Hajde da pogledamo prvi program u “Grananju” ponovo. Šta da je moja žena došla kući, vudjela program, isprobala ga i nije joj rekao kako divno ime ima? Ja baš i ne bih htio povrijediti njena osjećanja (ili spavati tu noć na kauču), pa sam kod ispravio na slijedeće:

puts 'Hello, what\'s your name?'

name = gets.chomp

puts 'Hello, ' + name + '.'

if name == 'Chris'

puts 'What a lovely name!'

else

if name == 'Katy'

puts 'What a lovely name!'

end

end

Ispis:

Hello, what's your name?

Katy

Hello, Katy.

What a lovely name!

Izgleda da radi, bez problema,…ali nije baš najljepši program. Zašto ne? Pa, najveće pravilo koje sam naučio u programiranju je NP pravilo: Nemoj ponavljati. Vjerovatno bi se dala knjiga napisati o tome zašto je to jako dobro pravilo. U našem slučaju, linija puts 'What a lovely name!' je ona koja se ponavalja. Zašto je to tako strašno? Šta das sam napravio grješku u pisanju, kad sam ponovo pisao istu liniju koda? Šta ako sam želio ‘lovely’ prepraviti u neki drugi atribut, u oba primjera/linije? Sjećate li se da sam rekao da sam lijen? U suštini, htio sam da program kaže kako su imena lijepa samo kad putem metode –get- dobije unos 'Chris' i 'Katy'...ukratko, samo u slučaju da dobije jedno od ta dva imena, trebalo bi uraditi istu stvar:

puts 'Hello, what\'s your name?'

name = gets.chomp

puts 'Hello, ' + name + '.'

if (name == 'Chris' or name == 'Katy')

puts 'What a lovely name!'

end

Ispis:

Hello, what's your name?

Katy

Hello, Katy.

What a lovely name!

Tako je već mnogo bolje. Da bih ostvario ono što sam naveo, koristio sam logički operator [or] (ili). Ostali logički operatori koje ćemo koristiti su [and] (i) i [not] (ne). Uvijek je dobar potez koristiti zagrade kada radimo sa ovim operatorima. Pogledajmo kako oni rade:

iAmChris = true

iAmPurple = false

iLikeFood = true

iEatRocks = false

puts (iAmChris and iLikeFood)

puts (iLikeFood and iEatRocks)

puts (iAmPurple and iLikeFood)

puts (iAmPurple and iEatRocks)

puts

puts (iAmChris or iLikeFood)

puts (iLikeFood or iEatRocks)

puts (iAmPurple or iLikeFood)

puts (iAmPurple or iEatRocks)

puts

puts (not iAmPurple)

puts (not iAmChris )

Ispis:

true

false

false

false

true

true

true

false

true

false

Samo jedan od ovih primjera bi vas mogao malo zbuniti. U govoru, dok s nekim pričamo, koristeći „ili“ želimo reći da od dvije opcije biramo samo jednu, ali ne oboje. Naprimjer, majka vas može upitati šta želite za dezert, pitu ili kolač. Time nije rekla da možete dobiti oboje! Računar, s druge strane, koristi „ili“ [or] kao logički operator koji znači da ili jedna ili druga vrijednost može odgovarati uslovu, pa da se on ispuni. (Još jedan način da se kaže „ako je makar jedan od ovih uslova tačan [true].“) Zato računari i jesu zanimljiviji od majki.

Par stvarčica za oprobati

    • 99 bottles of beer on the wall...“ Napišite program koji će ispisati tekst ove stare, dobre pjesme.
    • Napišite program pod imenom „Gluha baba“. Šta god da joj kažete (otipkate), ona će odgovoriti sa velikim HA?! MALO GLASNIJE!, osim ako joj tekst unesete velikim slovima. Ukoliko vičete, onda će vas i čuti (ili bar tako ona misli) i odgovoriti vam NISAM! NISAM, SINKO JOŠ OD 1938! Da bi vaš program bio zaista uvjerljiv, neka umjesto „sinko“ svaki put izgovori neko drugo ime; a možda da tome i dodate da umjesto 1938 navede neku slučajno generisanu godinu (random) između 1938 i 1950 (Ovaj dio je opcionalan, a biće dobro da pročitate poglavlje o metodama, da se malo podsjetite o generisanju slučajnih brojeva u Ruby). Na kraju, nećete se moći otarasiti babe, dok joj ne kažete ĆAO, BABA!

Caka #1: nemojte zaboraviti metodu –chomp-, jer „ĆAO, BABA!“ sa Enterom i bez njega, nije isto!

Caka #2: pokušajte otkriti koji dio programa se treba ponavljati; taj dio bi trebao biti uvršen u kružnu petlju koja počinje sa [while].

    • Proširite svoj program „Gluha baba“: Šta ako baba ne želi da idete? Kad joj viknete ĆAO, BABA!, ona će se praviti da vas ne čuje. Promijenite pređašnji program tako da joj tri puta morate reći ĆAO, BABA! zaredom. Pobrinite se da dobro da testirate vaš program: ukoliko joj ne kažete ĆAO, BABA! tri puta zaredom, ona će i dalje htjeti da razgovara s vama.
    • „Protekle prijestupne godine“. Napišite program koji će pitati početnu i krajnju godinu, te na osnovu toga izračunati koliko prijestupnih godina ima između tog roka, uključujući i njih same. Prijestupne su godine dijeljive sa 4 (kao 1984 ili 2004). Međutim, godine dijeljive sa 100 nisu prijestupne osim ako su u isto vrijeme dijeljive i sa 400 (kao 1600 i 2000, koje su bile prijestupne). (Da, prilično je zapetljano.)

Kad završite s programima, napravite malu pauzu! Stvarno smo već dosta toga naučili. Čestitke! Jeste li iznenađeni koliko postoji stvari koje možete narediti računaru da uradi? Par poglavlja dalje i bićete u stanju programirati sve što poželite. Ozbiljno! Pogledajte samo koliko stvari možete sad kad ste naučili grananje i kruženje, a ranije bez toga niste mogli.

Na redu su nam nove vrste objekata, oni koje bilježe liste nekih drugih objekata: Nizovi.

-----------------------------------------------

© 2003-2009 Chris Pine

http://pine.fm/LearnToProgram/