2. Tingimuslause

Informaatika õppelehekülg

Tutvustan üht kõige fundamentaalsemat programmeerimise konstruktsiooni – tingimuslauset. Veel vaadeldakse ka juhuslike arve ja kilpkonnagraafikat.

SISSEJUHATUS

Eelmisel nädalal vaatasime algoritme, kus mitmes kohas olenes järgmine samm teatud tingimuse täidetusest. Näiteks õnnetuse puhul: “Kui kannatanu ei hinga, tee kunstlikku hingamist.” Sellisel juhul on kirjeldatud tegevus selliseks juhuks, kui tingimus on täidetud ja kui pole täidetud, siis jäetakse see samm lihtsalt vahele. Siinkohal on veel huvitav see, et tingimus on eituse kaudu esitatud – “kannatanu ei hinga”.

Tihti aga on tegevused nii selleks juhuks, kui tingimus on täidetud, kui ka selleks, kui tingimus pole täidetud.

Programmides realiseeritakse selliseid valikuid tingimuslausete (ehk valikulausete ehk if-lausete) abil.

SÕNEDE VÕRDLEMINE TINGIMUSES

Tahame näiteks teha programmi, mis küsib kasutajalt sisenemiseks PIN-koodi ja kontrollib selle õigsust. Programm võiks

  • õige parooli sisestamisel öelda: “Sisenesid pangaautomaati!”
  • vale parooli sisestamisel aga hoopis: “Vale parool! Enesehävitusrežiim aktiveeritud: 3 … 2 … 1 ….”.

Programmi alguses tuleb kasutajalt PIN-kood küsida, seda saab teha järgmise lausega:

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

Kui kasutada programmeerimiskeskkonda Thonny, siis ootab input kasutaja sisestust alumisel paneelil (Shell).

Nüüd on vaja kontrollida, kas parool on õige või ei ole. Selleks saab kasutada tingimuslauset:

if sisestatud_pin == "1234":
print("Sisenesid pangaautomaati!")

Mis see tingimuslause (ka valikulause või if-lause) siis on? Tingimuslauses on kesksel kohal tingimus, mille alusel otsustatakse, kuidas programm edasi töötab. Tingimus on esitatud tõeväärtuse tüüpi avaldisena, mille väärtus on tõene (True) või väär (False) – tingimus on täidetud või ei ole täidetud. Kõige sagedamini on tingimus esitatud teatud võrdlemisena. Võrrelda võib näiteks muutuja väärtust ja sõne nagu eelnevas näites. Oluline on tähele panna, et muutuja väärtus on samuti sõnetüüpi. Topeltvõrdusmärgiga (==) avaldis on väärtusega True, kui mõlemad pooled on võrdsed ja väärtusega False, kui ei ole võrdsed.

Võrrelda saab ka näiteks muutuja väärtust ja arvu. Näiteks avaldis a >= 1 on tõene, kui a on suurem kui üks või ühega võrdne. Samuti võib võrrelda omavahel kahe muutuja väärtust. Tegelikult võib tingimusena olla kirjas ka lihtsalt True (või False), aga siis ei toimu tegelikult mingit valikut. Avaldis 5 == 4 on ka näiteks alati väär. Tingimuslausel on sisuline mõte siis, kui tingimusavaldis võib omandada erinevaid tõeväärtusi.

Kindlasti ei tohi unustada koolonit (:if-rea lõpust. Paneme tähele, et print on taandatud võrreldes eelmise reaga paremale. Seda saab teha kas vajutades TAB-klahvi või 4 korda tühikut. Selliselt tuleb käituda, et print käsk käiks ikkagi if-osa juurde ja sellist tegevust nimetatakse treppimiseks. Head programmeerimiskeskkonnad (näiteks Thonny) toetavad treppimist sellega, et pärast eelmise rea koolonit viivad kursori juba sobivalt taandesse.

Ülaltoodud programm juba kuidagi töötab, aga mitte siis, kui parool on vale. Tingimuslausel võib olla else-osa, millega määratakse, mis juhtub siis, kui tingimus ei ole täidetud (vastava avaldise väärtus on False).

Hetkel lisame järgmise lõigu:

else:
print("Vale parool! Enesehävitusrežiim aktiveeritud: 3 ... 2 ... 1 ....")

Kokku sai siis selline kood:

sisestatud_pin = input("Sisesta PIN-kood: ")
if sisestatud_pin == "1234":
print("Sisenesid pangaautomaati!")
else:
print("Vale parool! Enesehävitusrežiim aktiveeritud: 3 ... 2 ... 1 ....")

Antud programmi plokkskeem näeb välja selline:

Sellist ühes või teises suunas otsuste tegemist ja liikumist vastavalt tingimuse kontrollile nimetatakse programmeerimises ka hargnemiseks. Programm otsustab, millist haru pidi edasi minna. Kui tingimus on täidetud, siis minnakse edasi ühte haru pidi, kui ei ole, siis teist haru pidi. Rõhutada tuleb, et tingimuslauses on harusid alati kaks, isegi kui else-osa “näha” pole. Kui else puudub, siis ei tehta väära tingimusavaldise korral mitte midagi, sama hästi võiks else-osa kirjutada ja tühjaks jätta.

Kui eelnevas programmis else-osa poleks, siis plokkskeem oleks selline:

NB! Sõnede võrdlemisel loetakse suurtähed ja väiketähed erinevateks. Näiteks "A" ja "a" ei ole võrdsed. Mõnede ülesannete puhul me tahame nad siiski võrdseks lugeda. Näiteks saab sisendi puhul kõik tähed väikeseks teisendada nii:

sisestatud_väike = input().lower()

Analoogiliselt saab kõik tähed suureks teisendada:

sisestatud_suur = input().upper()

-ARVUDE VÕRDLEMINE

Eelmises näites kontrollisime koodi võrdsust sõnega "1234". Oluline on siinkohal just see, et jutumärgid teevad sellest muidu arvuna näivast asjast sõne. Loomulik on aga paljusid asju käsitleda ka arvuna.

Tingimusi saab (muuhulgas) moodustada järgmiste märkidega:

  • <><=>= võrratuste kehtivuse kontrollimiseks;
  • == võrdsuse kontrollimiseks;
  • != mittevõrdsuse kontrollimiseks.

Kasutame nüüd arvude võrdlemisel võrratust. Teeme programmi, mis küsib kasutajalt vanust ja kui ta on noorem kui 14, siis öeldakse, et ta on selle mängu mängimiseks liiga noor. Täisarvu sisestamiseks peame sisendiks saadud sõne täisarvuks teisendama. Seda saab teha funktsiooniga int. Näiteks: arv = int(input()).

vanus = int(input()) 
print(“Kui vana oled?”)
if vanus < 14:
print("Oled natukene noor edasipääsuks.")
else:
print("Sisenesid võlumaailma.")

Ülesandeid huvilisematele

Siin on nüüd mõned ülesanded, mille võivad need, kes end ebakindlamalt tunnevad, vahele jätta. Kuid soovitame soojalt siiski proovida!

  • Kirjutada PIN-koodi küsimise programm nii ümber, et sisestatud koodi võrreldakse arvuga 1234 (just arvuga, mitte sõnega). Programm võiks ka öelda, kas sisestatud vale kood oli “liiga suur” või “liiga väike”.
  • Katsetada, kas ka sõnesid saab võrrelda märkide <<=>= ja > abil. Kuidas tulemust kommenteerida?

2.2 TINGIMUSLAUSE TINGIMUSLAUSE SEES

Valikulausete puhul on kesksel kohal tingimus, mille kehtimisest sõltub, millise haruga edasi minnakse. Tingimus esitatakse tõeväärtustüüpi avaldisena, näiteks sisestatud_pin == "1234". Avaldis võib olla ka märksa keerulisem. Mõningaid selliseid vaatame käesoleva nädala järgmistes materjalides.

Praegu aga jätkame varasemat programmi, kus küsitakse PIN-koodi ja õige koodi korral “sisenetakse” pangaautomaati. Mis aga saab edasi? Tundub, et programm peab edasi ka valikutega minema. Teeme nüüd nii, et pangaautomaati sisenedes näidatakse, mitu eurot pangakontol on, ning küsitakse, mitu eurot soovitakse välja võtta. Kui kasutaja soovib välja võtta rohkem raha, kui on pangakontol, siis teavitatakse kasutajat, et see pole võimalik.

Eelnevalt oli meil olemas pangaautomaati sisenemise programm:

sisestatud_pin = input("Sisesta PIN-kood: ")
if sisestatud_pin == "1234":
print("Sisenesid pangaautomaati!")
else:
print("Vale parool! Enesehävitusrežiim aktiveeritud: 3 ... 2 ... 1 ....")

Esiteks võiks programmi alguses kasutusele võtta muutuja, mille väärtus näitab, kui palju pangakontol raha on. Näiteks teeme nii, et algselt on kasutaja pangakontol 100 eurot:

kontoseis = 100

Nüüd teeme programmiosa, mis töötab siis, kui kasutaja on automaati sisse saanud. Selles osas väljastatakse ekraanile pangakontol olev summa ning küsitakse, mitu eurot soovitakse välja võtta. Küsitud väljavõetava raha teisendame seekord koheselt täisarvutüüpi (int) väärtuseks:

print("Sisenesid pangaautomaati! Pangakontol on " + str(kontoseis) + " eurot.")
print("Sisesta, mitu eurot soovid välja võtta:")
soovitud_raha = int(input())

Seejärel oleks vaja kontrollida, et väljavõetav rahasumma oleks väiksem või võrdne kontol olevast. Kui nii on, siis võetakse vastav summa kontolt maha. Kui ei ole, siis väljastatakse vastav veateade:

if soovitud_raha <= kontoseis:
kontoseis = kontoseis - soovitud_rahaprint("Välja võetud: " + str(soovitud_raha) + " eurot. Ärge unustage raha masinast ära võtta!")
else:
print("Kontol ei ole nii palju raha!")

Juba eelmisel nädalal oli näide, muutujale anti väärtuse tehtega, milles kasutame sedasama muutujat ennast (siin kontoseis = kontoseis - soovitud_raha). Muutuja uue väärtuse arvutamine vana põhjal on isegi nii levinud, et kasutusel on tehtemärgid (nt +=-=*=/=), mis võimaldavad seda lühemalt kirja panna.

Nii saaks asendada vastava rea eeltoodud programmis järgmisega:

kontoseis -= soovitud_raha

Lähme nüüd tagasi pangaautomaadi programmi juurde. Kõige lõpuks võime veel ekraanile väljastada, kui palju raha pangakontole jäi.

print("Pangakontol on nüüd: " + str(kontoseis) + " eurot.")

Kui nüüd lisada need read algse programmi if-osa sisse, siis saame kokkuvõttes järgneva programmi. Märgiga # tähistatakse programmis kommentaare, mis on inimeste jaoks ja mida Python ei arvesta. Kõik, mis samal real # märgile järgneb, on kommentaar.

kontoseis = 100 sisestatud_pin = input("Sisesta PIN-kood: ")
if sisestatud_pin == "1234":
print("Sisenesid pangaautomaati! Pangakontol on " + str(kontoseis) + " eurot.")
print("Sisesta, mitu eurot soovid välja võtta:")
soovitud_raha = int(input())
if soovitud_raha <= kontoseis:
kontoseis = kontoseis - soovitud_raha 
#kontoseisu väärtus väheneb
print("Raha välja võetud: " + str(soovitud_raha) + " euro t.")
else:
print("Kontol ei ole nii palju raha!")
print("Pangakontol on järgi: " + str(kontoseis) + " eurot.")
else:
print("Vale parool! Enesehävitusrežiim aktiveeritud: 3 ... 2 ... 1 ....")

Palun mõelge selle programmi loogika rahulikult läbi ning seejärel katsetage selle tööd.

2.3 MITMEOSALINE TINGIMUS. LOOGILISED TEHTED JA AVALDISED
-Tingimus on keerulisem

Eespool käsitlesime olukorda, kus mingi tingimuslause oli teise tingimuslause ühes harus. Nüüd aga vaatleme, kuidas saab kasutada keerulisemaid tingimusi. Tegemist on siis ikkagi ühe tingimusega, aga see koosneb mitmest osast. Võib ette kujutada mitmeid elulisi situatsioone, kus on vaja kontrollida mitut tingimust korraga. Olgu näiteks selline seif, mis avaneb ainult siis, kui kaks erinevat koodi õigesti sisestatakse. See võimaldaks näiteks kindlalt teada, et seifi avamisel peavad mõlemad partnerid korraga kohal olema.

Tingimusi saab kombineerida loogiliste tehete abil. Üks nendest on näiteks and, mis ongi “ja” tähenduses. Tehtega and seotud avaldis on tõene siis ja ainult siis, kui mõlemad avaldised, millega tehe tehakse, on tõesed. Järgnevas programmis ongi seda ära kasutatud.

kood1 = "1234"
kood2 = "0000"
print("Sisesta 1. salakood:")
pakutud_kood1 = input()
print("Sisesta 2. salakood:")
pakutud_kood2 = input()
 if pakutud_kood1 == kood1 and pakutud_kood2 == kood2:
print("Seif avaneb!")
else:
print("Salakoodidega on kehvasti. Tõstke käed üles!")

Katsetage seda programmi erinevate sisenditega. Näiteks, kui

  • mõlemad koodid on õiged;
  • 1. kood on õige, 2. kood vale;
  • 1. kood on vale, 2. kood õige;
  • mõlemad on valed.

Kas tulemus vastas teie ootustele?

Loogilisi tehteid on veel, näiteks or ja not. Sõna “or” tähendab tõlkes “või”. Asendage valikulauses tehe and tehtega or:

if pakutud_kood1 == kood1 or pakutud_kood2 == kood2:

Katsetage nüüd programmi tööd erinevate sisenditega. Jälle, kui

  • mõlemad koodid on õiged;
  • 1. kood on õige, 2. kood vale;
  • 1. kood on vale, 2. kood õige;
  • mõlemad on valed.

Püüdke or-tehte olemust nüüd selgitada. Kuidas on seos tavakeele sõnaga “või”?

-Loogilised tehted ja avaldised

Meil on kasutada tõeväärtused True ja False, mis sageli otseselt “nähtavad” polegi ja programmis paistavad näiteks hoopis mingite võrdlemistena.

pakutud_kood1 == "1234"
vanus < 14
soovitud_raha <= kontoseis

Olenevalt muutujate konkreetsetest väärtustest on nende avaldiste väärtusteks True või False. Loogiliste tehete abil saame keerulisemaid avaldisi moodustada. Tehete and ja or puhul on meil vaja kahte operandi, millega tehe toimub. Selliseid tehteid nimetatakse kahekohalisteks ehk binaarseteks. Tehe not töötab ühe operandiga (on ühekohaline ehk unaarne). Tehe not “pöörab” tõeväärtuse vastupidiseks. Näiteks avaldise

not 1 == 1

väärtus on False, sest 1 == 1 on True.

Võib öelda, et andor ja not tehete kasutamisel on tulemused järgnevad:

  • väide1 and väide2 – tõene ainult siis, kui mõlemad väited on tõesed
  • väide1 or väide2 – tõene siis, kui vähemalt üks väidetest on tõene
  • not väide1 – tõene ainult siis, kui väide1 on väär.

Tehted ja avaldised on meile põhimõtteliselt tuttavad juba koolimatemaatikast – aritmeetikast ja algebrast. Loogilised tehted ja avaldised vajavad veidi harjumist. Ärge väga muretsege, kui esimese hooga kõik veel selgeks ei saa. Põhimõtteliselt on tegemist siiski loogilise asjaga. 🙂

Loogilised avaldised muutuvad tingimusteks, kui neid selles rollis kasutatakse – näiteks tingimuslauses.

Vahel on tingimused keerulisemad ja programmi korraliku töö huvides tuleb need põhjalikult läbi mõelda. Olgu meil tahtmine teha salatit – kartuli- või makaronisalatit. Lihtsustatult oleks meil siis vaja kartuleid või makarone ja salatikastet.

Jätame praegu täpsustamata, millest see salatikaste tehtud on ja muid detaile ka. Tegelikult kipubki päriselu loogilistes avaldistes kirjeldamine päris keeruline olema. Programmide kirjutamisel aga vähemalt mingil tasemel seda teha tuleb.

Loogilise avaldise koostamiseks võtame kasutusele muutujad kartul_olemasmakaron_olemas ja salatikaste_olemas. Vastavalt siis sellele, kas vastav koostisosa on olemas või mitte, on selle muutuja väärtus True (on olemas) või False (ei ole olemas).

Püüame nüüd kirja panna, kas saame salatit teha või mitte. Siin on tegelikult võimalikud mitu mõttekäiku ja ka avaldis võib lõpuks tulla (näiliselt) erinev.

Üks võimalus oleks mõelda nii, et meil on vaja kahte koostisosa: n-ö nimiosa ja salatikastet. Nimiosas võib olla kartul või makaron – panemegi kirja kartul_olemas or makaron_olemas. Ja salatikaste – (kartul_olemas or makaron_olemas) and salatikaste_olemas. Sulud tähistavad siin (nagu ka aritmeetikas ja algebras) seda, et vastav tehe tuleb enne ära teha.

Järgmises näites on meil siis kartul olemas ja salatikaste, aga makarone pole. Kui meie mõttekäik on õige olnud, siis peaks ekraanile tulema True, sest tõesti saame salatit teha. Proovige!

kartul_olemas = True
makaron_olemas = False
salatikaste_olemas = True
print((kartul_olemas or makaron_olemas) and salatikaste_olemas)

Proovige nüüd programmi tööd muutujate kartul_olemasmakaron_olemas ja salatikaste_olemas erinevatel väärtustel. Enne kui käivitate, mõelge milline tulemus võiks tulla. Kas programm töötab vastavalt teie ootustele?

Eelnevalt oli juttu, et sulgude kasutamine suunab tehete järjekorda. Sulgudes olev tehakse varem. Mis aga juhtuks, kui näiteks avaldises (a or b) and c sulud ära jätaksime? Mis mõte neil üldse siin on? Kas siis nagunii ei tehtaks siin or-tehet enne, asub see ju eespool?

Tõepoolest on sulud siin olulised, sest kui neid poleks, siis tehtaks esimesena hoopis and-tehe. Nimelt on kokkulepe, et and on kõrgema prioriteediga kui or, analoogiliselt tavalise aritmeetikaga, kus ka korrutamine tehakse enne liitmist. Näiteks 2 + 3 * 4 on 14, aga mitte 20.

2.4 MITMEHARULINE TINGIMUSLAUSE ELIF ABIL

Eespool juba vaatlesime olukordi, kus tingimuslause harudes oli omakorda tingimuslauseid. Siin vaatame, kuidas vahel saab selliseid olukordi lühemalt kirja panna.

Vaatame sellist näidet, kus programmile öeldakse punktisumma ja programm teatab, mis hinde see summa annab.

Ülikoolis pannakse tihti hindeid järgmise skeemi järgi:

Tulemus (%)Hinne
>90 .. 100A
>80 .. 90B
>70 .. 80C
>60 .. 70D
>50 .. 60E
<=50F

Programm, mis saab sisendiks punktid ja kontrollib, kas selle eest saab hinde “A”, oleks järgnev:

punktid = int(input("Sisesta punktide arv")) 
if punktid > 90:
print("Hinne A")
else:
print("Ei ole hinne A")

Lisame nüüd kontrolli ka hindele “B”:

punktid = int(input("Sisesta punktide arv"))
if punktid > 90:
print("Hinne A")
else:
if punktid > 80:
print("Hinne B")
else:
print("Hinne ei ole A ega B")

Kuna hinnetele vastavaid vahemikke on palju, siis kipub programm jooksma treppides liiga paremale. Mugavamaks programmeerimiseks võib kasutada ka elif-osa, mis on nii kirjapildi kui ka tähenduse poolest kombinatsioon else-ist ja talle järgnevast if-ist.

Näiteks eelnev programmilõik oleks siis selline:

punktid = int(input("Sisesta punktide arv"))
 if punktid > 90:
print("Hinne A")
elif
punktid > 80:
print("Hinne B")
else:
print("Hinne ei ole A ega B")

Plokkskeem on siis hetkel järgmine.

2.5 JUHUSLIK ARV
-Juhusliku arvu genereerimine

Vahest läheb programmeerimises vaja, et arvuti oskaks genereerida juhuslikke arve. Näiteks proovime teha programmi, mis simuleeriks mündiviskamist ja saaks tulemuseks kulli või kirja.

Kuidas panna arvuti juhuslikult valima kahe valiku vahel?

Selles tulebki meile appi juhusliku arvu genereerimine. Funktsiooniga randint(1,2) saame võrdse tõenäosusega ühe arvu vahemikust 1-st 2-ni (mõlemad kaasaarvatud). Kuna sinna vahemikku jäävadki vaid kaks arvu: 1 ja 2, siis valitakse nende vahel. Kumb igal konkreetsel juhul tuleb, ei ole ette teada. Võrdse tõenäosuse puhul on mõlema juhu tõenäosus 50% (sageli öeldakse ka 0,5). Kui teha piisavalt palju katseid, siis umbes samapaljudel juhtudel tuleb tulemuseks 1 kui 2. Oluline on siin märkida, et väikestel katsearvudel võib erinevus olla täiesti märgatav. Näiteks vabalt võib juhtuda, et kümnest juhust on seitsmel juhul 1 ja kolmel juhul 2. Järgmisel nädalal asume juhuslikkust tsükliliselt “kontrollima”.

Sageli on meil aga vaja rohkem variante kui kaks. Näiteks randint(1,3) annab kas arvu 1, 2 või 3. Igaühe tõenäosus on siis ligikaudu 33,3% (1/3).

Funktsiooni randint() saab aga kasutada ainult siis, kui esimesele reale kirjutada, et seda funktsiooni programmis kasutatakse:

from random import randint

See tähendab, et me impordime moodulist random funktsiooni randint. Seal moodulis on veel teisigi huvitavaid funktsioone. Juhuslikke arve saab veel mooduli secrets abil, mille kasutamine on turvaline ka krüptograafiliste programmide puhul.

Meie aga jätkame siiski mooduliga random, mille kõik funktsioonid impordime korraga:

from random import *

Proovige aga nüüd järgmist programmi:

from random import
randint suvaline_arv = randint(1, 2)
if suvaline_arv == 1:
arvuti_valik = "kull"
else:
arvuti_valik = "kiri" 
print("Mündiviskes võitis: " + arvuti_valik)

Kui nüüd küsida kasutajalt, kas ta valib kulli või kirja, siis saamegi kulli ja kirja viskamise mängu:

from random import randint
 print("Kas kull (1) või kiri (2)?")
kasutaja_valik = int(input())
suvaline_arv = randint(1, 2)
 if kasutaja_valik == suvaline_arv:
print("Arvasid õigesti.")
else:
print("Arvasid valesti.")

Teeme nüüd programmi ümber lisades selle tingimuslause ühte harusse teise tingimuslause.

from random import randint 
print("Kas kull (1) või kiri (2)?")
kasutaja_valik = int(input())
suvaline_arv = randint(1, 2)
 if kasutaja_valik == suvaline_arv:
print("Arvasid õigesti.")
suvaline_arv2 = randint(1, 2)
if kasutaja_valik == suvaline_arv2:
print("Arvamus oli õige ka teisel korral.")
else:
print("Teist korda see arvamus enam õige ei olnud.")
else:print("Arvasid valesti.")

2.6 KILPKONNAGRAAFIKA
-Pythoni dokumentatsioon

Seni oleme saanud programmide töö tulemused tekstilisel kujul ekraanile väljastatuna. Samuti oleme sisendi andnud tekstilisel kujul. Reaalselt kasutatavad programmid on sageli hoopis graafilise kasutajaliidesega. Sellisteni jõuame mõne nädala pärast, aga natuke graafikat toome juba praegu sisse. Selles peatükis vaatame lähemalt Pythoni moodulit turtle (tõlkes “kilpkonn”), mille abil saab ekraanile kujundeid joonistada. Joonistamiseks tuuakse mängu tegelane – kilpkonn, kes oma virtuaalmaailmas ringi liikudes võib jätta maha jälje. See jälg võib teinekord päris huvitava ja isegi kunstilise kujuga olla.

-Ajalugu

Selline virtuaalne kilpkonn ilmus esmakordselt hariduslikus programmeerimiskeeles LOGO, mille lõid aastal 1967 Wally Feurzeig ja Seymour Papert. See keel oli mõeldud just lastele algoritmilise mõtlemise arendamiseks. Praeguseks on kilpkonnagraafikat võimalik kasutada mitmetes programmeerimiskeeltes, ka Pythonis. Viimasel ajal eriti populaarses hariduslikus programmeerimiskeeles Scratch on samuti tuntavaid kilpkonnagraafika mõjutusi. LOGO programmeerimist võib proovida siin. Võib-olla on huvitav teada, et üks esimesi interneti kaudu toimunud kursusi (aastal 1996, tol ajal e-posti kaudu) Eestis oli just programmeerimiskeele Logo kursus.

-Alustamine ja liikumine

Järgnevalt uurime, kuidas kilpkonna Pythonis kasutama hakata ning vaatame, kuidas kujundeid joonistada. Kokkuleppeliselt nimetatakse kilpkonnaks väikest kolmnurka joonistamisväljal.

Selleks, et joonistamisega alustada, tuleb esmalt importida vajalikud käsud kilpkonna moodulist. Selleks kirjutame programmi esimesele reale:

from turtle import *

Järgnevalt proovime kirjutada programmi, mille abil joonistataks ruut. Selleks kasutame sobivaid kilpkonnakäske:

  • forward(n) – liigu edasi (ingl forwardn sammu võrra (ühe sammu pikkus on 1 piksel ehk üks täpike ekraanil);
  • back(n) – liigu tagasi (ingl backn sammu võrra;
  • left(d) – pööra vasakule (ingl leftd kraadi;
  • right(d) – pööra paremale (ingl rightd kraadi.

Eelnevaid käske sobivas järjekorras rakendades saame järgneva programmi.

Näiteprogramm. Ruut

from turtle import *     
# * lisamisel imporditakse kõik kilpkonna käsud 
forward(100)                  
 # Kilpkonn liigub edasi 100 pikslit
left(90)                         
  # Kilpkonn pöörab 90° vasakule
forward(100)                      
 # Kordame eelnevaid käske, sest ruudul on neli külge
left(90)forward(100)left(90)forward(100) 
exitonclick()                     
 # Saame akna sulgeda hiireklõpsuga

NB! Ärge pange oma Pythoni programmi nimeks turtle.py. See ajab Pythoni segadusse.

Tulemuseks saame

Tegelikult võib kilpkonn järjekindlalt pöörata ka 90° paremale, tulemuseks on ikka ruut.

Näiteprogrammis märkame, et kilpkonn peab täitma korduvalt samu käske: minema 100 pikslit edasi ja pöörama seejärel 90° vasakule. Seega on siin tegemist tsüklilise tegevusega. Tsüklitest aga räägime edasistes osades.

Selleks, et vähendada kirjutamisvaeva, saab kilpkonna liikuma panna ka lühemate käskudega, kasutades pikemate esituste esimesi ja viimaseid tähti.

  • fd(n) – võrdne käsuga forward(n);
  • bk(n) – võrdne käsuga back(n);
  • lt(d) – võrdne käsuga left(d);
  • rt(d) – võrdne käsuga right(d).

See robot-kilpkonn oskab teha veel palju muudki. Täpsemalt võib vaadata Pythoni dokumentatsioonist.

-Värvimine

Kilpkonn oskab ka joonistatud kujundeid värvida ja muuta taustavärvi. Selleks, et värvima hakata, tuleb esmalt valida sobiv värv. Seda saab teha käsuga color(värvi_nimetus), kus värv antakse sõnena, mille väärtuseks on värvi ingliskeelne vaste või värvi kuueteistkümnendkoodis esitus. Näiteks musta värvi esitus kuueteistkümnendkoodis on #000000. Värvikoode saab vaadata siit.

Näiteks

color("red")
# Kilpkonn muutub punaseks

või

color("#008000")
# Kilpkonn muutub tumeroheliseks

Kui värv on valitud, siis tuleb kilpkonnale käsuga begin_fill() teada anda, et nüüd lähebki värvimiseks. Seda peab tegema vahetult enne kujundi joonistamist, mida värvida soovime. Värvimise lõpetamiseks tuleb peale kujundi lõppu kirjutada käsk end_fill(). Järgmiseks kirjutame programmi, mis joonistab punase ringi. Kilpkonn oskab joonistada ringi (ingl circle) käsuga circle(r), kus r on ringi raadius pikslites.

Näiteprogramm. Jaapani lipp

from turtle import * 
color("red")
# Kilpkonn muutub punaseks
begin_fill()                       
# Kilpkonn alustab ringi värvimist
circle(100)
# Kilpkonn joonistab ringi raadiusega 100 pikslit
end_fill()                         
# Kilpkonn lõpetab ringi värvimise
 exitonclick()

Kui eelmisel programmi puhul oli täpselt teada, mis toimub, siis täiendame seda programmi juhuslikkusega. Selles programmis imporditakse käske lausa kahest moodulist.

Näiteprogramm. Sinine, must või valge

from turtle import *
from random import randint
 värv = randint(1, 3)
if värv == 1:
color("blue")
# Sinine
if värv == 2:
color("black")
# Must
if värv == 3:
color("white")
# Valge valgel taustal
begin_fill()
# Kilpkonn alustab ringi värvimistcircle(100)
# Kilpkonn joonistab ringi raadiusega 100 pikslit
end_fill()
# Kilpkonn lõpetab ringi värvimise 
exitonclick()

Praegu tõime kilpkonna mängu selleks, et edasisi natuke keerulisemaid teemasid paremini illustreerida. Aga mitte ainult – hakkame ikka ilusaid pilte ka tegema.

2.7 SILMARING. ARVUSÜSTEEMID
-Kümnendsüsteem

Selle nädala silmaringi materjal on arvusüsteemidest. Alustame terminitest “arv” ja “number”, mida paraku üsna sageli segi aetakse. Sellele lisab hoogu asjaolu, et inglise keeles on sõna “arv” vasteks just “number” ja juhtub, et tõlkides jäetakse ka eesti keeles sõnaks “number”. Samuti on eesti keeles mitmeid termineid, kus “number” on kinnistunud, aga tegelikult pigem arvu tähenduses on (nt telefoni number, kinga number, passi number).

Niisiis püüdes sellest mitte liiga suurt numbrit teha, peame siiski vähemalt antud materjalis (ja tegelikult kogu sel kursusel) neil mõistetel vahet tegema.

Ajalooliselt oli arv algul loendamise tulemus. Loendades saame naturaalarvud, 1, 2, 3, 4, 5 jne. 0 võetakse mõnes kontekstis naturaalarvude hulka, mõnes mitte. Eks siin olegi mõneti filosoofiline küsimus – kas siis, kui midagi ei ole loendatud, saab üldse rääkida loendamise tulemusest! Hiljem arvude mõistet laiendati – räägiti täisarvudest, ratsionaalarvudest, reaalarvudest, kompleksarvudest. Meie jääme siin põhiliselt täisarvude juurde.

Igatahes tekkis ajalooliselt vajadus arve kirja panna. Kasutusel on olnud väga erinevaid süsteeme. Tänapäeval on kõige levinum viis panna arve kirja araabia numbrite abil. Algselt India päritolu märgid jõudsid Araabia kaudu Euroopasse. Seejuures 0 võeti teistest numbritest märgatavalt hiljem kasutusse. Numbreid on siis klassikaliselt kasutusel kümme. Need on 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. Numbrid on seega sümbolid – märgid, mille abil arve kirja pannakse.

Arve, mida kirja panna tuleb, on muidugi palju rohkem kui kümme. Teoreetiliselt on neid lausa lõpmatult palju. Kui väikeste naturaalarvude puhul saame ühe numbriga arvu kirja, siis edasi peab mingit süsteemi kasutama. Nii ongi kujunenud, et lisaks numbri enda väärtusele loeb ka tema positsioon. Näiteks arvus 77 on esimese 7 tähendus tegelikult 70 ja teisel 7. Sellist süsteemi nimetatakse positsiooniliseks arvusüsteemiks. Positsioon on oluline!

Kui nüüd nt 2016 juppideks võtta saame 2016 = 2000 + 10 + 6. Näeme, et 0 on väga oluline ja näitab, et sajalisi pole. Veel detailsemalt saame, et 2016 = 2 · 103 + 0 · 102 + 1 · 101 + 6 · 100. Tähele tuleb panna, et arvu väärtuse leidmisel hakatakse tegelikult pihta paremalt. Paremalt esimene number näitab üheliste (100 = 1) arvu, teine number kümneliste (101 = 10) jne. Lühematel juhtudel näeme muidugi peale vaadates ära, mis positsioonil paremalt viimane ehk vasakult esimene number on. Pikematel juhtudel aga tulebki paremalt lugema hakata.

Kuna on kasutada kümme erinevat numbrit, siis nimetatakse seda süsteemi kümnendsüsteemiks. See on tõesti laialt levinud, seejuures ka näiteks mõõtühikute (sh rahaühikute) juures. Siiski pole tegemist ainukese võimaliku arvusüsteemiga. Aegade jooksul on kasutuses olnud väga erinevad süsteemid. (Näiteks ka rahaühikute korral – Suurbritannia naelsterling jaotub 100 penniks alles alates 1971. aastast.)

Arvusüsteemid pole alati ka (puhtalt) positsioonilised olnud. Näiteks rooma numbrite puhul on positsioon küll oluline, aga mitte ülal toodud süsteemi järgi. Nüüd aga jätkame ikkagi positsiooniliste süsteemidega.

-Kahendsüsteem

Võib tekkida õigustatud küsimus, et kas kümme on ainuke võimalik numbrite arv ja arvusüsteemi alus. Kas võib süsteemi üles ehitada ka vähemate numbritega või hoopis enamate? Jah, saab nii vähemate kui enamatega. Vaatleme nüüd sellist süsteemi, kus numbreid on ainult kaks: 0 ja 1. Tegemist on kahendsüsteemiga. Arvude üles kirjutamise idee on samasugune nagu kümnendsüsteemis. Esialgu saame hakkama ühe numbriga. Kui loendatavaid elemente pole, siis on neid 0 ja kui on üks, siis on 1. Rohkem aga erinevaid numbreid pole. Tekib samasugune olukord nagu kümnendsüsteemis arvu 9 puhul, mille järel enam uusi numbreid pole. Nagu kümnendsüsteemiski tuleb nüüd kasutusele kirjapilt 10, mis tähendab siis tavamõttes kahte, arvutus oleks selline: 1 · 21 + 0 · 20.

Rõhutada tuleb, et tegemist on loendamise mõttes ikka sama arvuga, lihtsalt kirjapilt on erinev. Selleks, et eristada erinevaid aluseid, märgitakse neid alaindeksitega, seega 102 = 210. Pythonis aga pannakse kahendarvudele ette 0b. Näiteks 0b10 on siis tavamõttes 2.

Toome tabeli mõningate arvudega.

KümnendarvKahendarv
00
11
210
311
4100
5101
6110
7111
81000
91001
101010
111011
141110
151111
1610000
3111111
32100000
63111111
641000000

Näeme, et erinevates süsteemides on “ümmargused” hoopis erinevad arvud. Hea võimalus näiteks juubelite pidamiseks!

Kahendarvudel on praktiline väärtus just arvutitega seoses. Nimelt on kahte võimalikku seisundit palju hõlpsam realiseerida kui näiteks kümmet erinevat. Lamp põleb / ei põle. Mälupesas on midagi / ei ole. Kahendarv koosneb kahendnumbritest. Inglise keeles on kahendnumber binary digit, millest on tuletatud mõõtühiku nimeks bit. Bitt ongi informatsiooni põhiühikuks.

Kahendarvudega saab tehteid teha analoogiliselt kümnendarvudega, aga seda me siinkohal ei vaatle, mis ei takista siiski selleteemalise küsimuse esitamist.

-Kaheksandsüsteem. Kuuteistkümnendsüsteem

Kahendarvud lähevad üsna kiiresti pikaks ja see on üks põhjus, miks kasutatakse ka kaheksandarve ja kuueteistkümnendarve. Kuna 8 ja 16 on 2 astmed, siis on konverteerimine näiteks kuueteistkümnend ja kahendsüsteemi vahel oluliselt lihtsam kui kümnendsüsteemi ja kahendsüsteemi vahel.

Kaheksandsüsteemis saab ikka tavalisi numbreid kasutada – lihtsalt 8 ja 9 jäävad kasutamata. Kuueteistkümmendsüsteemis aga kümnest märgist ei piisa. Spetsiaalseid numbreid pole siiski juurde mõeldud, kasutatakse tähti A, B, C, D, E ja F.

Lisamegi nüüd eelmisele tabelile kaheksandarvude ja kuueteistkümnendarvude veerud.

KümnendarvKahendarvKaheksandarvKuueteistkümnendarv
0000
1111
21022
31133
410044
510155
611066
711177
81000108
91001119
10101012A
11101113B
14111016E
15111117F
16100002010
3111111371F
321000004020
63111111773F
64100000010040

Kuidas siis mõista kaheksandarvu 137? Nüüd on siis aluseks 8, mis tähendab, et

1378 = 1 · 82 + 3 · 81 + 7 · 80 = 64 + 24 + 7 = 95

Vaatleme ka kahte kuueteistkümnendarvu. Neis võivad numbritena olla tähed tähestiku algusest, aga ei pruugi olla. Näiteks arvestades, et A on kümnendsüsteemi 10 ja D on 13, saame

A2D16 = 10 · 162 + 2 · 161 + 13 · 160 = 2560 + 32 + 13 = 2605

ja

101016 = 1 · 163 + 0 · 162 + 1 · 161 + 0 · 160 = 4096 + 16 = 4112.

Pythonis on kaheksandsüsteemis arvu märkimiseks kasutusel prefiks (eesliide) 0o ja kuueteistkümnendarvude jaoks 0x.

Kuueteistkümnendarve kasutatakse sageli näiteks mäluaadressides ja ka näiteks värvide märkimiseks. Erinevate värvide kuueteistkümnend koode saab vaadata siit. Neid saame ka kilpkonnagraafikas kasutada. Näiteks turtle.pencolor('#85e085') mõjul muutub kilpkonna sule heleroheliseks.

Kaheksandsüsteemi arve kasutatakse näiteks mõnedes operatsioonisüsteemides failidele juurdepääsu õiguste määramiseks. Näiteks Unixis annab chmod 664 mingifail.txt kasutajale ja rühmale õiguse lugeda ja kirjutada, aga mitte käivitada. Teised saavad ainult õiguse lugeda.

-Veel lugemist

Ise saate arve erinevate alustega süsteemidesse konverteerida näiteks siin või ka siin.

Nagu paljudest muudest asjadestki on arvusüsteemidest juttu “Matemaatika õhtuõpikus”, mille saab ka alla laadida.

2.8 SILMARING. TÕEVÄÄRTUSED
-Tõeväärtustabelid

Eespool vaatlesime salatinäidet.

kartul_olemas = True
makaron_olemas = False
salatikaste_olemas = True
print((kartul_olemas or makaron_olemas) and salatikaste_olemas)

Soovitati ka proovida programmi tööd muutujate kartul_olemasmakaron_olemas ja salatikaste_olemas erinevatel väärtustel. Kerkib küsimus, mitu erinevat varianti üldse on? Igaüks kolmest muutujast võib omada kahte erinevat väärtust. Kui olekski ainult üks muutuja, oleks võimalusi kaks:

  • True
  • False

Kui oleks ainult kaks muutujat, siis võimalusi oleks neli:

  • TrueTrue
  • TrueFalse
  • FalseTrue
  • FalseFalse

Kui on kolm muutujat, siis on võimalusi kaheksa:

  • TrueTrueTrue
  • TrueTrueFalse
  • TrueFalseTrue
  • TrueFalseFalse
  • FalseTrueTrue
  • FalseTrueFalse
  • FalseFalseTrue
  • FalseFalseFalse


Meie näites on salati jaoks vaja kartulit või makaroni. Sõnal “või” on tavakeeles mõnevõrra teistsugune tähendus, kui programmeerimisel (või ka matemaatilises loogikas). Tavakeeles on “või” sageli välistav – kas see või teine (aga mitte mõlemad). Loogikas ja programmeerimisel on aga tehe or tõene ka siis, kui mõlemad operandid on tõesed. Seda saab kujutada ka tõeväärtustabelina. Loogikas tähistatakse or-tehet sageli märgiga V. Tõene ja väär on tähistatud vastavalt t ja v.

Toome ka tõeväärtustabeli and-tehte jaoks, mida sageli tähistatakse märgiga &.

Meie salatinäites on tõeväärtustabel arvutatud kahes järgus kõigepealt A v B, mis siis meil tähendab kartul_olemas or makaron_olemas ja pärast siis kogu avaldis (kartul_olemas or makaron_olemas) and salatikaste_olemas.

-Loogiliste avaldiste samaväärsus

Salatinäite puhul võime läheneda ka natuke teistmoodi. Kartulisalati jaoks oleks meil vaja kartulit ja salatikastet. Makaronisalati jaoks oleks vaja makarone ja salatikastet. Kokkuvõttes aga piisab, kui vähemalt ühe jaoks neist on materjal olemas. Vastav loogiline avaldis on siis järgmine.

(kartul_olemas and salatikaste_olemas) or (makaron_olemas and salatikaste_olemas) 

Tegelikult ongi see samaväärne avaldisega, mis meil enne oli.

(kartul_olemas or makaron_olemas) and salatikaste_olemas 

Loogiliste tehete puhul kehtivad mitmed seadused (analoogiliselt algebrale). Näiteks

  • avaldis a and b on samaväärne avaldisega b and a;
  • avaldis a or b on samaväärne avaldisega b or a;
  • avaldis (a or b) and c on samaväärne avaldisega (a and c) or (b and c);

Loogilistes tehetes orienteeruda on programmeerijale väga oluline ja nii on seda arendavad õppeained ka ülikoolide õppekavades.