17 Tsüklite rakendamine

Selles peatükis näeme, kuidas saab tsükleid kasutada erinevate eesmärkide täitmiseks. Loome tsüklite abil programmid rahvastiku muutumise ennustamiseks, pangaautomaadi ligipääsu lubamiseks ning arvude äraarvamise mängu.

SUUR ARV

Alustame elulise näitega, kus tsüklimuutuja suureneb igal sammul ühe võrra, aga algväärtus pole 0, vaid hoopis 2017. Oletame, et aastal 2017 on Eesti riigi elanike arv 1 315 635 (link). Iibe kordaja näitab selle arvu muutumist aasta jooksul 1000 inimese kohta (positiivse iibe korral on kordaja positiivne, negatiivse korral negatiivne). 2017. aastal võiks see olla -1.33 (link). Leiame, mis oleks riigi elanike arv aastal 2080, kui iibe kordaja ei muutuks:

Näiteprogramm. Elanike arv I

aasta = 2017                             # loendamist ei pea nullist alustama
arv = 1315635
iibe_kordaja = -1.33                     # Promillides (arvukuse muutus 1000 elaniku kohta)
while aasta < 2080:
   arv = arv + arv * iibe_kordaja / 1000 # Arvutame selle aasta uue arvu
   aasta = aasta + 1                     # Läheme järgmise aasta juurde
print("Aastal " + str(aasta) + " on elanikke " + str(round(arv)) + ".")

Kui me tahaks teada, mis aastal oleks elanikke 2 000 000, kui iibe kordaja oleks 6 promilli:

Näiteprogramm. Elanike arv II

aasta = 2017
arv = 1315635
iibe_kordaja = 6
while arv < 2000000:
   arv = arv + arv * iibe_kordaja / 1000
   aasta = aasta + 1
print("Aastal " + str(aasta) + " on elanike arv " + str(round(arv)) + ".")

Täpsema prognoosi saamiseks oleks vaja arvestada paljusid erinevaid asjaolusid. Huvi korral uuri statistikaameti prognoosi 2040. aasta kohta.

MITU KORDA?

Eelnevates näidetes oli tsükli korduste arv põhimõtteliselt algusest peale teada. Nüüd teeme programmi, kus tsükli läbimiste arv sõltub kasutaja sisestatud vastustest. Alustame valikulause materjalides vaadeldud programmist, milles küsitakse PIN-koodi. Seal küsiti PIN-koodi üks kord ja lõplik otsus tehti ühe pakkumise järel:

Näiteprogramm. Pangaautomaat I

print("Sisesta PIN-kood:")
sisestatud_pin = input()
if sisestatud_pin == "1234":
   print("Sisenesid pangaautomaati!")
else:
   print("Vale parool! Ligipääs keelatud!")

Tavaliselt lubatakse PIN-koodi mõned korrad uuesti proovida, kui õiget koodi ei sisestatud. Ilmselt on siin kasu tsüklist. Antud juhul peame tsükliliselt käituma (koodi uuesti küsima) vaid siis, kui sisestatud PIN-kood ei ole õige. Jätkamistingimuseks sobiks seega sisestatud_pin != "1234". Programm oleks järgmine:

Näiteprogramm. Pangaautomaat II

print("Sisesta PIN-kood:")
sisestatud_pin = input()
while sisestatud_pin != "1234":
   print("Sisesta PIN-kood:")
   sisestatud_pin = input()
print("Sisenesid pangaautomaati!")

Mõtle läbi, kuidas see programm samm-sammult töötab. Vajadusel joonista selle plokkskeem. Proovi programmi erinevate PIN-koodidega.

Muutujate olemasolu tsüklis

Programmi vaadates näeme, et järgmine lõik on kahes kohas (nii tsükli ees kui sees):

print("Sisesta PIN-kood:")
sisestatud_pin = input()

Võime proovida tsükli eest selle lõigu ära jätta:

while sisestatud_pin != "1234":
   print("Sisesta PIN-kood:")
   sisestatud_pin = input()
print("Sisenesid pangaautomaati!")

Sellisel juhul ilmub veateade, sest muutujal sisestatud_pin ei ole väärtust, kui seda while-tingimuses esimest korda kontrollida tahetakse:

Traceback (most recent call last):
  File "C:/Python33/pin.py", line 1, in <module>
    while sisestatud_pin != "1234":
NameError: name 'sisestatud_pin' is not defined

Anname muutujale sisestatud_pin esialgseks väärtuseks tühja sõne. Sellega garanteerime, et muutujal sisestatud_pin on alati väärtus ja tsükli jätkamistingimus on esialgu kindlasti tõene, sest tühi sõne ei ole võrdne sõnega “1234”. Programmi plokkskeem on kujutatud joonisel 1.

Näiteprogramm. Pangaautomaat III

sisestatud_pin = ""
while sisestatud_pin != "1234":
   print("Sisesta PIN-kood:")
   sisestatud_pin = input()
print("Sisenesid pangaautomaati!")
Joonis 1. Programmi “Pangaautomaat III” plokkskeem

Nüüd ei pääse ilma parooli sisestamata edasi. Paraku on süsteem ebaturvaline, sest katsetada saab suvaline arv kordi. Püüame katsete arvu piirata:

Näiteprogramm. Pangaautomaat IV

sisestatud_pin = ""
katseid = 3
while sisestatud_pin != "1234" and katseid > 0:
   print("Sisesta PIN-kood:")
   print("Jäänud on " + str(katseid) + " katset.")
   katseid -= 1
   sisestatud_pin = input()
print("Sisenesid pangaautomaati!")

Nüüd koosneb jätkamistingimus kahest osast – endiselt kontrollitakse, ega sisestatud PIN-kood õige ei ole, aga lisaks kontrollitakse seda, mitu korda veel vastata tohib. Enne tsüklit on kordade arvuks määratud 3 ja pärast igat tsükli keha täitmist väheneb see arv 1 võrra. Esimesel korral saab muutuja katseid väärtuseks 2, teisel korral 1 ja kolmandal korral 0.

Jätkamistingimuses kasutatakse võtmesõna and, mis tähendab, et tingimuse kehtimiseks peab nii selles sõnast paremal kui vasakul pool olevad tingimused tõesed olema, teisisõnu peavad mõlemad osaavaldised olema tõesed. Meie koodis küsitakse PIN-koodi ainult siis, kui õiget koodi pole sisestatud ja järele jäänud katseid on rohkem kui 0. Nagu eelmise nädala materjalides mainiti, võib ka siin tingimus olla ükskõik kui keeruline. Tehetega andor ja not saab moodustada väga erinevaid avaldisi.

Kokkuvõttev video programmi koostamisest: link

Enesekontroll (1 küsimus)

Täiendatud pangaautomaat

Meie programm ei toimi veel nii, nagu me tahaks. Mure on selles, et küsimiste arv on küll piiratud, aga isegi kui vale kood kolm korda sisestatakse, lubab programm kasutaja pangaautomaati sisse. Muudame programmi nii, et arvestataks, kas lõpuks sisestati õige kood või mitte. Kui ei sisestatud, siis ähvardame kasutajat turvatöötajaga, keda lubame kutsuda 10 sekundi pärast. Programmi saab üheks sekundiks “uinutada” käsuga sleep(1), kuid selle kasutamiseks tuleb see importida moodulist time käsuga from time import sleep.

Näiteprogramm. Pangaautomaat V

from time import sleep
sisestatud_pin = ""
katseid = 3
while sisestatud_pin != "1234" and katseid > 0:
   print("Sisesta PIN-kood:")
   print("Jäänud on " + str(katseid) + " katset.")
   katseid -= 1
   sisestatud_pin = input()
if sisestatud_pin == "1234":
   print("Sisenesid pangaautomaati!")
else:
   print("Katsete arv ületatud! Turvatöötaja kutsutakse 10 sekundi pärast!")
   i = 10
   while i > 0:
      print(i)
      i -= 1
      sleep(1)
   print("Turvatöötaja kutsutud!")

Huvi korral katseta, mida teeb programm teisiti, kui

if sisestatud_pin == "1234":

asemel oleks

if katseid > 0:

Mitmetasandiline taane

Eelmises programmis oli viimane tsükkel valikulause else-osa sees. Näeme, et taane on vastavalt läinud veel kaugemale. Selline mitmetasemeline struktuur on programmides täiesti tavaline. näiteks võib esineda while-tsükkel, mille sees on tingimuslause, mille sees on veel üks tsükkel. Kuna mitmetasandiliste programmide käitumise ette ennustamine võib muutuda keeruliseks, siis tuleks võimaluse korral hoida struktuur võimalikult lihtne.

Arvamismäng

Klassikalises arvamismängus on kasu tingimuslausest tsükli sees:

Näiteprogramm. Arvamismäng

from random import randint

arv = randint(1,19) # Juhuslik täisarv
print("Mõtlen ühele 20-st väiksemale naturaalarvule. Arva ära!")
arvamus = int(input())

while arvamus != arv:
   if arv > arvamus:
      print("Minu arv on suurem!")
   else:
      print("Minu arv on väiksem!")

   print("Arva veel!")
   arvamus = int(input())

print("Õige! Tubli!")

Proovi mängu modifitseerida. Näiteks pane programm loendama sooritatud arvamiste arvu ja sellele reageerima. Kui arv arvatakse esimese korraga ära, siis võib mängijal soovitada oma selgeltnägija-võimeid laiemaltki kasutada.

Palun kommenteeri seda materjali Google’i küsimustikus.

Litsents

Icon for the Creative Commons Attribution 4.0 International License

Programmeerimine on loodud Eno Tõnisson, Tauno Palts, Merilin Säde, Kaarel Tõnisson jt poolt Creative Commons Attribution 4.0 International License litsentsi alusel, kui pole teisiti märgitud.

Jaga seda raamatut