Decyzje

🎯 Po co Ci to?

Program bez decyzji jest jak droga bez skrzyżowań — zawsze ta sama trasa. Tymczasem bankomat sprawdza saldo, gra sprawdza kolizję, a formularz sprawdza, czy hasło się zgadza. W dziale 1 rysowałeś romby na schematach blokowych; dziś nauczysz się je pisać. Na deser zaprogramujesz w końcu rok przestępny — specyfikację i algorytm masz gotowe od dwóch działów.

✅ Czego się nauczysz

Po tej jednostce potrafisz:

  • budować wyrażenia logiczne z porównań oraz spójników and, or, not;
  • pisać rozgałęzienia if / elif / else i przewidywać, którą gałęzią pójdzie program;
  • tłumaczyć warunki z języka polskiego na Pythona — i wyłapywać, gdzie polszczyzna oszukuje.

🔁 Przypomnij sobie

Romb w schemacie blokowym (1.3) ma dwa wyjścia: TAK i NIE. if to dokładnie ten romb, a wcięcia w kodzie to jego gałęzie.

📘 Wyjaśnienie

Warunki. Porównania znasz z matematyki, w Pythonie piszą się niemal tak samo: <, >, <=, >=, != (różne). Jedna zmiana jest zdradliwa: pytanie o równość to ==, bo pojedyncze = zabrało już przypisanie. Wynikiem porównania jest wartość logiczna: True albo False — dwie jedyne wartości typu, który znasz z działu o bitach.

Warunki łączy się spójnikami: and (oba muszą zachodzić), or (wystarczy jeden), not (odwróć). Nawiasy porządkują, jak w matematyce.

wiek = 16
ma_zgode = True
moze_jechac = wiek >= 18 or (wiek >= 16 and ma_zgode)
print(moze_jechac)      # True

Rozgałęzienia. Instrukcja if wykonuje wcięty blok tylko, gdy warunek jest prawdziwy; else łapie całą resztę; elif (skrót od „else if") pozwala ustawić kilka rombów w kaskadę:

punkty = int(input("Punkty: "))
if punkty >= 90:
    print("celujący")
elif punkty >= 75:
    print("bardzo dobry")
elif punkty >= 50:
    print("dostateczny")
else:
    print("do poprawy")

Program sprawdza warunki od góry i wykonuje pierwszy pasujący blok — po czym opuszcza całą kaskadę. Dlatego dla 95 punktów wypisze tylko „celujący", choć $95 \ge 75$ też jest prawdą. Kolejność warunków to część algorytmu: odwróć kaskadę (punkty >= 50 na górze), a każdy zdający dostanie „dostateczny".

🧮 Prześledź

Prześledź kaskadę ocen dla wejść: 90, 74, 50, 49. Zapisz, które warunki zostały sprawdzone (nie tylko który zadziałał).

Sprawdź odpowiedź

90: sprawdzony 1 warunek (>=90 prawda) → „celujący". 74: >=90 fałsz, >=75 fałsz, >=50 prawda → „dostateczny", sprawdzone 3. 50: identycznie 3 sprawdzenia → „dostateczny" (brzeg! równość wchodzi dzięki >=). 49: trzy fałsze → else → „do poprawy". Zauważ: else nie ma warunku — jest gwarancją, że każde dane gdzieś trafią, czyli programową wersją reguły „każda droga schematu prowadzi do Stopu".

💻 Kod krok po kroku

Rok przestępny — algorytm z jednostki 1.2 słowo w słowo przełożony na Pythona:

r = int(input("Rok: "))
if r % 400 == 0:            # % to reszta z dzielenia (mod z pseudokodu)
    print("przestępny")
elif r % 100 == 0:          # dzieli się przez 100 (a przez 400 już nie)
    print("nieprzestępny")
elif r % 4 == 0:            # dzieli się przez 4 (a przez 100 już nie)
    print("przestępny")
else:
    print("nieprzestępny")

Przyjrzyj się kolejności: pytamy najpierw o wyjątek od wyjątku (400), potem o wyjątek (100), na końcu o regułę (4). Spróbuj w głowie odwrócić kolejność i prześledzić rok 2000 — zobaczysz, czemu kaskada od reguły do wyjątku by skłamała. Kolejność pytań to nie kosmetyka, to logika.

🐞 Znajdź błąd

Program ma wpuszczać na film osoby w wieku 13–17 lat tylko z opiekunem, a od 18 — zawsze:

wiek = int(input("Wiek: "))
opiekun = input("Jest opiekun? (t/n): ") == "t"
if wiek >= 13 and opiekun or wiek >= 18:
    print("Wchodzisz")
else:
    print("Niestety nie")

Dla jakich danych program zachowa się źle? (Podpowiedź: sprawdź dwunastolatka z opiekunem i… trzydziestolatka bez opiekuna — a potem dziesięciolatka z opiekunem.)

Sprawdź odpowiedź

Trzydziestolatek bez opiekuna wchodzi (dobrze — wiek >= 18 ratuje sprawę). Ale dziesięciolatek z opiekunem też wejdzie? Sprawdźmy: wiek >= 13 fałsz, więc and daje fałsz; or wiek >= 18 fałsz — nie wejdzie. Dobrze. To gdzie błąd? W wieku 13–17 bez opiekuna: wiek >= 13 prawda, opiekun fałsz → fałsz, wiek >= 18 fałsz → „Niestety nie" — poprawnie… Program jest w istocie poprawny logicznie, ale kruchy: działa tylko dzięki temu, że and wiąże mocniej niż or. Wystarczy, że ktoś „poprawi" go do wiek >= 13 and (opiekun or wiek >= 18) — i osiemnastolatek bez opiekuna nadal wejdzie, ale dwunastolatek z opiekunem już... też nie wejdzie (poprawnie), za to każdy 13+ bez opiekuna odpadnie — zmiana znaczenia! Morał podwójny: (1) ucz się, że and ma pierwszeństwo przed or, (2) i tak stawiaj nawiasy — (wiek >= 13 and opiekun) or wiek >= 18 znaczy to samo, a nie wymaga od czytelnika pamiętania reguł pierwszeństwa. Kod czyta się częściej, niż pisze.

⚠️ Uwaga, pułapka

Polskie „lub" bywa podstępne. „Wstęp wolny dla uczniów i studentów" znaczy: jesteś uczniem lub studentem (uczen or student) — a nie and (jedną osobą będącą uczniem i studentem naraz). Przy tłumaczeniu warunków z polskiego zawsze pytaj: „czy oba naraz, czy wystarczy jedno?" — język naturalny i logika częściej się tu rozjeżdżają, niż zgadzają.

🛠️ Teraz Ty

Napisz kalkulator BMI z klasyfikacją: pyta o masę i wzrost, liczy $\text{BMI} = \frac{\text{masa}}{\text{wzrost}^2}$ (wzrost w metrach; potęga to ** — wzrost ** 2), po czym kaskadą if/elif/else wypisuje kategorię (np. do 18,5 / do 25 / do 30 / powyżej). Przetestuj na wartościach brzegowych kategorii — dokładnie 25.0 powinno trafić tam, gdzie zaplanowałeś, a nie „gdzieś".

📐 Definicje tej lekcji

  • Wyrażenie logiczne — konstrukcja o wartości True/False, zbudowana z porównań i spójników and/or/not.
  • if / elif / else — rozgałęzienie: pierwszy prawdziwy warunek wygrywa, else łapie resztę.
  • % (reszta z dzielenia) — pythonowy zapis mod; r % 4 == 0 czyta się „r dzieli się przez 4".

📌 Najważniejsze w pigułce

  • == pyta, = przypisuje — pomylenie ich to błąd składni, na szczęście głośny.
  • Kaskada if/elif/else wykonuje pierwszy pasujący blok; kolejność warunków to logika, nie estetyka.
  • and wiąże mocniej niż or; nawiasy stawiaj dla ludzi, nie dla interpretera.

🎒 Zadania

  1. Bez komputera: jaką wartość mają wyrażenia dla a = 4, b = 10? (a) a < 5 and b < 5, (b) a < 5 or b < 5, (c) not (a == b), (d) a * 2 <= b <= a * 3.
Wskazówka i odpowiedź

(a) True and False → False. (b) True or False → True. (c) not False → True. (d) Python pozwala łańcuchować porównania jak w matematyce: $8 \le 10 \le 12$ → True. Ten łańcuchowy zapis to rzadkość wśród języków — doceniaj go, ale wiedz, że w wielu innych językach trzeba pisać a*2 <= b and b <= a*3.

  1. Napisz program, który dla trzech długości boków rozstrzyga, czy da się z nich zbudować trójkąt (każdy bok krótszy od sumy dwóch pozostałych). Podaj dane testowe, w tym przypadek brzegowy 1, 2, 3.
Wskazówka i odpowiedź

Warunek: a + b > c and a + c > b and b + c > a. Dane 1, 2, 3: $1+2 = 3$, warunek > fałszywy → „nie" (trójkąt zdegenerowany do odcinka — dlatego w specyfikacji musi być ostra nierówność; gdybyś napisał >=, brzeg by Cię zdradził). Testy: (3,4,5) tak, (1,1,10) nie, (1,2,3) nie.

  1. Sklep daje rabat: 5% od 100 zł, 10% od 300 zł, 15% od 500 zł. Klient za 500 zł ma dostać 15%, nie 5%. Napisz kaskadę i wyjaśnij, dlaczego warunki muszą iść od największego progu.
Wskazówka i odpowiedź
if kwota >= 500:
    rabat = 15
elif kwota >= 300:
    rabat = 10
elif kwota >= 100:
    rabat = 5
else:
    rabat = 0

Gdyby progi szły od najmniejszego, klient za 500 zł spełniłby już pierwszy warunek (>= 100) i kaskada skończyłaby się na 5%. Pierwszy pasujący wygrywa — więc najbardziej wymagające warunki stawiamy na górze. Porównaj z rokiem przestępnym: to ta sama zasada.

🔍 Sprawdź, czy umiesz

  • Przetłumaczyć na Pythona: „pełnoletni albo małoletni z pisemną zgodą".
  • Prześledzić kaskadę if/elif/else dla danych brzegowych.
  • Wyjaśnić, czemu = w warunku to błąd, a == w przypisaniu nie ma sensu.

Ucz się tej jednostki z asystentem