2. hét: nyomkövetés, vezérlés

Czirkos Zoltán, Frey Balázs, Bulla Ádám · 2024.09.22.

Nyomkövetés. Vezérlési szerkezetek: elágazások, ciklusok. Összetett vezérlési szerkezetek, összefüggő ciklusok és független változók.

Felkészülés a laborra:

1. Kettő meg három

Adott az alábbi program.

egyik = input("Írj be valamit: ")
masik = input("Írj be még valamit: ")

print(egyik + masik)

Másold be a fejlesztőkörnyezetbe, és futtasd le! Mi történik akkor, ha azt írod be neki, hogy alma, és hogy fa? És mi történik akkor, ha 2-t és 3-at írsz be neki? (Miért nem 5?) Magyarázd meg (magyar nyelvű szövegben), hogy mi történik!

Ha ez megvolt, írd át a programot ilyenre:

egyik = int(input("Írj be valamit: "))
masik = int(input("Írj be még valamit: "))

print(egyik + masik)

Figyeld meg, mi a különbség a kódban! Az első két sor változott, a harmadik nem. Próbáld most ki 2-vel és 3-mal! Mit tapasztalsz? Mi történik akkor, ha most próbálod beírni az előbbi szavakat? Magyarázd meg az eredményt!

2. Sztringek különleges karakterekkel

Az előadás szorzótáblás programjánál szóba jött, hogy létezik egy tabulátor nevű karakter, és hogy azt "\t"-vel kell a forráskódban megadni. Ennek kapcsán pedig arról is, hogy a különleges karaktereket \ visszaperrel kell jelölni, ha szöveg belsejében szerepelnek a forráskódban.

Írd ki egyetlen egy print() utasítással az alábbi szövegeket! Ügyelj arra, hogy ahol két sorban vannak a minta szerint a kimenetek, ott a programodnak is úgy kell megjelenítenie őket.

A print('hello') kiírja, hogy "hello",
és kezd egy új sort.
A "\t" karaktert tabulátornak nevezzük.
A következő 8-cal osztható sorszámú oszlopra lehet ugrani vele.

3. A tartály

Tartály

Írj programot, amely segít kiszámolni a felhasználónak, hogy hány doboz festéket kell vennie a lábakon álló tartály festéséhez! Ehhez használnod kell majd az első előadásokon tanultakat. Indulj ki az előadáson bemutatott kör kerülete és területe programból!

A tartálynak ismerjük a magasságát és az átmérőjét. Mindenhol le kell festeni, az oldalát, a tetejét és az alját is. Tudjuk azt is, hogy egy doboz festék 2 m2 felület lefestéséhez elegendő.

Tartály festése

Milyen magas? 2
Mennyi az átmérője? 1.2

4.900885 doboz festék kell.

Figyelj arra, hogy a program kódjában tizedesvessző helyett tizedespontot kell használni (pl. 3.14, persze jó a math.pi is), ugyanígy a bemenet megadásánál is. Ha nem jön ki a fenti eredmény, gondold át, helyes-e a képlet, amit használsz.

Megoldás
print("Tartály festése")

magas = float(input("Milyen magas? "))
atmero = float(input("Mennyi az átmérője? "))

sugar = atmero/2
doboz = (2 * sugar**2 * math.pi + magas * 2 * sugar * math.pi) / 2

print(doboz, "doboz festék kell.")

4. Szakasz hossza

Írj programot, amely a felhasználótól bekéri két síkbeli pont x és y koordinátáit, és kiírja a közéjük húzott egyenes szakasz hosszát (Pitagorasz tételével)!

szakaszhossz
(0;0)–(1;1)1.414214
(1;5)–(4;1)5
(-3;2)–(5;7)9.433981
Megoldás
import math

x1 = float(input("x1 = "))
y1 = float(input("y1 = "))
x2 = float(input("x2 = "))
y2 = float(input("y2 = "))
hossz = math.sqrt((x1-x2)**2 + (y1-y2)**2)
print(hossz)

Hasonló feladatok

Ha ez a feladat nehezen ment, megoldhatsz pár hasonló feladatot a példatárból, mielőtt a következő feladatra rátérsz.

Vigyázz, a laborfeladatokat erősen ajánlott az utolsó feladatig megoldani, hogy a jövő hétre felkészült legyél. Ha nem sikerül, fejezd be őket otthon!

5. Másodfokú egyenlet

Írj programot, amely az ax2+bx+c=0 másodfokú egyenlet együtthatóit kérdezi a felhasználótól! Ezek valós számok. Ezek után írja ki az egyenlet x1 és x2 megoldását! A megoldóképlet:

Próbáld ki a bal oldalt látható egyenletekre! Ezekkel ellenőrizni tudod a megoldásod. Próbáld ki aztán a jobb oldali egyenletekre is. Mit tapasztalsz? Miért?

egyenletmegoldás
2x2-x-6 = 0x1=2, x2=-1.5
x2-12x+35 = 0x1=5, x2=7
egyenletmegoldás
2x2-4x+2 = 0?
x2+2x+10 = 0?

Írd át úgy a programot, hogy figyelembe vegye azokat az eseteket, amikor nincs, vagy csak egy valós gyök van, és eszerint végezd a kiírást! Ehhez a diszkriminánst kell megvizsgálni, ami a gyökjel alatti rész. Például, ha ott negatív szám van, nincsen valós megoldás, mert nem lehet negatív számból gyököt vonni.

Megoldás

Arra kell figyelni, hogy ne vonj negatív számból négyzetgyököt. A gyökvonás előtt a diszkrimináns vizsgálatával meg kell nézni, hány valós megoldás lesz.

Itt egy nagyobb kifejezést kapsz, amiben többféle operátor (összeadás, kivonás, szorzás stb.) szerepel. Ezeknek a műveleteknek Pythonban ugyanúgy van precedenciája, mint a matematikában. A szorzás pl. magasabb rendű művelet, mint az összeadás. A nyelv precedencia szabályai összetettebbek; erről majd előadáson lesz szó.

A diszkr == 0 vizsgálat elméletben helyes, gyakorlatban azonban nem előnyös ilyet írni. A kerekítési hibák miatt előfordulhat az, hogy 0-hoz olyan közeli szám adódik, amit már 0-ra kerekít a számítógép. Erről is később lesz szó előadáson.

import math
a = float(input("a: "))
b = float(input("b: "))
c = float(input("c: "))

diszkr = b**2 - 4* a * c

if diszkr > 0:
    x1 = (-b - math.sqrt(diszkr)) / (2*a)
    x2 = (-b + math.sqrt(diszkr)) / (2*a)
    print("x1: ",x1)
    print("x2: ",x2)
elif diszkr == 0:
    print(-b / (2*a))
else:
    print("Az egyenletnek nincs megoldása")

Hasonló feladatok

Ha ez a feladat nehezen ment, megoldhatsz pár hasonló feladatot a példatárból, mielőtt a következő feladatra rátérsz.

Vigyázz, a laborfeladatokat erősen ajánlott az utolsó feladatig megoldani, hogy a jövő hétre felkészült legyél. Ha nem sikerül, fejezd be őket otthon!

6. Számtani sorozat

Olyan programot kell írnod, amelyik számtani sorozatot jelenít meg.

  • A számtani sorozat differenciáját a felhasználó adhassa meg! A sorozat két határát (alsó és felső) is! Ezek egész számok kell legyenek.
  • Hogy „reagálja le” a program azt, ha rossz sorrendben adod meg a határokat? Javítsd meg, hogy ilyenkor is működjön! Ezt legjobb úgy csinálni, ha a két határt nem mn és mx, hanem valamilyen semleges nevű változóba teszed először (pl. hatar1, hatar2), mert amíg nem vizsgáltad meg őket, addig nem jó ötlet minimumnak és maximumnak nevezni. Tehát olvasd be őket, vizsgáld meg a sorrendet, és utána kerüljenek mn-be és mx-ba a számok! Hogy miért nem min és max a változók nevei, arról majd később tanulunk. (itt nem okozna egyébként gondot...)
Megoldás
diff = int(input("Mennyi a sorozat differenciája?"))
hatar1 = int(input("Mennyi a sorozat egyik határa?"))
hatar2 = int(input("Mennyi a sorozat másik határa?"))

if hatar1 <= hatar2:
    mn = hatar1
    mx = hatar2
else:
    mn = hatar2
    mx = hatar1

szam = mn
while szam <= mx:
    print(szam)
    szam = szam+diff

Hasonló feladatok

Ebben a témakörben is találsz még feladatokat a példatárból. Ha úgy érzed, oldj meg onnan néhányat a továbblépés előtt. De vigyázz, az itteni feladatokat ajánlott végig megoldani a jövő hétre, hogy felkészült legyél.

7. A nyomkövető használata

A programozási hibákat gyakran nehéz megtalálni, de sokat segít a nyomkövetés. Ennek segítségével a programot megállíthatjuk futás közben, végrehajthatjuk soronként, közben megfigyelhetjük a változók értékeit. Ez azért jó, mert:

  • Rögtön észre tudjuk venni, ha épp „elromlott” egy változó: rossz volt a gondolatmenetünk, algoritmusunk, és nem azt tettük bele, amit szerettünk volna.
  • Azt is látjuk, ha kódolási hibánk van; ha nem azt a műveletet végzi el a programsor, mint amit szántunk neki. Például mert lefelejtettünk egy zárójelet, tehát kódolási hibánk van.

A nyomkövetés kipróbálásához, megtanulásához tedd a következőket. Először is másold be ezt a programot egy új fájlba:

n = 1
while n <= 10:
    print(n, end=" ")     # nem kezd új sort
    n += 1
print(".")

Mentés után a Shell ablak menüjében kattints a Debug / Debugger menüpontra. Erre megjelenik egy Debug Control nevű ablak. Ebben pipáld be a [ ] Source jelölőnégyzetet! Utána a program ablakában a szokásos Run / Run module menüpontra kattints.

A program ilyenkor elindult, de még egyelőre meg van akasztva a legelső sor előtt. A Debug Control ablak Over gombjának nyomkodásával lehet végrehajtani a következő sort. A befejezett ciklustörzsek után a kimeneten elkezdenek megjelenni a számok. A forráskódban látszik, melyik az aktuális sor, a szürke sáv mutatja, hol tart épp a végrehajtás. A Debug Control ablakban pedig (sok jelenleg nem lényeges információ mellett) a változó értéke figyelhető meg:

Debug Control

Kattints még sokszor az Over gombra, közben figyeld a kimenetet és a Shell ablakot!

Miután kitapasztaltad, válaszolj a nyomkövető használatával az alábbi kérdésekre!

  • Mennyi az alábbi programban az n változó értéke, amikor a legalsó sorhoz ér a végrehajtás, a print(".")-hoz?
    n = 1
    while n <= 10:
        print(n, end=" ")     # nem kezd új sort
        n += 1
    print(".")
  • Alább egy program, amely 8 faktoriálisát számítja ki, és 40320-at ír a kimenetre.
    szorzat = 1
    n = 8
    while n > 1:
        szorzat *= n
        n -= 1
    print(szorzat)
    Értsd meg a nyomkövető segítségével a program működését! A nyomkövető használatával – újabb print() beírása nélkül – mondd meg, hogy mennyi a szorzat változó értéke, amikor az n változó éppen 3-ra változott!
    Megoldás

    A válasz: szorzat = 6720. Mivel a ciklus visszafelé megy, ez a változó nem a faktoriálisok értékeit veszi fel menet közben.

  • A következő program Euklidész algoritmusa segítségével határozza meg két szám legnagyobb közös osztóját, jelen esetben az 11220-ét és a 2002-ét, ami 22:
  • a = 11220
    b = 2002
    while b > 0:
        temp = b
        b = a % b
        a = temp
    
    print("lnko =", a)
    Megint új print() beírása nélkül: mennyi a b változó értéke, amikor az a épp 374-re változott?
    Megoldás

    Itt: b = 44.

8. Adott hosszúságú szakasz

Írj egy programot, amely kér a felhasználótól egy számot, és kirajzol egy + és − jelekből álló szakaszt. Pl. ha a szám 4, akkor a képernyőn a lenti ábra jelenjen meg, vagyis a belsejében 4 db − legyen:

Mekkora legyen a szakasz?
4
+----+

Írd meg a programot előbb úgy, hogy ciklust használsz a – jelek kiírásához!

Aztán próbáld ki, mi történik a print("-" * 4) sor hatására. Hogy lehetne ezt felhasználni? Írd meg így is a programot!

Megoldás

Ciklussal:

print("Mekkora legyen a szakasz?")
hossz = int(input())
print("+", end="")
i = 0
while i < hossz:
    print("-", end="")
    i = i+1
print("+")

Sztring többszörözésével:

print("Mekkora legyen a szakasz?")
hossz = int(input())
print("+", end="")
print("-" * hossz, end="")
print("+", end="")

Még rövidebben:

print("Mekkora legyen a szakasz?")
hossz = int(input())
print("+", "-" * hossz, "+", sep="")

9. Adott méretű négyzet

Az előző feladat rajzolást végző programrészéből készíts egy olyan másolatot, amely + és - karakterek helyett | és . karaktereket használ, mint jobb oldalon! Végül pedig, ezt ciklusba téve, írj egy olyan változatot, amelyben egy adott méretű négyzet jelenik meg.

|....|
+----+
|....|
|....|
|....|
|....|
+----+

A forráskód szerkesztését kényelmesebb billentyűzeten végezni, mint egérrel. Szinte minden funkció elérhető gyorsbillentyűkön keresztül. Néhány fontosabb:

  • Home, End: sor elejére, sor végére ugrás,
  • Shift + , , , : forráskódrészlet kijelölése,
  • Ctrl + ], Ctrl + [: a kijelölt részlet indentálása (különösen hasznos ennél a feladatnál: amikor egy meglévő kódrészletet szeretnél ciklusba betenni, vagy ciklusból kivenni!),
  • Ctrl + C, Ctrl + V: a szokásos másolás és beillesztés,
  • Ctrl + Z: „undo”, szerkesztés visszavonása.
Megoldás

Ciklussal:

print("Mekkora legyen a négyzet?")
hossz = int(input())

# Felső sor
print("+", end="")
i = 0
while i < hossz:
    print("-", end="")
    i = i+1
print("+")

# Közepe
j = 0
while j < hossz:
    print("|", end="")
    i = 0
    while i < hossz:
        print(".", end="")
        i = i+1
    print("|")
    j = j+1

# Alsó sor, mint a teteje
print("+", end="")
i = 0
while i < hossz:
    print("-", end="")
    i = i+1
print("+")

Sztring többszörözésével lehetne rövidebben is.

10. Háromszög golyókból

Írjunk programot, amely kér a felhasználótól egy számot (n), és utána egy akkora háromszöget rajzol a képernyőre „o” betűkből, hogy annak éppen a megadott számú sora van! Például n=3 esetén az itt látható ábra keletkezzen.

  o
 ooo
ooooo
Megoldás

A feladat megoldásának kulcsa egy rajz készítése… És annak meghatározása, hogy melyik sorban hány golyó és hány szóköz van. Aki ide eljut, annak nyert ügye van.

  • Minden sor egyforma: sok szóköz, aztán sok golyó. A rajzon pötty helyettesíti a kiírandó szóközöket.
  • Egy sor kiírása: ciklusban szóköz, ciklusban golyó. Aztán új sor kezdése.
  • Ha ez megvan, ezt kell ciklusba tenni.
···o
··ooo
·ooooo
ooooooo

Ciklusokkal:

magas = int(input("Milyen magas legyen a kupac?"))

sor = 0
while sor < magas:
    # A sorok elejére kellenek szóközök
    oszlop = 0
    while oszlop < magas-sor-1:
        print(" ", end="")
        oszlop = oszlop+1

    # Utána valamennyi darab o
    oszlop = 0
    while oszlop < sor*2+1:
        print("o", end="")
        oszlop = oszlop+1
    print()
    sor = sor+1

Sztring többszörözésével:

print("Milyen magas legyen a kupac?")
magas = int(input())

sor = 0
while sor < magas:
    print(" " * (magas-sor-1) + "o" * (sor*2+1))
    sor = sor+1

Hasonló feladatok

Itt mindig az a lényeg, hogy a rajz alapján rájöjj, milyen vezérlési szerkezettel állítható az elő. Ebben a témakörben is találsz még feladatokat a példatárból.

11. További feladatok

Ha a laborfeladatokkal elkészültél, dolgozz a példatárban lévő feladatokon, a szorgalmi feladatokon, a minta zárthelyin, vagy a házi feladatodon.

Informatikusok próbálják lekódolni az Algoritmusok és gráfok tárgyon tanult algoritmusokat. A félév elején még nem biztos, hogy minden egyszerűen menni fog, de ahogy megismeritek a vonatkozó adatszerkezeteket és nyelvi elemeket, egyre könnyebb lesz. Ezzel két legyet lehet ütni egy csapásra, mert két tantárgyat is gyakoroltok egyszerre.