Materjalid koostas ja kursuse viib läbi
Tartu Ülikooli arvutiteaduse instituudi programmeerimise õpetamise töörühm
< eelmine | 3. nädala sisukord | järgmine > |
3.3 Tsükkel. Mitu korda?
SUUR ARV?
Alustame elulisema näitega, kus tsüklimuutuja suureneb igal sammul ühe võrra, aga algväärtus pole 0
, vaid hoopis 2017
. Oletame, et aastal 2017 on kedagi 1 315 635 (https://www.stat.ee/505933). Iibe kordaja näitab selle arvu muutumist aasta jooksul 1000 inimese kohta (positiivse iibe kordaja korral on arv kasvanud, negatiivse korral langenud).
aasta = 2017 # Ei pea sugugi nullist alustama arv = 1315635 iibe_kordaja = -1.14 # Promillides (muut 1000 kohta) while aasta < 2080: arv = arv + arv * iibe_kordaja / 1000 aasta = aasta + 1 print("Aastal " + str(aasta) + " on meid " + str(round(arv)) + ".")
Proovige ka teiste väärtustega!
Kui aga näiteks tahaks teada, mis aastal oleks eestlasi 2 000 000, kui iibe kordaja oleks 6 promilli (tegelikult pole nii kõrget loomulikku iivet vähemalt viimase saja aasta jooksul Eestis olnud):
aasta = 2017 arv = 1315635 iibe_kordaja = 6 # Promillides while arv < 2000000: arv = arv + arv * iibe_kordaja / 1000 aasta = aasta + 1 print("Aastal " + str(aasta) + " on arv " + str(round(arv)) + ".")
Täpsema prognoosi saamiseks on muidugi vaja arvestada väga erinevaid asjaolusid (huvi korral vt ka https://www.stat.ee/76578).
MITU KORDA?
Eelmistes näidetes oli meil tsükli korduste arv tegelikult juba algul teada või siis kindlatel alustel arvutatav nagu viimases näites. Nüüd aga püüame teha programmi, kus tsükli läbimiste arv sõltub kasutaja sisestatud vastustest. Võtame aluseks valikulause materjali juures olnud programmi, milles küsitakse PIN-koodi. Seal küsiti PIN-koodi üks kord ja lõplik otsus tehti juba ühe pakkumise järel:
print("Sisesta PIN-kood:") sisestatud_pin = input() if sisestatud_pin == "1234": print("Sisenesid pangaautomaati!") else: print("Vale parool! Enesehävitusrežiim aktiveeritud: 3 … 2 … 1 ....")
Tavaliselt siiski antakse ka eksimisvõimalusi ja vale koodi puhul küsitakse uuesti. Püüamegi nüüd selle programmi vastavalt ümber kirjutada. Ilmselt on siin kasu tsüklist. Antud juhul peame tsükliliselt käituma (uuesti küsima) vaid siis, kui sisestatud PIN-kood ei ole õige. Jätkamistingimuseks sobiks seega sisestatud_pin != "1234"
. Programm ise oleks näiteks järgmine:
print("Sisesta PIN-kood:") sisestatud_pin = input() while sisestatud_pin != "1234": print("Sisesta PIN-kood:") sisestatud_pin = input() print("Sisenesid pangaautomaati!")
Püüdke samm-sammult läbi mõelda, kuidas selline programm töötab. Vajadusel joonistage selle plokkskeem. Proovige see programm tööle panna ja testige erinevate PIN-koodidega. Proovige ka oma pangakaardi tegeliku koodiga! :-) Või ärge ikka proovige!
Programmi vaadates näeme, et järgmine lõik on kahes kohas:
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 aga tuleb 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 while
jätkamistingimus on esialgu kindlasti tõene, sest tühi sõne ei ole võrdne sõnega "1234"
.
sisestatud_pin = "" while sisestatud_pin != "1234": print("Sisesta PIN-kood:") sisestatud_pin = input() print("Sisenesid pangaautomaati!")
Nüüd ei pääse ilma parooli sisestamata edasi. Paraku on süsteem ebaturvaline, sest katsetada saab suvaline arv kordi. Püüame ka katsete arvu piirata:
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 ka seda, mitu korda veel vastata saaks. 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 pool kui vasakul pool olev tingimus tõene olema, teisisõnu peavad mõlemad osaavaldised olema tõesed. Tõesti, selleks et PIN-koodi peaks uuesti küsima, ei tohi olla veel õiget sisestatud ja järele jäänud katseid peab olema rohkem kui 0. Nagu eelmise nädala materjalides juttu oli, võib ka siin tingimus olla ükskõik kui keeruline. Tehetega and
, or
ja not
saab väga erinevaid avaldisi tekitada.
Kui eelnevas näites midagi segaseks jäi, siis saab vaadata kokkuvõtvat videot programmi koostamise kohta:
Ülesanne
Mure on nüüd selles, et küsimiste arv on küll piiratud, aga isegi kui valet koodi kolm korda sisestatakse, saadakse ikka pangaautomaati sisse. Muudame programmi nii, et arvestataks, kas lõpuks sisestati õige kood või mitte. Kui ei sisestatud, siis on kuri karjas ja lahkumiseks antakse 10 sekundit! :-) Programmi saab üheks sekundiks "uinutada" käsuga sleep(1)
, kuid selle kasutamiseks tuleb see importida moodulist time
nii: from time import sleep
.
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("Enesehävitusrežiim aktiveeritud:") i = 10 while i > 0: print(i) i -= 1 sleep(1)
Huvi korral mõtisklege ja katsetage, mida teeks programm teisiti, kui
if sisestatud_pin == "1234":
asemel oleks
if katseid > 0:
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. Vabalt võib olla ka näiteks while
-tsükkel, mille sees on tingimuslause, mille sees on veel üks tsükkel, aga sellise programmi käitumise ette ennustamine võib muutuda keeruliseks, seega tuleks võimaluse korral keerulisemast struktuurist hoiduda.
Klassikalises arvamismängus on aga kasu tingimuslausest tsükli sees:
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!")
Proovige mängida, aga ärge sellest sõltuvusse sattuge! Proovige mängu modifitseerida. Näiteks las programm loeb vastamiste arvu ka ja reageerib vastavalt sellele. (Kui arvatakse arv esimese korraga ära, siis näiteks võiks mängijal soovitada oma selgeltnägija võimeid ehk laiemaltki kasutada.) Huvitav oleks ka teistpidi mäng, kus arvuti oleks arvaja rollis ja arvaks võimalikult mõistliku strateegiaga.
Ülesanne
Mõelda oma elule ja ümbritsevale ning kirjeldada ühte tsüklilist protsessi. Seejuures märkida, kas tsükli läbimiste arv on enne teada või selgub täitmise ajal. Protsess ei pea olema (lihtsasti) programmeeritav. Lahendus esitada Moodle'is vastava testiküsimuse vastusena.
< eelmine | 3. nädala sisukord | järgmine > |