Projekt końcowy: dziennik wyników

Preview Mode

You're viewing this material in preview mode. Sign up to track your progress and access all features.

Projekt końcowy: dziennik wyników
Required In Progress

Projekt końcowy: dziennik wyników

Zbudujesz program, który zapisuje wyniki graczy, pokazuje tabelę i zachowuje dane w pliku JSON. Projekt łączy najważniejsze elementy kursu: dane wejściowe, warunki, pętle, funkcje, listy, słowniki, pliki, moduły i obsługę wyjątków.

Co powinien robić program?

  • pokazywać menu z poleceniami: dodaj wynik, pokaż wyniki i zakończ;
  • pobierać imię gracza oraz liczbę punktów;
  • odrzucać pustą nazwę i wynik mniejszy od zera;
  • przechowywać każdy wpis jako słownik;
  • zapisywać całą listę do pliku scores.json;
  • po ponownym uruchomieniu odczytywać wcześniejsze wyniki;
  • reagować czytelnym komunikatem na błędną liczbę lub uszkodzony plik.

Model danych

Jeden wynik będzie słownikiem, a wszystkie wyniki utworzą listę:

scores = [
    {"name": "Ala", "points": 12},
    {"name": "Jan", "points": 8},
]

Przed dalszą pracą sprawdź, jak odczytać imię pierwszego gracza i jak obliczyć najwyższy wynik.

Etap 1. Menu i dane w pamięci

Zacznij bez pliku. Najpierw doprowadź do działania menu oraz dodawanie wpisów:

scores = []

while True:
    print("\n1. Dodaj wynik")
    print("2. Pokaż wyniki")
    print("3. Zakończ")

    choice = input("Wybierz: ").strip()

    if choice == "1":
        name = input("Imię: ").strip()
        try:
            points = int(input("Punkty: "))
        except ValueError:
            print("Punkty muszą być liczbą całkowitą.")
            continue

        if not name:
            print("Imię nie może być puste.")
        elif points < 0:
            print("Wynik nie może być ujemny.")
        else:
            scores.append({"name": name, "points": points})
            print("Wynik dodany.")
    elif choice == "2":
        for position, score in enumerate(scores, start=1):
            print(f"{position}. {score['name']}: {score['points']}")
    elif choice == "3":
        break
    else:
        print("Wybierz 1, 2 albo 3.")

Uruchom program po każdej niewielkiej zmianie. Sprawdź poprawny wpis, pustą nazwę, ujemny wynik, tekst zamiast liczby i nieznaną opcję menu.

Etap 2. Wydziel funkcje

Gdy pierwsza wersja działa, podziel ją na funkcje o jednej odpowiedzialności:

  • show_menu() wyświetla dostępne polecenia;
  • add_score(scores) pobiera i sprawdza nowy wynik;
  • show_scores(scores) wyświetla tabelę;
  • load_scores(path) odczytuje listę z pliku;
  • save_scores(path, scores) zapisuje listę do pliku.

Przekazuj dane przez parametry i zwracaj wynik przez return. Dzięki temu funkcje można sprawdzać oddzielnie.

Etap 3. Zapis JSON

Utwórz plik storage.py. Umieść w nim funkcje odpowiedzialne za plik:

import json
from pathlib import Path


def load_scores(path):
    if not path.exists():
        return []

    try:
        text = path.read_text(encoding="utf-8")
        return json.loads(text)
    except (OSError, json.JSONDecodeError):
        print("Nie udało się odczytać zapisanych wyników.")
        return []


def save_scores(path, scores):
    text = json.dumps(scores, ensure_ascii=False, indent=2)
    path.write_text(text, encoding="utf-8")

W pliku main.py zaimportuj te funkcje i przygotuj ścieżkę:

from pathlib import Path
from storage import load_scores, save_scores


path = Path("scores.json")
scores = load_scores(path)

Po poprawnym dodaniu wpisu wywołaj save_scores(path, scores). Nie zapisuj danych, które nie przeszły walidacji.

Plan testów

  1. Uruchom program bez pliku scores.json — powinien zacząć z pustą listą.
  2. Dodaj dwa poprawne wyniki i sprawdź ich kolejność.
  3. Wpisz litery zamiast punktów — program powinien kontynuować działanie.
  4. Wpisz pustą nazwę i wynik ujemny — żaden z tych wpisów nie powinien zostać zapisany.
  5. Zamknij program i uruchom go ponownie — wcześniejsze wyniki powinny wrócić.
  6. Celowo uszkodź kopię pliku JSON i sprawdź komunikat błędu. Nie eksperymentuj na ważnych plikach.

Rozszerzenia

Dodawaj tylko jedno rozszerzenie naraz i po każdym powtarzaj testy:

  • sortowanie wyników malejąco przez sorted();
  • pokazywanie najlepszego wyniku przez max();
  • wyszukiwanie wyników wybranego gracza;
  • usuwanie wpisu po numerze;
  • eksport dodatkowej tabeli do CSV.

Typowe pułapki

  • input() zwraca tekst, dlatego punkty wymagają konwersji przez int().
  • Po nieudanej konwersji użyj continue, aby nie korzystać z nieistniejącej wartości.
  • Nie stosuj pustego except; przechwytuj tylko oczekiwane rodzaje błędów.
  • Nie mieszaj kodu obsługi menu z kodem zapisu pliku — osobne funkcje ułatwiają debugowanie.

Kiedy projekt jest ukończony?

Projekt jest gotowy, gdy spełnia wymagania podstawowe, przechodzi wszystkie testy i potrafisz własnymi słowami wyjaśnić przepływ danych: od odpowiedzi użytkownika, przez walidację i listę słowników, aż do pliku JSON.