Przejdź do treści
INF.04Styczeń 2024180 min

INF.04 styczeń 2024 — walidacja numeru PESEL i aplikacja paszportowa

Rozbiór arkusza INF.04 ze stycznia 2024: konsolowy walidator numeru PESEL z cyfrą kontrolną, desktopowa aplikacja do danych paszportowych i dokumentacja. Plan na 180 minut i gotowe rozwiązania.

Oryginalny arkusz CKE (PDF)

Pobierz plik źródłowy i rozwiąż go samodzielnie przed sprawdzeniem rozwiązań.

Pobierz PDF

Arkusz, w którym wszystko rozstrzyga jedno mnożenie przez wagi

Styczeń 2024 w kwalifikacji INF.04 to zestaw pozornie łagodny: prosty program konsolowy, jedno okienko z kontrolkami i kilka zrzutów ekranu. Pułapka siedzi w miejscu, którego nikt się nie spodziewa — w czterech linijkach liczących cyfrę kontrolną numeru PESEL. Kto pomyli wagi, pomyli kolejność cyfr albo zapomni o przypadku, w którym reszta z dzielenia wynosi zero, ten dostaje program, który kompiluje się i działa, a mimo to zwraca zły wynik. Egzaminator wpisuje jeden numer testowy i rezultat przepada.

Jak korzystać z tego rozbioru

Każda część zaczyna się od karty „Czego wymaga arkusz" — widocznej od razu. Rozwiązanie jest schowane pod przyciskiem. Zanim je odsłonisz, napisz kod samodzielnie. Na egzaminie nie będziesz czytać cudzego rozwiązania, tylko produkować własne z głowy, w 180 minut, przy trzech zadaniach naraz.

1

Metryka arkusza i klucz oceniania

Dane arkusza
  • Kwalifikacja: INF.04 — projektowanie, programowanie i testowanie aplikacji
  • Sesja: styczeń 2024, zadanie 01, wersja arkusza SG
  • Czas: 180 minut, plus 10 minut na zapoznanie się z zadaniem (niewliczane)
  • Próg zdania: 75% punktów
  • Temat: walidator numeru PESEL w konsoli oraz okienkowy formularz danych paszportowych
  • Konto systemowe: Egzamin, bez hasła
Oceniane rezultaty

Arkusz wymienia cztery rezultaty. To dosłownie lista, po której idzie egzaminator:

  1. implementacja, kompilacja, uruchomienie programu
  2. aplikacja konsolowa
  3. aplikacja desktopowa
  4. dokumentacja aplikacji

Zwróć uwagę na rezultat pierwszy: on nie dotyczy treści kodu, tylko tego, czy projekt w ogóle się kompiluje i uruchamia. Program, który nie przechodzi kompilacji, przewraca dwa rezultaty naraz.

Co musi znaleźć się na płycie

Folder nazwany numerem zdającego, a w nim dokładnie trzy podfoldery. Nazwy są narzucone przez arkusz — literówka w nazwie folderu to realna strata:

PESEL/
├── konsola/
│      konsola.zip          spakowany caly projekt aplikacji konsolowej
│      main.cpp             plik zrodlowy, ktory byl modyfikowany
│      main.exe             plik uruchomieniowy, jesli istnieje
├── desktopowa/
│      desktopowa.zip       spakowany caly projekt aplikacji desktopowej
│      Form1.cs             logika aplikacji
│      Form1.Designer.cs    interfejs uzytkownika
│      Paszport.exe         plik uruchomieniowy, jesli istnieje
└── dokumentacja/
     egzamin.odt          dokument ze zrzutami i opisem narzedzi
     konsola1.png         zrzuty aplikacji konsolowej
     konsola2.png
     desktop1.png         zrzuty aplikacji desktopowej
     desktop2.png
     desktop3.png

Wszędzie, gdzie widzisz PESEL, wchodzi Twój własny numer zdającego. W archiwum ZIP ma być cały folder projektu, a obok, luzem, tylko te pliki źródłowe, których treść zmieniałeś.

Dwa zdania, które łatwo przeoczyć: archiwum materialy.7z z pulpitu jest zabezpieczone hasłem p@szporTy% — bez rozpakowania go nie ma czym testować aplikacji desktopowej. A tytuł okna ma brzmieć „Wprowadzenie danych do paszportu. Wykonał: " i dopiero za tym numer zdającego. To jeden z najczęściej gubionych, a najtańszych punktów w całym arkuszu.

2

Plan czasowy na 180 minut

Trzy części, cztery rezultaty, jeden zegar. Konsola jest najmniejsza objętościowo, ale to od niej zależy dokumentacja (komentarz ma być w kodzie konsolowym), więc robisz ją pierwszą. Desktopowa zjada najwięcej czasu, bo dochodzi klikanie w projektancie formularzy. Dokumentacja jest za darmo — o ile zostawisz na nią czas, a nie doklejasz jej w ostatnich trzech minutach.

EtapCzasRezultatUwagi
Foldery, rozpakowanie materialy.7z10 minobejrzyj nazwy plików graficznych, zanim zaczniesz kodować
Konsola: obie funkcje i program główny45 min1 i 2najgęstszy punktowo etap, rób go wypoczęty
Komentarz dokumentacyjny + zrzuty konsoli10 min4rób od razu, póki konsola jest otwarta
Desktop: interfejs, kontrolki, kolory40 min3sam wygląd jest punktowany niezależnie od logiki
Desktop: zdarzenia Leave i klik OK35 min3najpierw komunikat OK, potem podmiana obrazów
Zrzuty desktopowe i dokument egzamin20 min4tyle zrzutów, ile interakcji ma aplikacja
Archiwa ZIP, porządki, nagranie i sprawdzenie płyty20 minwszystkierezerwa, której nigdy nie tniesz

Kolejność, która ratuje egzamin: gdy po 100 minutach aplikacja desktopowa nadal nie działa, przestań ją naprawiać i przejdź do dokumentacji. Rezultat „dokumentacja" można zdobyć w komplecie nawet dla aplikacji, która się nie uruchamia — arkusz wprost pisze, że gdy program nie kompiluje się, na zrzucie ma być okno ze spisem błędów. Puste pole „dokumentacja" to strata jednego z czterech rezultatów za coś, co zajmuje kwadrans.

3

Część I: aplikacja konsolowa, walidacja numeru PESEL

Czego wymaga arkusz
  • Język: obiektowy, zgodny z zainstalowanym na stanowisku — C++, C#, Java albo Python.
  • Przechowywanie numeru: zmienna tekstowa albo tablica 11 liczb całkowitych lub znaków. Zmienna ma być zainicjowana numerem zdającego, a przy jego braku numerem 55030101193.
  • Funkcja płci: osobna funkcja zwracająca typ znakowy — 'K' dla kobiety, 'M' dla mężczyzny. Decyduje 10. (przedostatnia) cyfra: parzysta to kobieta, nieparzysta to mężczyzna.
  • Funkcja sumy kontrolnej: osobna funkcja zwracająca wartość logiczną — true przy zgodności, false w przeciwnym razie.
  • Parametr obu funkcji: zmienna przechowująca numer PESEL. Jeden parametr, nic więcej.
  • Program główny: wczytuje numer z klawiatury, wypisuje „Kobieta" albo „Mężczyzna" oraz informację o zgodności lub niezgodności sumy kontrolnej.
  • Algorytm cyfry kontrolnej: wagi 1, 3, 7, 9, 1, 3, 7, 9, 1, 3 dla dziesięciu pierwszych cyfr; suma iloczynów to S; M = S modulo 10; R = 0 gdy M = 0, w przeciwnym razie R = 10 − M; R musi być równe jedenastej cyfrze.

Napisz obie funkcje sam, bez zaglądania. Potem sprawdź się na numerze 55030101193 — powinien wyjść mężczyzna i zgodna suma kontrolna.

Pokaż rozwiązanieCyfra kontrolna krok po kroku na liczbach

Weźmy numer podany w arkuszu jako zapasowy: 55030101193. Pierwsze dziesięć cyfr to dane, jedenasta — czyli końcowa 3 — to cyfra kontrolna, którą będziemy odtwarzać.

PozycjaCyfraWagaIloczyn
1515
25315
3070
43927
5010
6133
7070
8199
9111
109327
S — suma iloczynów87
  1. S = 5 + 15 + 0 + 27 + 0 + 3 + 0 + 9 + 1 + 27 = 87
  2. M = 87 modulo 10 = 7
  3. M nie jest zerem, więc R = 10 − 7 = 3
  4. Jedenasta cyfra numeru to 3. R = 3, zgadza się — numer jest poprawny.

Płeć: dziesiąta cyfra tego numeru to 9. Dziewięć jest nieparzyste, więc funkcja zwraca 'M', a program wypisuje „Mężczyzna".

Drugi przykład — po co w ogóle ten warunek na zero

Weź numer 44051401380. Iloczyny: 4, 12, 0, 45, 1, 12, 0, 9, 3, 24. Suma S = 110, więc M = 110 modulo 10 = 0. Gdybyś liczył R zawsze wzorem 10 − M, wyszłoby 10 — a to nie jest cyfra i porównanie z jedenastą cyfrą numeru (0) nigdy się nie powiedzie. Właśnie po to arkusz osobno opisuje krok czwarty: przy M = 0 przypisujemy R = 0 i numer jest poprawny.

Gdzie się traci punkty: najczęstszy błąd to pominięcie warunku na M = 0 — program działa dla dziewięciu numerów na dziesięć i wywraca się na tym dziesiątym. Drugi klasyk to indeksowanie: cyfra numer 1 z arkusza to indeks 0 w tablicy, a dziesiąta cyfra (płeć) to indeks 9, nie 10. Trzeci: mnożenie znaku zamiast cyfry — bez odjęcia znaku zera dostajesz kody ASCII i sumę rzędu tysiąca.

Pokaż rozwiązanieKompletny program w C++ — obie funkcje i main

Cały plik main.cpp — przepisz, skompiluj, uruchom. Komentarz dokumentacyjny nad pierwszą funkcją realizuje jednocześnie wymóg z części III arkusza.

#include <iostream>
#include <string>
using namespace std;

/**********************************************
nazwa funkcji:       sprawdzPlec
opis funkcji:        ustala plec osoby na podstawie 10. cyfry numeru PESEL
parametry:           pesel - lancuch znakow z 11-cyfrowym numerem PESEL
zwracany typ i opis: char - 'K' dla kobiety, 'M' dla mezczyzny
autor:               PESEL
***********************************************/
char sprawdzPlec(string pesel)
{
  int cyfraPlci = pesel[9] - '0';   // 10. cyfra, indeks 9

  if (cyfraPlci % 2 == 0)
      return 'K';
  else
      return 'M';
}

/**********************************************
nazwa funkcji:       sprawdzSumeKontrolna
opis funkcji:        weryfikuje cyfre kontrolna numeru PESEL wagami 1,3,7,9...
parametry:           pesel - lancuch znakow z 11-cyfrowym numerem PESEL
zwracany typ i opis: bool - true gdy suma kontrolna zgodna, false gdy niezgodna
autor:               PESEL
***********************************************/
bool sprawdzSumeKontrolna(string pesel)
{
  int wagi[10] = {1, 3, 7, 9, 1, 3, 7, 9, 1, 3};
  int S = 0;

  for (int i = 0; i < 10; i++)
  {
      int cyfra = pesel[i] - '0';
      S = S + cyfra * wagi[i];
  }

  int M = S % 10;
  int R;

  if (M == 0)
      R = 0;
  else
      R = 10 - M;

  int cyfraKontrolna = pesel[10] - '0';

  return R == cyfraKontrolna;
}

int main()
{
  // zmienna zainicjowana numerem zdajacego (tu: numer zapasowy z arkusza)
  string pesel = "55030101193";

  cout << "Program sprawdzajacy poprawnosc numeru PESEL" << endl;
  cout << "Podaj numer PESEL (11 cyfr): ";
  cin >> pesel;

  if (pesel.length() != 11)
  {
      cout << "Blad: numer PESEL musi miec dokladnie 11 cyfr." << endl;
      return 1;
  }

  char plec = sprawdzPlec(pesel);

  if (plec == 'K')
      cout << "Plec: Kobieta" << endl;
  else
      cout << "Plec: Mezczyzna" << endl;

  if (sprawdzSumeKontrolna(pesel))
      cout << "Suma kontrolna zgodna - numer PESEL jest poprawny." << endl;
  else
      cout << "Suma kontrolna niezgodna - numer PESEL jest bledny." << endl;

  return 0;
}
Dlaczego akurat tak
  • pesel[i] - '0' zamienia znak na cyfrę. Znak „5" ma kod 53, znak „0" ma 48 — różnica daje 5. Bez tego odejmowania cała suma jest bez sensu.
  • Tablica wagi jest zapisana dokładnie w kolejności z arkusza. Nie licz wag „w pamięci" wewnątrz pętli — to najprostsza droga do pomyłki.
  • Zmienne nazwane S, M, R celowo — arkusz żąda nazw „zgodnych z przedstawionym algorytmem", a algorytm operuje właśnie tymi literami. Egzaminator ma je znaleźć bez czytania całego kodu.
  • Obie funkcje mają dokładnie jeden parametr — zmienną z numerem. Dodanie drugiego (np. długości) łamie wymaganie wprost zapisane w arkuszu.
  • Sprawdzenie długości w main to nie kaprys: bez niego wpisanie krótszego numeru wychodzi poza łańcuch i program potrafi się wywalić na oczach egzaminatora, przewracając rezultat „uruchomienie programu".
Polskie znaki w konsoli

Arkusz żąda napisów „Kobieta" i „Mężczyzna". Jeśli chcesz mieć w wyniku prawdziwe „ż", w systemie Windows dopisz na początku funkcji main jedną linię:

#include <windows.h>
// ... a w main, jako pierwsza instrukcja:
SetConsoleOutputCP(65001);   // wlacza UTF-8 w oknie konsoli

Jeżeli po tym zabiegu w konsoli nadal sypią się krzaki, wróć do wersji bez ogonków. Czytelny napis „Mezczyzna" jest bezpieczniejszy niż nieczytelne bajty na zrzucie ekranu, który idzie do dokumentacji.

Gdzie się traci punkty: całą logikę wrzuconą do main. Arkusz mówi „w osobnej funkcji" dwa razy — to nie jest sugestia stylistyczna, tylko warunek zaliczenia. Drugi klasyk: funkcja płci zwracająca łańcuch „Kobieta" zamiast znaku. Arkusz żąda typu znakowego o wartości 'K' lub 'M', a tłumaczenie na pełne słowo należy do programu głównego.

Pokaż rozwiązanieTen sam program w Pythonie — wariant skrócony

Jeśli na stanowisku masz tylko Pythona, logika jest identyczna — zmienia się wyłącznie składnia. Plik pesel.py:

WAGI = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3]


def sprawdz_plec(pesel):
  """
  nazwa funkcji:       sprawdz_plec
  opis funkcji:        ustala plec na podstawie 10. cyfry numeru PESEL
  parametry:           pesel - napis z 11-cyfrowym numerem PESEL
  zwracany typ i opis: str - znak 'K' dla kobiety, 'M' dla mezczyzny
  autor:               PESEL
  """
  cyfra_plci = int(pesel[9])
  if cyfra_plci % 2 == 0:
      return 'K'
  return 'M'


def sprawdz_sume_kontrolna(pesel):
  """
  nazwa funkcji:       sprawdz_sume_kontrolna
  opis funkcji:        weryfikuje cyfre kontrolna numeru PESEL
  parametry:           pesel - napis z 11-cyfrowym numerem PESEL
  zwracany typ i opis: bool - True gdy suma zgodna, False gdy niezgodna
  autor:               PESEL
  """
  S = 0
  for i in range(10):
      S = S + int(pesel[i]) * WAGI[i]

  M = S % 10

  if M == 0:
      R = 0
  else:
      R = 10 - M

  return R == int(pesel[10])


# zmienna zainicjowana numerem zdajacego
pesel = "55030101193"

print("Program sprawdzajacy poprawnosc numeru PESEL")
pesel = input("Podaj numer PESEL (11 cyfr): ")

if len(pesel) != 11 or not pesel.isdigit():
  print("Blad: numer PESEL musi skladac sie z 11 cyfr.")
else:
  if sprawdz_plec(pesel) == 'K':
      print("Plec: Kobieta")
  else:
      print("Plec: Mezczyzna")

  if sprawdz_sume_kontrolna(pesel):
      print("Suma kontrolna zgodna - numer PESEL jest poprawny.")
  else:
      print("Suma kontrolna niezgodna - numer PESEL jest bledny.")
Trzy zestawy testowe
WejściePłećSuma kontrolna
55030101193Mężczyznazgodna (S=87, M=7, R=3)
02070803628Kobietazgodna (S=132, M=2, R=8)
55030101194Mężczyznaniezgodna — celowo zepsuta ostatnia cyfra

Trzeci wiersz jest najważniejszy przy testach: sprawdza, czy program potrafi powiedzieć „niezgodna". Program, który zawsze zwraca true, przechodzi dwa pierwsze testy i wygląda na działający.

4

Część II: aplikacja desktopowa

Czego wymaga arkusz
Wygląd okna
  • Tytuł okna: „Wprowadzenie danych do paszportu. Wykonał: " i numer zdającego.
  • Trzy pola edycyjne poprzedzone etykietami „Numer", „Imię", „Nazwisko".
  • Grupa „Kolor oczu" z trzema polami wyboru: „niebieskie", „zielone", „piwne". Pierwsze zaznaczone domyślnie, jednocześnie może być zaznaczone tylko jedno.
  • Przycisk o treści „OK".
  • Dwa obrazy o tej samej wysokości — w oryginale 180. Startowo 000-zdjecie.jpg i 000-odcisk.jpg.
  • Tło okna: CadetBlue (#5F9EA0). Tło pól edycyjnych i przycisku: Azure (#F0FFFF).
Działanie
  • Po opuszczeniu pola „Numer": oba obrazy zmieniają się na pliki <numer>-zdjecie.jpg oraz <numer>-odcisk.jpg. Dla numeru nieodpowiadającego żadnemu plikowi obraz nie jest wyświetlany.
  • Po kliknięciu „OK", gdy pola wypełnione: komunikat o treści „<imie> <nazwisko> kolor oczu <kolor>".
  • Po kliknięciu „OK", gdy brakuje imienia lub nazwiska: komunikat „Wprowadź dane".
  • Materiały graficzne pochodzą z archiwum materialy.7z (hasło p@szporTy%) i trzeba przetestować aplikację na wszystkich.

Zbuduj formularz sam w swoim środowisku, uruchom go i dopiero potem porównaj obsługę zdarzeń z rozwiązaniem.

Pokaż rozwiązanieSzkielet klasy formularza i obsługa zdarzeń w C#

Aplikacja konsolowa była w C++, ale okienkową najszybciej złożysz w C# Windows Forms — dostajesz projektanta formularzy, a arkusz pozwala na inny język w każdej części (w dokumentacji wymieniasz wtedy oba). Poniżej cały plik Form1.cs; kontrolki wstawiasz myszą w projektancie i nadajesz im widoczne niżej nazwy.

using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;

namespace Paszport
{
  public partial class Form1 : Form
  {
      // folder z obrazami wypakowanymi z materialy.7z
      private readonly string folderObrazow =
          Path.Combine(Application.StartupPath, "obrazy");

      public Form1()
      {
          InitializeComponent();
          UstawWyglad();
          ZaladujObrazy("000");
      }

      private void UstawWyglad()
      {
          this.Text = "Wprowadzenie danych do paszportu. Wykonal: PESEL";
          this.BackColor = Color.CadetBlue;

          textBoxNumer.BackColor = Color.Azure;
          textBoxImie.BackColor = Color.Azure;
          textBoxNazwisko.BackColor = Color.Azure;
          buttonOK.BackColor = Color.Azure;

          radioNiebieskie.Checked = true;

          pictureBoxZdjecie.Height = 180;
          pictureBoxOdcisk.Height = 180;
          pictureBoxZdjecie.SizeMode = PictureBoxSizeMode.Zoom;
          pictureBoxOdcisk.SizeMode = PictureBoxSizeMode.Zoom;
      }

      /**********************************************
      nazwa funkcji:       ZaladujObraz
      opis funkcji:        wstawia obraz z pliku do kontrolki lub czysci ja,
                           gdy plik o podanej nazwie nie istnieje
      parametry:           pole - kontrolka PictureBox,
                           nazwaPliku - nazwa pliku graficznego
      zwracany typ i opis: void - funkcja nie zwraca wartosci
      autor:               PESEL
      ***********************************************/
      private void ZaladujObraz(PictureBox pole, string nazwaPliku)
      {
          string sciezka = Path.Combine(folderObrazow, nazwaPliku);

          if (File.Exists(sciezka))
          {
              // wczytanie przez tablice bajtow nie blokuje pliku na dysku
              byte[] dane = File.ReadAllBytes(sciezka);
              pole.Image = Image.FromStream(new MemoryStream(dane));
          }
          else
          {
              pole.Image = null;
          }
      }

      private void ZaladujObrazy(string numer)
      {
          ZaladujObraz(pictureBoxZdjecie, numer + "-zdjecie.jpg");
          ZaladujObraz(pictureBoxOdcisk, numer + "-odcisk.jpg");
      }

      // zdarzenie Leave pola edycyjnego "Numer"
      private void textBoxNumer_Leave(object sender, EventArgs e)
      {
          string numer = textBoxNumer.Text.Trim();
          ZaladujObrazy(numer);
      }

      private string PobierzKolorOczu()
      {
          if (radioZielone.Checked) return "zielone";
          if (radioPiwne.Checked) return "piwne";
          return "niebieskie";
      }

      // zdarzenie Click przycisku "OK"
      private void buttonOK_Click(object sender, EventArgs e)
      {
          string imie = textBoxImie.Text.Trim();
          string nazwisko = textBoxNazwisko.Text.Trim();

          if (imie.Length == 0 || nazwisko.Length == 0)
          {
              MessageBox.Show("Wprowadz dane");
              return;
          }

          MessageBox.Show(imie + " " + nazwisko +
                          " kolor oczu " + PobierzKolorOczu());
      }
  }
}
Nazwy kontrolek w projektancie
KontrolkaNazwaUstawienia
TextBoxtextBoxNumerBackColor Azure, zdarzenie Leave
TextBox × 2textBoxImie, textBoxNazwiskoBackColor Azure
GroupBoxgroupBoxKolorOczuText „Kolor oczu"
RadioButton × 3radioNiebieskie, radioZielone, radioPiwnewewnątrz GroupBox, pierwszy Checked
ButtonbuttonOKText „OK", BackColor Azure
PictureBox × 2pictureBoxZdjecie, pictureBoxOdciskHeight 180, SizeMode Zoom
Dlaczego akurat tak
  • Zdarzenie Leave, nie TextChanged. Arkusz mówi „po opuszczeniu pola edycyjnego". TextChanged strzelałby przy każdym wciśniętym klawiszu i próbował wczytać plik „3-zdjecie.jpg" w trakcie wpisywania „333".
  • Trzy przyciski radiowe w jednym GroupBox same z siebie wykluczają się nawzajem. To realizuje wymóg „w grupie może być jednocześnie zaznaczone jedno pole" bez ani jednej linii kodu — pod warunkiem że naprawdę leżą wewnątrz grupy, a nie obok niej na formularzu.
  • Sprawdzenie File.Exists realizuje zdanie „w przypadku wpisania numeru, który nie odpowiada żadnemu plikowi, obraz nie jest wyświetlany". Bez tego aplikacja rzuci wyjątkiem i się zamknie — a to już strata rezultatu „uruchomienie programu".
  • Wczytanie przez tablicę bajtów zamiast Image.FromFile: to drugie blokuje plik na dysku, więc przy powtórnym wpisaniu tego samego numeru dostajesz błąd dostępu. Klasyczna pułapka podczas testów na wszystkich obrazach z archiwum.
  • SizeMode Zoom dopasowuje zdjęcia o różnych proporcjach do ustalonej wysokości bez rozciągania. Arkusz wymaga, żeby oba obrazy miały tę samą wysokość.

Gdzie się traci punkty: komunikat sklejony z przecinkami albo dwukropkami. Arkusz podaje wzorzec dosłownie: imię, spacja, nazwisko, spacja, słowa „kolor oczu", spacja, kolor — bez znaków interpunkcyjnych. Drugi klasyk to walidacja po długości pola bez Trim(): sama spacja przechodzi jako „wpisane imię". Trzeci: zapomniany kolor tła przycisku — pola edycyjne mają Azure i przycisk też.

Pokaż rozwiązanieWariant w Pythonie — tkinter, ta sama logika

Gdy na stanowisku nie ma Visual Studio, ten sam formularz składasz w tkinterze. Zdarzenie „opuszczenie pola" nazywa się tu <FocusOut>, a wyłączność pól wyboru daje wspólna zmienna StringVar.

import os
import tkinter as tk
from tkinter import messagebox
from PIL import Image, ImageTk

FOLDER = "obrazy"
WYSOKOSC = 180


class Paszport(tk.Tk):
  def __init__(self):
      super().__init__()
      self.title("Wprowadzenie danych do paszportu. Wykonal: PESEL")
      self.configure(bg="#5F9EA0")

      self.numer = tk.Entry(self, bg="#F0FFFF")
      self.imie = tk.Entry(self, bg="#F0FFFF")
      self.nazwisko = tk.Entry(self, bg="#F0FFFF")
      self.kolor = tk.StringVar(value="niebieskie")

      tk.Label(self, text="Numer", bg="#5F9EA0").grid(row=0, column=0)
      self.numer.grid(row=0, column=1)
      tk.Label(self, text="Imie", bg="#5F9EA0").grid(row=1, column=0)
      self.imie.grid(row=1, column=1)
      tk.Label(self, text="Nazwisko", bg="#5F9EA0").grid(row=2, column=0)
      self.nazwisko.grid(row=2, column=1)

      grupa = tk.LabelFrame(self, text="Kolor oczu", bg="#5F9EA0")
      grupa.grid(row=3, column=0, columnspan=2)
      for kolor in ("niebieskie", "zielone", "piwne"):
          tk.Radiobutton(grupa, text=kolor, value=kolor,
                         variable=self.kolor, bg="#5F9EA0").pack(anchor="w")

      tk.Button(self, text="OK", bg="#F0FFFF",
                command=self.klik_ok).grid(row=4, column=0, columnspan=2)

      self.zdjecie = tk.Label(self, bg="#5F9EA0")
      self.odcisk = tk.Label(self, bg="#5F9EA0")
      self.zdjecie.grid(row=0, column=2, rowspan=5)
      self.odcisk.grid(row=0, column=3, rowspan=5)

      self.numer.bind("<FocusOut>", self.opuszczenie_numeru)
      self.zaladuj_obrazy("000")

  def zaladuj_obraz(self, etykieta, nazwa_pliku):
      sciezka = os.path.join(FOLDER, nazwa_pliku)
      if os.path.exists(sciezka):
          obraz = Image.open(sciezka)
          skala = WYSOKOSC / obraz.height
          obraz = obraz.resize((int(obraz.width * skala), WYSOKOSC))
          etykieta.zdjecie = ImageTk.PhotoImage(obraz)
          etykieta.configure(image=etykieta.zdjecie)
      else:
          etykieta.configure(image="")

  def zaladuj_obrazy(self, numer):
      self.zaladuj_obraz(self.zdjecie, numer + "-zdjecie.jpg")
      self.zaladuj_obraz(self.odcisk, numer + "-odcisk.jpg")

  def opuszczenie_numeru(self, zdarzenie):
      self.zaladuj_obrazy(self.numer.get().strip())

  def klik_ok(self):
      imie = self.imie.get().strip()
      nazwisko = self.nazwisko.get().strip()
      if imie == "" or nazwisko == "":
          messagebox.showinfo("Informacja", "Wprowadz dane")
          return
      messagebox.showinfo("Informacja",
                          imie + " " + nazwisko +
                          " kolor oczu " + self.kolor.get())


Paszport().mainloop()

Uwaga techniczna: w tkinterze obraz trzeba przypisać do atrybutu etykiety (etykieta.zdjecie), bo inaczej odśmiecacz pamięci go usunie i w oknie zobaczysz puste miejsce. To jeden z tych błędów, których nie widać w kodzie — aplikacja działa, a obrazy „migają" i znikają.

5

Część III: dokumentacja i zrzuty ekranu

Czego wymaga arkusz
  • Komentarz nad dowolną funkcją aplikacji konsolowej, według wzoru z listingu 1: nazwa funkcji, opis funkcji, parametry, zwracany typ i opis, autor (numer zdającego). Komentarz może stać nad funkcją albo pod jej nagłówkiem, wieloliniowy lub złożony z kilku jednoliniowych.
  • Zrzuty ekranu obejmujące cały obszar monitora z widocznym paskiem zadań. Na zrzucie ma być okno z wynikiem działania programu oraz otwarte środowisko programistyczne z projektem lub terminal z kompilacją.
  • Tyle zrzutów, ile interakcji podejmuje aplikacja — stan początkowy, po wpisaniu numeru i opuszczeniu kontrolki, po wciśnięciu OK itd.
  • Nazwy plików: konsola1, konsola2, ... oraz desktop1, desktop2, ...
  • Dokument w edytorze tekstu pakietu biurowego, nazwany egzamin, zawierający podpisane zrzuty oraz nazwę systemu operacyjnego, nazwy środowisk programistycznych i nazwy języków programowania.

Spisz sam listę zrzutów, które musisz zrobić w tym zadaniu — potem sprawdź, czy niczego nie pominąłeś.

Pokaż rozwiązanieWzór komentarza, lista zrzutów i zawartość pliku egzamin
Komentarz dokumentacyjny

Arkusz podaje wzór bez znaków otwarcia i zamknięcia komentarza, bo te różnią się między językami. W C++ i C# obudowujesz go ukośnikiem z gwiazdką, w Pythonie potrójnym cudzysłowem. Wystarczy jedna udokumentowana funkcja, ale nic nie kosztuje udokumentowanie obu:

/**********************************************
nazwa funkcji:       sprawdzSumeKontrolna
opis funkcji:        sprawdza zgodnosc cyfry kontrolnej numeru PESEL,
                   mnozac dziesiec pierwszych cyfr przez wagi
                   1,3,7,9,1,3,7,9,1,3 i porownujac wynik
                   z jedenasta cyfra numeru
parametry:           pesel - lancuch znakow z 11-cyfrowym numerem PESEL
zwracany typ i opis: bool - true gdy suma kontrolna jest zgodna,
                   false gdy numer jest bledny
autor:               PESEL
***********************************************/

Liczba gwiazdek jest dowolna — arkusz zaznacza to wprost. Nie jest natomiast dowolny zestaw pięciu pozycji: brak którejkolwiek z nich (najczęściej wypada „zwracany typ i opis") to niepełny rezultat. W miejsce PESEL wpisujesz swój numer zdającego.

Minimalny komplet zrzutów
PlikCo ma być widoczne
konsola1okno programu z wynikiem dla poprawnego numeru plus otwarte IDE z kodem
konsola2wynik dla numeru z błędną cyfrą kontrolną — „suma niezgodna"
desktop1stan początkowy okna, obrazy 000-zdjecie i 000-odcisk
desktop2stan po wpisaniu numeru i opuszczeniu pola — podmienione obrazy
desktop3okno komunikatu po kliknięciu OK z kompletem danych
desktop4komunikat „Wprowadź dane" przy pustym imieniu lub nazwisku

Warto dorzucić piąty zrzut desktopowy: numer, który nie ma odpowiadających plików (np. 444) i puste miejsca po obrazach. To osobna interakcja opisana w arkuszu, więc osobny dowód, że aplikacja ją obsługuje.

Szkielet dokumentu egzamin
Dokumentacja aplikacji - PESEL

Narzedzia wykorzystane podczas egzaminu
System operacyjny:            Windows 10 Education 64-bit
Srodowiska programistyczne:   Code::Blocks 20.03,
                              Microsoft Visual Studio 2022 Community
Jezyki programowania:         C++, C#
Edytor tekstu:                LibreOffice Writer

Aplikacja konsolowa
[zrzut konsola1]
Podpis: Obliczenie plci i sumy kontrolnej dla poprawnego numeru PESEL
[zrzut konsola2]
Podpis: Komunikat o niezgodnej sumie kontrolnej

Aplikacja desktopowa
[zrzut desktop1]
Podpis: Stan poczatkowy aplikacji z obrazami 000
[zrzut desktop2]
Podpis: Podmiana obrazow po opuszczeniu pola Numer
[zrzut desktop3]
Podpis: Komunikat po wybraniu przycisku OK
[zrzut desktop4]
Podpis: Komunikat o braku danych

Gdzie się traci punkty: kadrowany zrzut samego okna programu. Arkusz żąda całego obszaru ekranu z widocznym paskiem zadań — wycięcie okna dyskwalifikuje zrzut, choćby wynik był idealny. Drugi klasyk: zrzuty w folderze, ale niewstawione do dokumentu, albo wstawione bez podpisów. Trzeci: pominięta lista narzędzi — trzy linijki tekstu, które są osobnym wymaganiem arkusza.

6

Jak to ocenia egzaminator

Egzaminator nie czyta kodu linijka po linijce. Uruchamia to, co zostawiłeś na płycie, wpisuje własne dane testowe i patrzy, czy zachowanie zgadza się z arkuszem. Dopiero potem zagląda do źródeł — żeby sprawdzić rzeczy, których nie widać z zewnątrz: czy funkcje są osobne, czy mają jeden parametr, czy komentarz dokumentacyjny jest kompletny.

Sprawdzane z zewnątrz
  • Czy projekt się kompiluje i uruchamia (osobny rezultat).
  • Czy dla podanego numeru wychodzi właściwa płeć.
  • Czy program rozróżnia numer poprawny od błędnego.
  • Czy tytuł okna zawiera numer zdającego.
  • Czy kolory tła zgadzają się z CadetBlue i Azure.
  • Czy obrazy podmieniają się po opuszczeniu pola „Numer".
  • Czy komunikat po OK ma dokładnie żądaną treść.
Sprawdzane w źródłach i na płycie
  • Czy płeć i suma kontrolna są w osobnych funkcjach.
  • Czy typ zwracany zgadza się z opisem: znak i wartość logiczna.
  • Czy funkcje przyjmują jeden parametr z numerem PESEL.
  • Czy zmienna z numerem jest zainicjowana.
  • Czy nazwy zmiennych są znaczące i zgodne z algorytmem.
  • Czy komentarz zawiera wszystkie pięć pozycji z listingu 1.
  • Czy struktura folderów i archiwa ZIP są zgodne z opisem.

Najdroższy pojedynczy błąd tego arkusza: nienagrana albo nieczytelna płyta. Nie ma znaczenia, jak dobry jest kod na dysku stanowiska — oceniane jest to, co znajdzie się na nośniku. Nagraj płytę najpóźniej na 15 minut przed końcem, a potem otwórz ją ponownie i sprawdź, czy foldery naprawdę się zapisały.

7

Checklista przed oddaniem

  • Folder nazwany numerem zdającego, a w nim podfoldery konsola, desktopowa, dokumentacja.
  • Archiwa konsola.zip i desktopowa.zip zawierają cały folder projektu, nie same pliki źródłowe.
  • Obok archiwów leżą luzem modyfikowane pliki źródłowe oraz plik uruchomieniowy, jeśli powstał.
  • Program konsolowy przetestowany na numerze poprawnym i na numerze z zepsutą cyfrą kontrolną — komunikaty są różne.
  • Sprawdzony przypadek M = 0, czyli numer, dla którego suma iloczynów kończy się zerem.
  • Płeć zwracana jako znak 'K' lub 'M', a napisy „Kobieta" i „Mężczyzna" tworzy program główny.
  • Obie funkcje mają dokładnie jeden parametr i są zdefiniowane poza main.
  • Tytuł okna desktopowego zawiera numer zdającego po dwukropku.
  • Tło okna CadetBlue, tła pól edycyjnych i przycisku Azure — sprawdzone wzrokowo, nie tylko w kodzie.
  • Domyślnie zaznaczone pole „niebieskie", a zaznaczenie jednego koloru odznacza pozostałe.
  • Oba obrazy mają tę samą wysokość i podmieniają się po opuszczeniu pola „Numer".
  • Numer bez odpowiadających plików (np. 444) nie wywala aplikacji — obrazy po prostu znikają.
  • Aplikacja przetestowana na wszystkich obrazach z archiwum materialy.7z.
  • Komentarz dokumentacyjny w kodzie konsolowym ma wszystkie pięć pozycji i Twój numer w polu autor.
  • Zrzuty obejmują cały ekran z paskiem zadań, nazwane konsola1, desktop1 i dalej.
  • Dokument egzamin zawiera podpisane zrzuty oraz nazwy systemu, środowisk i języków.
  • Płyta nagrana, opisana numerem zdającego i sprawdzona po nagraniu.
  • Arkusz podpisany numerem PESEL, karta oceny wypełniona, płyta w pudełku przy arkuszu.
Przećwicz to na czas

Przeczytanie rozwiązania to nie to samo, co napisanie go w 180 minut przy trzech częściach naraz. Otwórz oryginalny arkusz, ustaw stoper i zrób zadanie od zera — dopiero wynik tej próby pokaże, gdzie naprawdę stoisz.