← Lekcje
Python · lekcja 27

Projekt: gra w zgadywanie liczby

Ostatnia lekcja kursu: składamy w całość to, co już umiecie.

  1. Specyfikacja: co gra dostaje i co ma wypisać
  2. Losowanie liczby modułem random
  3. Pętla while z licznikiem prób i podpowiedziami
  4. Odporność na literówkę: try i except
Rozgrzewka · 3 minuty

Co pamiętacie z poprzedniej lekcji?

  1. Czym różni się sortowanie bąbelkowe od sortowania przez wstawianie?
  2. Dlaczego oba algorytmy sortowania zapisujemy w pętli, a nie jako ciąg osobnych linijek?
  3. Co robi pętla while i jak policzyć w niej, ile razy się wykonała?
Część 1 · Specyfikacja i lista kroków

Zanim napiszemy pierwszą linijkę

Dane: liczba od 1 do 100 wylosowana przez komputer i kolejne liczby wpisywane przez gracza.
Wynik: po każdej próbie podpowiedź „za mało” albo „za dużo”, a po trafieniu liczba prób.

  1. Wylosuj liczbę całkowitą od 1 do 100. Zapamiętaj ją.
  2. Ustaw licznik prób na 0.
  3. Poproś gracza o liczbę.
  4. Jeśli jest mniejsza od wylosowanej, wypisz „za mało”, a jeśli większa, „za dużo”. Wróć do kroku 3.
  5. Gdy liczby są równe, wypisz komunikat o trafieniu i liczbę prób.
Podręcznik Informatyka na czasie 2 (Nowa Era), s. 97–98 (6.3 Tworzymy własne programy użytkowe, specyfikacja i lista kroków)
Część 2 · Moduł random

Komputer losuje liczbę

import random

number = random.randint(1, 100)
print("Wylosowana liczba:", number)
Wylosowana liczba: 60
Wylosowana liczba: 62
Wylosowana liczba: 96

import random wnosi do programu moduł, czyli gotowy zestaw funkcji napisany przez kogoś innego.

random.randint(1, 100) oddaje losową liczbę całkowitą od 1 do 100, razem z obiema granicami. Trzy uruchomienia dały trzy różne liczby.

W praktyce: komputer nie losuje naprawdę. Liczy kolejne liczby z wzoru, który daje ciąg wyglądający na przypadkowy. Dlatego mówi się o generatorze pseudolosowym.

docs.python.org, The Python Tutorial, rozdz. 10.6 (Mathematics)
Część 2 · Pętla i licznik

Pytaj, dopóki nie trafi

number = random.randint(1, 100)
guess = 0
tries = 0

while guess != number:
    guess = int(input("Twoja liczba: "))
    tries = tries + 1
    if guess < number:
        print("Za mało.")
    elif guess > number:
        print("Za dużo.")

print("Trafione! Liczba prób:", tries)
  • guess = 0 to wartość startowa. Wylosowana liczba jest z zakresu 1–100, więc 0 na pewno nie jest trafieniem i pętla rusza.
  • Warunek guess != number czyta się „dopóki liczby są różne”.
  • tries = tries + 1 stoi wewnątrz pętli: rośnie po każdej próbie.
  • Ostatni print nie ma wcięcia, więc wykona się dopiero po wyjściu z pętli.
Podręcznik Informatyka na czasie 2 (Nowa Era), s. 225 (dodatek 7, pętla while, gra w odgadywanie imienia) · docs.python.org, The Python Tutorial, rozdz. 3.2 (First Steps Towards Programming)
Część 2 · if, elif, else

Jedna próba, trzy możliwe drogi

gracz podaje guess porównaj guess z number if guess < number „Za mało.” i pytaj dalej elif guess > number „Za dużo.” i pytaj dalej guess == number koniec pętli, wynik

Trzecia droga nie ma w kodzie żadnego if. Gdy liczby są równe, warunek pętli guess != number przestaje być prawdziwy i pętla po prostu się kończy.

W praktyce: gracz, który za każdym razem podaje środek pozostałego zakresu, trafia liczbę z przedziału 1–100 najpóźniej w siódmej próbie. To wyszukiwanie binarne z lekcji 25.

Podręcznik Informatyka na czasie 2 (Nowa Era), s. 224 (dodatek 7, instrukcja warunkowa) · docs.python.org, The Python Tutorial, rozdz. 4.1 (if Statements)
Część 3 · Błędy wykonania

Gracz wpisuje „osiem”

Funkcja int zamienia napis na liczbę tylko wtedy, gdy napis składa się z cyfr. Napis „osiem” cyfr nie ma, więc Python przerywa program i zgłasza wyjątek ValueError.

Twoja liczba: osiem
Traceback (most recent call last):
  ...
    guess = int(input("Twoja liczba: "))
ValueError: invalid literal for int()
with base 10: 'osiem'

Para try i except przechwytuje taki wyjątek: program pisze własny komunikat i gra toczy się dalej.

text = input("Twoja liczba: ")
try:
    guess = int(text)
    tries = tries + 1
except ValueError:
    print("To nie jest liczba.")

Licznik stoi w bloku try, więc literówka nie zużywa próby.

docs.python.org, The Python Tutorial, rozdz. 8.2 (Exceptions) i 8.3 (Handling Exceptions)
Część 3 · Gotowy program

Wszystko razem w jednym pliku

import random

number = random.randint(1, 100)
guess = 0
tries = 0

print("Zgadnij liczbę od 1 do 100.")
while guess != number:
    text = input("Twoja liczba: ")
    try:
        guess = int(text)
        tries = tries + 1
        if guess < number:
            print("Za mało.")
        elif guess > number:
            print("Za dużo.")
    except ValueError:
        print("To nie jest liczba, wpisz ją cyframi.")

print("Trafione! Liczba prób:", tries)
Zgadnij liczbę od 1 do 100.
Twoja liczba: 50
Za dużo.
Twoja liczba: 25
Za mało.
Twoja liczba: osiem
To nie jest liczba, wpisz ją cyframi.
Twoja liczba: 37
Za mało.
Twoja liczba: 43
Za dużo.
Twoja liczba: 42
Trafione! Liczba prób: 5

Przebieg dla liczby 42. Wpis „osiem” nie zwiększył licznika.

Podręcznik Informatyka na czasie 2 (Nowa Era), s. 224–225 (dodatek 7, instrukcja warunkowa i pętla while) · docs.python.org, The Python Tutorial, rozdz. 8.3 (Handling Exceptions)
Podsumowanie kursu

Skąd wzięła się każda linijka

input i int lekcja 03 if, elif, else lekcje 05 i 06 while i licznik lekcja 07 operatory lekcja 04 import random lekcja 13 try i except lekcja 16 lista kroków lekcja 17

Ani jedna instrukcja w tym programie nie jest nowa. Cały projekt to siedem rzeczy, które ćwiczyliście osobno, ustawione w jednej kolejności.

Ćwiczenie · przy komputerze · 12 minut

Ćwiczenie: Wasza wersja gry

  1. Utwórz plik gra.py, przepisz program ze slajdu i uruchom go dwa razy. Za drugim razem wpisz celowo słowo zamiast liczby. Zapisz, co się stało z licznikiem prób.
  2. Dopisz na końcu programu ocenę wyniku: dla siedmiu prób lub mniej pochwałę, w przeciwnym razie wskazówkę, żeby dzielić zakres na pół. Użyj if i else po pętli.
  3. Dodaj podpowiedź „Jesteś bardzo blisko.”, gdy gracz pomylił się najwyżej o 3. Przyda się funkcja abs z lekcji 4, która podaje odległość dwóch liczb.
Jak to sprawdzić

Uruchom program w terminalu poleceniem python3 gra.py. Jeśli zobaczysz IndentationError, popraw wcięcia: każdy poziom to dokładnie cztery spacje, a linie pod try mają dwa poziomy wcięcia. Jeśli gra nigdy się nie kończy, sprawdź, czy w warunku pętli jest !=, a nie ==.

Sprawdzenie

Trzy pytania na koniec

  1. Dlaczego przed pętlą ustawiamy guess = 0?
  2. Gdzie w programie stoi tries = tries + 1 i dlaczego akurat tam?
  3. Co się stanie, gdy gracz wpisze słowo zamiast liczby, i jak temu zapobiegamy?
Podsumowanie

A jak to wygląda w produkcji?

Na lekcjiW produkcjiStatus
try i except wokół int()Formularz płatności pokazuje „wpisz kwotę cyframi” zamiast strony błędu, gdy ktoś wpisze tekst w pole kwotystandard w firmach
while, dopóki warunek prawdziwyAplikacja ponawia wysyłkę wiadomości, dopóki serwer nie potwierdzi odbiorucodziennie
Licznik próbBank blokuje logowanie po trzeciej błędnej próbie hasłacodziennie
random.randintSklep losuje zwycięzcę konkursu, a gra mobilna losuje nagrodę ze skrzynkicodziennie