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

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

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.

1. 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!

2. Számok kiírása

Az ábrán egy program pszeudokódja látható, amely kiírja a számokat 1-től 20-ig.

Gondolok egy számra, legyen ez 1.
Ismétlés, amíg a szám ≤ 20
    Leírom a számot.
    Új sort kezdek.
    Növelem a számot 1-gyel.
Ismétlés eddig

Írd meg ezt a programot Pythonban while ciklussal!

Figyeld meg: ahogy begépeled a while utáni : kettőspontot, az Enter billentyű hatására a gép egyből néhány szóközzel beljebb kezdi a sorokat. Ez kell ahhoz, hogy a következő utasításokat a ciklustörzs részének tekintse a Python.

Emlékezz arra is, hogy a ciklusokban az elvégzendő művelet van a ciklustörzsben (ki akarjuk írni a számokat, tehát a print), utána pedig a következő elemre lépés (x növelése). Ezt használd mindig így, ez a legjobban követhető!

Megoldás
szam = 1
while szam <= 20:
    print(szam)
    szam = szam+1

3. Számtani sorozat

Dolgozz tovább az előző feladattal! Az tulajdonképp egy számtani sorozatot írt egész számokból ki 1-től 20-ig, 1-es növekménnyel.

  • Írd át úgy a programot, hogy a számtani sorozat differenciáját a felhasználó adhassa meg!
  • Egészítsd ki úgy, hogy a sorozat két határát (eddig 1 és 20 voltak) is a felhasználó adhassa meg! Ezek is 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 min és max, 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 min-be és max-ba a számok!
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:
    min = hatar1
    max = hatar2
else:
    min = hatar2
    max = hatar1

szam = min
while szam <= max:
    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égigoldani a jövő hétre, hogy felkészült legyél.

4. 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 kiemeneten 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!

5. Nyomkövető: feladatok

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.

6. 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="")

7. 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.

8. 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.

9. Egyre több

Egy olyan Python programot kell írnod, amelyik kér egy számot a felhasználótól, majd kirajzol egy háromszöget az oldalt látható módon. A háromszög egyre több számot tartalmaz. Benne a számok mindig egyesével nőnek minden sorban.

Az egyik példában a bemenet n=5 volt, ezért a leghosszabb sorban pontosan öt darab szám van: 11 12 13 14 15, előbb 1-től 5-ig lesznek egyre többen. A rövidebb példa az n=4 esetet mutatja, itt a leghosszabb sor négy számból áll: 7 8 9 10. Ha a felhasználó túl kicsi számot ad, nullát, esetleg negatívat, akkor adj hibajelzést! Használj tabulátor karaktereket a számok között!

n = 5

 1 
 2   3 
 4   5   6 
 7   8   9  10 
11  12  13  14  15 
n = 4

 1 
 2   3 
 4   5   6 
 7   8   9  10 

Tipp

Ezt két egymásba ágyazott ciklussal legegyszerűbb megoldani; egyik a sorokért felel, másik pedig azon belül a számokért. A kiírt számot tárold külön változóban, amely független a ciklusváltozóktól! Mikor kell ezt a kiírt számot növelni?

10. Szorgalmik

Ha mindennel elkészültél, dolgozhatsz a szorgalmi feladatokon is. Ezek plusz pontért küldhetők be.