INF.04-01-26.01-SGStyczeń 2026 · 61 kroków · ok. 121 min · 35 kryteriów z klucza
Rozwiązanie krok po kroku: Aplikacja gry w kości (Java + Android Studio)
Rozwiązujemy arkusz z grą w kości w wersji Java + Android Studio: klasa Kosc z polem statycznym, dwoma konstruktorami i trzema metodami, program konsolowy, który tworzy dwie kości (jedną z rzutu losowego, drugą z liczby wpisanej z klawiatury), aplikacja mobilna z pięcioma kośćmi, przyciskiem RZUT i sumą oczek oraz dwa testy jednostkowe w JUnit 5.
Kroki idą zdanie po zdaniu za treścią arkusza - każdy zaczyna się cytatem wymagania, a kod pokazuje dokładnie te linie, które je spełniają. Najpierw piszemy najprostszą wersję, której wymaga klucz (np. android:onClick w XML), a na końcu, w etapie „Dobre praktyki”, przerabiamy ją na kod z prawdziwych projektów.
Co widać w podglądzie. Wyniki programu konsolowego i testów pochodzą z prawdziwego uruchomienia kodu z danego kroku (JDK 21, JUnit 5). Ekran telefonu to symulacja w przeglądarce: układ jest odtwarzany z pliku activity_main.xml z kroku, a przyciski i kości reagują tak, jak kod MainActivity.java z tego samego kroku - możesz klikać. Symulację sprawdziłem z prawdziwą aplikacją uruchomioną w emulatorze Pixel 8; w kroku ze zrzutami jest prawdziwy zrzut z emulatora. Obrazy kosc0.png - kosc6.png pochodzą z archiwum zad1.7z dołączonego do arkusza.
Arkusz pozwala też na C#, C++ albo Pythona w konsoli i na .NET MAUI w części mobilnej - ten wariant to jedna z możliwych dróg, ta, którą na stanowiskach egzaminacyjnych spotyka się najczęściej.
Jak liczą się punkty. Klucz ma 35 kryteriów (R.1.1 - R.4.9), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 27 punktów - można stracić 8 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.
Krok 1 · po tym etapie masz 0 z 35 kryteriów (pkt)
Krok 1: Folder zdającego i trzy podfoldery
ok. 2 min
Polecenie z arkusza
Utwórz folder i nazwij go numerem zdającego. W folderze utwórz podfoldery: konsolowa, mobilna, testy.
Na pulpicie zakładamy folder o nazwie z numerem PESEL, a w nim trzy podfoldery: konsolowa, mobilna i testy. Od razu rozpakowujemy też archiwum z obrazami kości: arkusz podaje, że zad1.7z leży na pulpicie i ma hasło @Kosc6. W środku jest siedem plików kosc0.png - kosc6.png; kosc0.png to pusta ścianka (kość przed pierwszym rzutem), pozostałe mają od 1 do 6 oczek.
Projekty możemy trzymać w domyślnych folderach środowisk (IdeaProjects, AndroidStudioProjects) - na koniec pakujemy je do archiwów i kopiujemy do tych trzech podfolderów.
Etap 2: Aplikacja konsolowa
Kroki 2-27 · po tym etapie masz 18 z 35 kryteriów (pkt)
Krok 2: Nowy projekt konsola w IntelliJ IDEA
ok. 3 min
Polecenie z arkusza
Zastosowany obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym: C++ lub C#, lub Java, lub Python.
Wybieramy Javę - tę samą, w której napiszemy aplikację w Android Studio, więc klasę Kosc przeniesiemy tam bez zmian. W IntelliJ IDEA: New Project, nazwa konsola (od niej weźmie się nazwa archiwum konsola.zip), język Java, system budowania IntelliJ, JDK zainstalowane na stanowisku. Odznaczamy Add sample code i sami dodajemy w folderze src klasę Main z pustą metodą main - od niej program się zaczyna.
R.2.1 Zdefiniowana klasa Kosc z polami publicznymi: dwa typu całkowitego, jedno logiczne oraz polem publicznym statycznym typu całkowitego
ok. 1 min
Polecenie z arkusza
Zaprogramuj klasę o nazwie Kosc implementującą logikę działania pojedynczej kości, wykorzystywanej później w grze w kości.
Prawy przycisk na src → New → Java Class → Kosc. W Javie klasa publiczna musi leżeć w pliku o tej samej nazwie, więc powstaje Kosc.java. Nazwa dokładnie jak w arkuszu - bez „ś”, z wielką literą: klucz sprawdza klasę Kosc po nazwie (R.2.1).
konsola/src/Kosc.javaJavanowy plik
publicclassKosc {}
Krok 4: Pole statyczne: liczba instancji
Kryteria: ,
R.2.1 Zdefiniowana klasa Kosc z polami publicznymi: dwa typu całkowitego, jedno logiczne oraz polem publicznym statycznym typu całkowitego
R.1.4 Polskie lub angielskie nazewnictwo pól i zmiennych. Nazewnictwo jest znaczące. Wyjątkami od reguły są zmienne bufor, tmp, iteratory pętli. Kryterium nie jest spełnione, gdy nazwy zmiennych nic nie znaczą, np. x, tab, tablica, foo
ok. 1 min
Polecenie z arkusza
Klasa Kosc powinna zawierać: Pole ogólnodostępne, statyczne, przechowujące liczbę instancji klasy Kosc.
Ogólnodostępne to public, statyczne to static: takie pole należy do całej klasy, a nie do jednego obiektu - wszystkie kości widzą ten sam licznik. Dlatego nadaje się do liczenia, ile kości już utworzono. Typ int, bo to liczba całkowita, i wartość początkowa 0. Odczytamy je później przez nazwę klasy: Kosc.instanceCount.
Typowe błędy
Pole bez static jest osobne w każdym obiekcie - każda kość miałaby swój licznik równy 1 i program zawsze wypisywałby „1”.
R.2.2 Nazwy obrazów od kosc0.png do kosc6.png zostały przypisane jako elementy tablicy lub innej kolekcji
R.1.5 Typy zmiennych pasują do problemu, np. tablica przechowuje napisy, liczba oczek oraz identyfiaktor pliku graficznego są typu całkowitego, zmienna przechowująca czy kość jest dostępna jest typu logicznego (w przypadku języka Python typ wynika z przypisanych danych)
ok. 2 min
Polecenie z arkusza
Pola ogólnodostępne, przechowujące: Nazwy plików przechowujących obrazy (kosc0.png, kosc1.png, kosc2.png, kosc3.png, kosc4.png, kosc5.png, kosc6.png) umieszczone w tablicy lub innej kolekcji typu napisowego.
Tablica napisów String[] z siedmioma nazwami w kolejności od kosc0.png do kosc6.png. Kolejność ma znaczenie: indeks elementu równa się liczbie oczek (imageFiles[3] to "kosc3.png"), więc nazwę pliku dla wyrzuconej wartości odczytamy jednym odwołaniem, bez żadnego if. Długą listę łamiemy w dwóch wierszach z wcięciem - kod ma być czytelny (R.1.1).
R.2.1 Zdefiniowana klasa Kosc z polami publicznymi: dwa typu całkowitego, jedno logiczne oraz polem publicznym statycznym typu całkowitego
R.1.4 Polskie lub angielskie nazewnictwo pól i zmiennych. Nazewnictwo jest znaczące. Wyjątkami od reguły są zmienne bufor, tmp, iteratory pętli. Kryterium nie jest spełnione, gdy nazwy zmiennych nic nie znaczą, np. x, tab, tablica, foo
R.1.5 Typy zmiennych pasują do problemu, np. tablica przechowuje napisy, liczba oczek oraz identyfiaktor pliku graficznego są typu całkowitego, zmienna przechowująca czy kość jest dostępna jest typu logicznego (w przypadku języka Python typ wynika z przypisanych danych)
ok. 1 min
Polecenie z arkusza
Liczba oczek wyrzucona kością, typu liczbowego całkowitego (3 dla obrazu 1).
public int pips - pips to po angielsku oczka na kości. Nazwy pól mają coś znaczyć (R.1.4): pips albo po polsku liczbaOczek jest w porządku, x czy a - nie. Typ całkowity int, bo oczek nie bywa 2,5 (R.1.5).
R.2.1 Zdefiniowana klasa Kosc z polami publicznymi: dwa typu całkowitego, jedno logiczne oraz polem publicznym statycznym typu całkowitego
R.1.5 Typy zmiennych pasują do problemu, np. tablica przechowuje napisy, liczba oczek oraz identyfiaktor pliku graficznego są typu całkowitego, zmienna przechowująca czy kość jest dostępna jest typu logicznego (w przypadku języka Python typ wynika z przypisanych danych)
ok. 1 min
Polecenie z arkusza
Identyfikator pliku graficznego odpowiadającego wyrzuconej liczbie oczek, typu całkowitego (3 dla obrazu 1, jest to indeks tablicy wskazujący na nazwę kosc3.png).
Drugie pole całkowite: imageId to indeks w tablicy imageFiles. Dla trójki oba pola mają wartość 3 - arkusz mimo to chce dwóch osobnych pól, bo jedno opisuje kość (liczbę oczek), a drugie jej obraz. W aplikacji mobilnej ten sam indeks wskaże obrazek w zasobach Androida.
R.2.1 Zdefiniowana klasa Kosc z polami publicznymi: dwa typu całkowitego, jedno logiczne oraz polem publicznym statycznym typu całkowitego
R.1.5 Typy zmiennych pasują do problemu, np. tablica przechowuje napisy, liczba oczek oraz identyfiaktor pliku graficznego są typu całkowitego, zmienna przechowująca czy kość jest dostępna jest typu logicznego (w przypadku języka Python typ wynika z przypisanych danych)
ok. 1 min
Polecenie z arkusza
Informacja czy kość jest dostępna, typu logicznego.
boolean available przyjmuje tylko true albo false. W grze kość „odłożona” (zablokowana) nie bierze udziału w kolejnym rzucie - to pole będzie o tym decydować. Klasa ma teraz komplet pól z arkusza: statyczny licznik, tablicę napisów, dwa pola całkowite i jedno logiczne - dokładnie to, co sprawdza R.2.1.
Krok 9: Konstruktor z argumentem: sprawdzenie zakresu
Kryteria: , ,
R.2.3 Konstruktor bezparametrowy losuje liczbę i przypisuje ją do pola wartości liczby oczek i pola identyfikatora pliku. Konstruktor z jednym argumentem przypisuje liczbie oczek i identyfikatorowi pliku: - wartość argumentu, gdy argument jest z zakresu <1, 6> - 0, w przeciwnym wypadku (w języku Python jeden konstruktor z domyślną wartością argumentu)
R.1.1 Kod źródłowy zapisany w sposób czytelny: instrukcje w osobnych liniach, stosowane spacje pomiędzy operatorami, konsekwentnie stosowana wybrana konwencja dla nawiasów klamrowych instrukcji blokowej
R.1.2 Kod zapisany z wcięciami dla zagnieżdżeń bloków
ok. 2 min
Polecenie z arkusza
Konstruktory klasy: Jednoargumentowy, którego argument jest wartością wyrzuconej kości. W przypadku, gdy wartość argumentu jest inna niż 1, 2, 3, 4, 5 lub 6, ustawia wartość na 0.
Konstruktor ma nazwę klasy i nie ma typu zwracanego. Zamiast porównywać argument z sześcioma liczbami, sprawdzamy zakres: value < 1 || value > 6 (mniejsze od 1 lub większe od 6) obejmuje wszystko, co nie jest oczkiem kości - 0, 7, 100, -3. Wtedy zamieniamy argument na 0, który w tablicy obrazów wskazuje pustą ściankę kosc0.png.
Zwróć uwagę na zapis: każda instrukcja w osobnej linii, spacje wokół operatorów, klamra otwierająca na końcu linii i wcięcie o cztery spacje w każdym bloku - tak w całym kodzie (R.1.1, R.1.2).
Typowe błędy
value < 1 && value > 6 (oraz zamiast lub) nigdy nie jest prawdą - żadna liczba nie jest jednocześnie mniejsza od 1 i większa od 6, więc 9 przeszłoby bez zmiany.
Krok 10: Konstruktor z argumentem: przypisanie wartości
Kryteria:
R.2.3 Konstruktor bezparametrowy losuje liczbę i przypisuje ją do pola wartości liczby oczek i pola identyfikatora pliku. Konstruktor z jednym argumentem przypisuje liczbie oczek i identyfikatorowi pliku: - wartość argumentu, gdy argument jest z zakresu <1, 6> - 0, w przeciwnym wypadku (w języku Python jeden konstruktor z domyślną wartością argumentu)
ok. 1 min
Polecenie z arkusza
Przypisuje liczbie oczek i identyfikatorowi pliku wartość argumentu.
Po sprawdzeniu zakresu value jest już poprawne (1-6 albo 0), więc przypisujemy je obu polom. Kolejność ma znaczenie: przypisanie stoi po if, dlatego dla argumentu 9 pola dostaną 0, a nie 9.
R.2.4 W przynajmniej jednym konstruktorze jest inkrementowane pole statyczne oraz polu logicznemu przypisywana jest wartość true
ok. 1 min
Polecenie z arkusza
Przypisuje wartość polu logicznemu: kość jest dostępna.
Nowa kość bierze udział w grze, więc available = true. Pole logiczne bez przypisania miałoby w Javie wartość domyślną false - kość byłaby od początku zablokowana i metoda rzutu nic by nie robiła.
instanceCount++ zwiększa licznik o 1. Konstruktor wykonuje się przy każdym tworzeniu obiektu przez new, więc licznik rośnie dokładnie tyle razy, ile kości powstało. Klucz (R.2.4) wymaga inkrementacji i przypisania true w przynajmniej jednym konstruktorze - ten konstruktor jest już kompletny.
R.2.3 Konstruktor bezparametrowy losuje liczbę i przypisuje ją do pola wartości liczby oczek i pola identyfikatora pliku. Konstruktor z jednym argumentem przypisuje liczbie oczek i identyfikatorowi pliku: - wartość argumentu, gdy argument jest z zakresu <1, 6> - 0, w przeciwnym wypadku (w języku Python jeden konstruktor z domyślną wartością argumentu)
ok. 2 min
Polecenie z arkusza
Bezargumentowy: Losuje liczbę pseudolosową z zakresu od 1 do 6.
Drugi konstruktor ma tę samą nazwę, ale pustą listę parametrów - Java wybierze go przy new Kosc() (to przeciążenie konstruktora). Do losowania służy klasa Random z pakietu java.util (stąd import na górze pliku). random.nextInt(6) zwraca liczbę od 0 do 5, więc dodajemy 1 i dostajemy zakres 1-6.
Jeden generator Random wystarczy na wszystkie kości, dlatego jest polem static; private, bo nikt spoza klasy nie musi go widzieć, i final, bo nie podmieniamy go na inny.
Typowe błędy
random.nextInt(6) bez + 1 daje 0-5 (zero zamiast szóstki), a random.nextInt(7) daje 0-6 (może wypaść zero). W obu przypadkach kość wyrzuca wartość spoza zakresu 1-6 - właśnie taki błąd wyłapie pierwszy test z części III.
konsola/src/Kosc.javaJavazmienione: 8 linii
import java.util.Random;publicclassKosc {publicstaticint instanceCount = 0;public String[] imageFiles = {"kosc0.png", "kosc1.png", "kosc2.png", "kosc3.png","kosc4.png", "kosc5.png", "kosc6.png"};publicint pips;publicint imageId;publicboolean available;privatestaticfinal Random random = new Random();publicKosc(int value) {if (value < 1 || value > 6) { value = 0; } pips = value; imageId = value; available = true; instanceCount++; }publicKosc() {int value = random.nextInt(6) + 1; }}
Krok 14: Konstruktor bez argumentu: przypisanie wylosowanej liczby
Kryteria:
R.2.3 Konstruktor bezparametrowy losuje liczbę i przypisuje ją do pola wartości liczby oczek i pola identyfikatora pliku. Konstruktor z jednym argumentem przypisuje liczbie oczek i identyfikatorowi pliku: - wartość argumentu, gdy argument jest z zakresu <1, 6> - 0, w przeciwnym wypadku (w języku Python jeden konstruktor z domyślną wartością argumentu)
ok. 1 min
Polecenie z arkusza
Przypisuje liczbie oczek i identyfikatorowi pliku wylosowaną liczbę.
Wylosowaną wartość zapisaliśmy w zmiennej lokalnej value, żeby trafiła do obu pól ta sama liczba. Dwa osobne wywołania random.nextInt(6) + 1 dałyby dwie różne liczby - kość z trzema oczkami pokazywałaby obraz piątki.
konsola/src/Kosc.javaJavazmienione: 2 linie
import java.util.Random;publicclassKosc {publicstaticint instanceCount = 0;public String[] imageFiles = {"kosc0.png", "kosc1.png", "kosc2.png", "kosc3.png","kosc4.png", "kosc5.png", "kosc6.png"};publicint pips;publicint imageId;publicboolean available;privatestaticfinal Random random = new Random();publicKosc(int value) {if (value < 1 || value > 6) { value = 0; } pips = value; imageId = value; available = true; instanceCount++; }publicKosc() {int value = random.nextInt(6) + 1; pips = value; imageId = value; }}
Krok 15: Konstruktor bez argumentu: dostępność i licznik
Kryteria:
R.2.4 W przynajmniej jednym konstruktorze jest inkrementowane pole statyczne oraz polu logicznemu przypisywana jest wartość true
ok. 1 min
Polecenie z arkusza
Przypisuje wartość polu logicznemu: kość jest dostępna. Inkrementuje zmienną statyczną zliczającą instancje klasy.
Te same dwie linie co w pierwszym konstruktorze. Licznik musi rosnąć w obu konstruktorach - inaczej program konsolowy pokazałby złą liczbę kości po utworzeniu pierwszej z nich.
konsola/src/Kosc.javaJavazmienione: 2 linie
import java.util.Random;publicclassKosc {publicstaticint instanceCount = 0;public String[] imageFiles = {"kosc0.png", "kosc1.png", "kosc2.png", "kosc3.png","kosc4.png", "kosc5.png", "kosc6.png"};publicint pips;publicint imageId;publicboolean available;privatestaticfinal Random random = new Random();publicKosc(int value) {if (value < 1 || value > 6) { value = 0; } pips = value; imageId = value; available = true; instanceCount++; }publicKosc() {int value = random.nextInt(6) + 1; pips = value; imageId = value; available = true; instanceCount++; }}
Krok 16: Metoda roll: rzut tylko dostępną kością
Kryteria: ,
R.2.5 Metoda realizująca rzut kością losuje wartość z zakresu <1,6> i przypisuje ją do pola wartości liczby oczek i pola identyfikatora pliku tylko, gdy pole dostępności ma wartość true
R.1.3 Polskie lub angielskie nazewnictwo metod. Nazewnictwo jest znaczące
ok. 1 min
Polecenie z arkusza
Metoda ogólnodostępna, bezparametrowa, niezwracająca wartości, która realizuje rzut kością tylko, gdy kość jest dostępna.
Każde słowo z arkusza ma swój odpowiednik w nagłówku: ogólnodostępna - public, niezwracająca wartości - void, bezparametrowa - puste nawiasy (). Nazwa roll (rzuć) mówi, co metoda robi; nazwy metod też muszą być znaczące (R.1.3). W środku od razu warunek: cały rzut odbędzie się tylko wtedy, gdy available ma wartość true.
konsola/src/Kosc.javaJavazmienione: 5 linii
import java.util.Random;publicclassKosc {publicstaticint instanceCount = 0;public String[] imageFiles = {"kosc0.png", "kosc1.png", "kosc2.png", "kosc3.png","kosc4.png", "kosc5.png", "kosc6.png"};publicint pips;publicint imageId;publicboolean available;privatestaticfinal Random random = new Random();publicKosc(int value) {if (value < 1 || value > 6) { value = 0; } pips = value; imageId = value; available = true; instanceCount++; }publicKosc() {int value = random.nextInt(6) + 1; pips = value; imageId = value; available = true; instanceCount++; }publicvoidroll() {if (available) { } }}
Krok 17: Metoda roll: losowanie i przypisanie
Kryteria:
R.2.5 Metoda realizująca rzut kością losuje wartość z zakresu <1,6> i przypisuje ją do pola wartości liczby oczek i pola identyfikatora pliku tylko, gdy pole dostępności ma wartość true
ok. 1 min
Polecenie z arkusza
Losuje wartość z zakresu od 1 do 6. Przypisuje wylosowaną wartość do pola liczby oczek i identyfikatora pliku graficznego.
Wnętrze warunku powtarza losowanie z konstruktora bezargumentowego. Gdy kość jest zablokowana, blok if jest pomijany i oba pola zostają takie, jakie były - to zachowanie sprawdzi drugi test jednostkowy.
konsola/src/Kosc.javaJavazmienione: 3 linie
import java.util.Random;publicclassKosc {publicstaticint instanceCount = 0;public String[] imageFiles = {"kosc0.png", "kosc1.png", "kosc2.png", "kosc3.png","kosc4.png", "kosc5.png", "kosc6.png"};publicint pips;publicint imageId;publicboolean available;privatestaticfinal Random random = new Random();publicKosc(int value) {if (value < 1 || value > 6) { value = 0; } pips = value; imageId = value; available = true; instanceCount++; }publicKosc() {int value = random.nextInt(6) + 1; pips = value; imageId = value; available = true; instanceCount++; }publicvoidroll() {if (available) {int value = random.nextInt(6) + 1; pips = value; imageId = value; } }}
Krok 18: Metoda block: zablokowanie kości
Kryteria: ,
R.2.6 Metoda blokująca kość jest bezparametrowa, nie zwraca wartości i ustawia pole logiczne na false
R.1.3 Polskie lub angielskie nazewnictwo metod. Nazewnictwo jest znaczące
ok. 1 min
Polecenie z arkusza
Metoda ogólnodostępna, bezparametrowa, niezwracająca wartości, która blokuje kość: Ustawiana jest informacja, że kość jest niedostępna.
Najkrótsza metoda klasy: public void block() ustawia available na false. Od tej chwili roll() nie zmienia kości.
konsola/src/Kosc.javaJavazmienione: 4 linie
import java.util.Random;publicclassKosc {publicstaticint instanceCount = 0;public String[] imageFiles = {"kosc0.png", "kosc1.png", "kosc2.png", "kosc3.png","kosc4.png", "kosc5.png", "kosc6.png"};publicint pips;publicint imageId;publicboolean available;privatestaticfinal Random random = new Random();publicKosc(int value) {if (value < 1 || value > 6) { value = 0; } pips = value; imageId = value; available = true; instanceCount++; }publicKosc() {int value = random.nextInt(6) + 1; pips = value; imageId = value; available = true; instanceCount++; }publicvoidroll() {if (available) {int value = random.nextInt(6) + 1; pips = value; imageId = value; } }publicvoidblock() { available = false; }}
Krok 19: Metoda toWords: wartość słownie
Kryteria: ,
R.2.7 Istnieje metoda zwracająca wartość wyrzuconą na kości w postaci słownej np. "jeden" (w przypadku wartości spoza zakresu <1, 6> - dowolnie)
R.1.3 Polskie lub angielskie nazewnictwo metod. Nazewnictwo jest znaczące
ok. 3 min
Polecenie z arkusza
Metoda ogólnodostępna, bezparametrowa, zwracająca wartość wyrzuconą na kości w postaci tekstu (np. gdy wartość jest równa 3, zwracane jest „trzy”).
Tym razem metoda zwraca wartość, więc zamiast void ma typ String. switch wybiera gałąź po wartości pips; każda gałąź kończy się return, więc break nie jest potrzebny. Gałąź default obsługuje wszystko inne - u nas to 0 (kość z argumentem spoza zakresu). Klucz pozwala zwrócić tu cokolwiek (R.2.7), „zero” pasuje do pustej ścianki.
Typowe błędy
Bez default (albo return po switch) kompilator Javy zgłosi błąd „missing return statement” - metoda typu String musi coś zwrócić w każdym przypadku.
konsola/src/Kosc.javaJavazmienione: 19 linii
import java.util.Random;publicclassKosc {publicstaticint instanceCount = 0;public String[] imageFiles = {"kosc0.png", "kosc1.png", "kosc2.png", "kosc3.png","kosc4.png", "kosc5.png", "kosc6.png"};publicint pips;publicint imageId;publicboolean available;privatestaticfinal Random random = new Random();publicKosc(int value) {if (value < 1 || value > 6) { value = 0; } pips = value; imageId = value; available = true; instanceCount++; }publicKosc() {int value = random.nextInt(6) + 1; pips = value; imageId = value; available = true; instanceCount++; }publicvoidroll() {if (available) {int value = random.nextInt(6) + 1; pips = value; imageId = value; } }publicvoidblock() { available = false; }public String toWords() {switch (pips) {case1:return"jeden";case2:return"dwa";case3:return"trzy";case4:return"cztery";case5:return"pięć";case6:return"sześć";default:return"zero"; } }}
Krok 20: Program główny: pierwsza kość z konstruktora bez argumentu
Kryteria: ,
R.2.9 Uruchomiony program inicjuje jeden obiekt konstruktorem bezargumentowym, drugi jednoargumentowym. Po każdej inicjacji wyświetlana jest liczba instancji. Dla każdego obiektu wyświetlana jest wartość wyrzucona kością w postaci liczbowej i napisowej oraz odpowiadająca jej nazwa pliku (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
R.1.7 Program nawiązuje zrozumiałą komunikację z użytkownikiem, wyświetlane komunikaty są znaczące (jeżeli kod nie uruchamia się z powodu błędów kompilacji - sprawdzić w kodzie aplikacji)
ok. 2 min
Polecenie z arkusza
Sprawdź działanie klasy w programie głównym: Należy utworzyć dwa obiekty klasy Kosc, każdy za pomocą innego konstruktora.
Wracamy do Main.java. new Kosc() wywołuje konstruktor bezargumentowy - kość od razu ma wylosowaną liczbę oczek. Pierwsza linia komunikatu mówi użytkownikowi, co się stało (R.1.7). Uruchamiamy program zieloną strzałką przy main - wynik jest w konsoli.
konsola/src/Main.javaJavazmienione: 2 linie
publicclassMain {publicstaticvoidmain(String[] args) { Kosc firstDie = new Kosc(); System.out.println("Pierwsza kość (rzut losowy, konstruktor bez argumentu)"); }}
Wynik programu po tym kroku
> java Main
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Krok 21: Pierwsza kość: liczba instancji
Kryteria:
R.2.9 Uruchomiony program inicjuje jeden obiekt konstruktorem bezargumentowym, drugi jednoargumentowym. Po każdej inicjacji wyświetlana jest liczba instancji. Dla każdego obiektu wyświetlana jest wartość wyrzucona kością w postaci liczbowej i napisowej oraz odpowiadająca jej nazwa pliku (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 1 min
Polecenie z arkusza
Po utworzeniu każdego obiektu należy wyświetlić: Liczbę utworzonych instancji klasy.
Pole statyczne odczytujemy przez nazwę klasy, nie obiektu: Kosc.instanceCount. Po jednej kości licznik pokazuje 1 - to dowód, że inkrementacja w konstruktorze działa.
> java Main
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Liczba utworzonych kości: 1
Krok 22: Pierwsza kość: liczba oczek liczbowo i słownie
Kryteria:
R.2.9 Uruchomiony program inicjuje jeden obiekt konstruktorem bezargumentowym, drugi jednoargumentowym. Po każdej inicjacji wyświetlana jest liczba instancji. Dla każdego obiektu wyświetlana jest wartość wyrzucona kością w postaci liczbowej i napisowej oraz odpowiadająca jej nazwa pliku (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 1 min
Polecenie z arkusza
Informację o liczbie oczek wyrzuconych kością (w postaci liczbowej i napisowej).
W jednej linii wypisujemy pole pips (liczba) i wynik metody toWords() (napis). Operator + skleja napisy z liczbami w jeden tekst.
> java Main
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Liczba utworzonych kości: 1
Wyrzucono: 4 (cztery)
Krok 23: Pierwsza kość: nazwa pliku obrazu
Kryteria: ,
R.2.9 Uruchomiony program inicjuje jeden obiekt konstruktorem bezargumentowym, drugi jednoargumentowym. Po każdej inicjacji wyświetlana jest liczba instancji. Dla każdego obiektu wyświetlana jest wartość wyrzucona kością w postaci liczbowej i napisowej oraz odpowiadająca jej nazwa pliku (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
R.1.7 Program nawiązuje zrozumiałą komunikację z użytkownikiem, wyświetlane komunikaty są znaczące (jeżeli kod nie uruchamia się z powodu błędów kompilacji - sprawdzić w kodzie aplikacji)
ok. 1 min
Polecenie z arkusza
Nazwę pliku odpowiadającego wyrzuconej liczbie oczek.
Tu przydaje się tablica z indeksem równym liczbie oczek: firstDie.imageFiles[firstDie.imageId] zwraca np. "kosc5.png" dla piątki. Pusta println() oddziela pierwszą kość od drugiej - komunikaty mają być zrozumiałe (R.1.7), a ściana tekstu taka nie jest.
> java Main
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Liczba utworzonych kości: 1
Wyrzucono: 5 (pięć)
Plik obrazu: kosc5.png
Krok 24: Druga kość: liczba z klawiatury
Kryteria: ,
R.2.9 Uruchomiony program inicjuje jeden obiekt konstruktorem bezargumentowym, drugi jednoargumentowym. Po każdej inicjacji wyświetlana jest liczba instancji. Dla każdego obiektu wyświetlana jest wartość wyrzucona kością w postaci liczbowej i napisowej oraz odpowiadająca jej nazwa pliku (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
R.1.7 Program nawiązuje zrozumiałą komunikację z użytkownikiem, wyświetlane komunikaty są znaczące (jeżeli kod nie uruchamia się z powodu błędów kompilacji - sprawdzić w kodzie aplikacji)
ok. 2 min
Polecenie z arkusza
W przypadku konstruktora jednoargumentowego liczba przekazana jako argument ma być pobrana z klawiatury.
Do czytania z klawiatury służy Scanner z java.util połączony ze strumieniem wejścia System.in. Najpierw zachęta przez print (bez przejścia do nowej linii - kursor czeka zaraz za dwukropkiem), potem scanner.nextInt() czeka na liczbę i Enter. Wczytaną wartość przekazujemy do new Kosc(value) - tym razem działa konstruktor z argumentem. W podglądzie wpisano 4.
konsola/src/Main.javaJavazmienione: 8 linii
import java.util.Scanner;publicclassMain {publicstaticvoidmain(String[] args) { Kosc firstDie = new Kosc(); System.out.println("Pierwsza kość (rzut losowy, konstruktor bez argumentu)"); System.out.println("Liczba utworzonych kości: " + Kosc.instanceCount); System.out.println("Wyrzucono: " + firstDie.pips + " (" + firstDie.toWords() + ")"); System.out.println("Plik obrazu: " + firstDie.imageFiles[firstDie.imageId]); System.out.println(); System.out.print("Podaj liczbę oczek dla drugiej kości (1-6): "); Scanner scanner = new Scanner(System.in);int value = scanner.nextInt(); Kosc secondDie = new Kosc(value); System.out.println("Druga kość (wartość z klawiatury, konstruktor z argumentem)"); }}
Wynik programu po tym kroku
> java Main
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Liczba utworzonych kości: 1
Wyrzucono: 5 (pięć)
Plik obrazu: kosc5.png
Podaj liczbę oczek dla drugiej kości (1-6): 4
Druga kość (wartość z klawiatury, konstruktor z argumentem)
Krok 25: Druga kość: liczba instancji, oczka i plik
Kryteria: ,
R.2.9 Uruchomiony program inicjuje jeden obiekt konstruktorem bezargumentowym, drugi jednoargumentowym. Po każdej inicjacji wyświetlana jest liczba instancji. Dla każdego obiektu wyświetlana jest wartość wyrzucona kością w postaci liczbowej i napisowej oraz odpowiadająca jej nazwa pliku (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
R.1.7 Program nawiązuje zrozumiałą komunikację z użytkownikiem, wyświetlane komunikaty są znaczące (jeżeli kod nie uruchamia się z powodu błędów kompilacji - sprawdzić w kodzie aplikacji)
ok. 2 min
Polecenie z arkusza
Po utworzeniu każdego obiektu należy wyświetlić: Liczbę utworzonych instancji klasy, Informację o liczbie oczek wyrzuconych kością (w postaci liczbowej i napisowej), Nazwę pliku odpowiadającego wyrzuconej liczbie oczek. Informacja powinna być zrozumiała dla użytkownika.
Te same trzy linie co dla pierwszej kości, tylko dla secondDie. Licznik pokazuje teraz 2 - obie kości przeszły przez swoje konstruktory. Program jest kompletny: dwa obiekty z dwóch różnych konstruktorów i po każdym komplet informacji (R.2.9).
konsola/src/Main.javaJavazmienione: 3 linie
import java.util.Scanner;publicclassMain {publicstaticvoidmain(String[] args) { Kosc firstDie = new Kosc(); System.out.println("Pierwsza kość (rzut losowy, konstruktor bez argumentu)"); System.out.println("Liczba utworzonych kości: " + Kosc.instanceCount); System.out.println("Wyrzucono: " + firstDie.pips + " (" + firstDie.toWords() + ")"); System.out.println("Plik obrazu: " + firstDie.imageFiles[firstDie.imageId]); System.out.println(); System.out.print("Podaj liczbę oczek dla drugiej kości (1-6): "); Scanner scanner = new Scanner(System.in);int value = scanner.nextInt(); Kosc secondDie = new Kosc(value); System.out.println("Druga kość (wartość z klawiatury, konstruktor z argumentem)"); System.out.println("Liczba utworzonych kości: " + Kosc.instanceCount); System.out.println("Wyrzucono: " + secondDie.pips + " (" + secondDie.toWords() + ")"); System.out.println("Plik obrazu: " + secondDie.imageFiles[secondDie.imageId]); }}
Wynik programu po tym kroku
> java Main
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Liczba utworzonych kości: 1
Wyrzucono: 5 (pięć)
Plik obrazu: kosc5.png
Podaj liczbę oczek dla drugiej kości (1-6): 4
Druga kość (wartość z klawiatury, konstruktor z argumentem)
Liczba utworzonych kości: 2
Wyrzucono: 4 (cztery)
Plik obrazu: kosc4.png
Krok 26: Zrzuty konsola1.png i konsola2.png
Kryteria: , ,
R.2.8 Program uruchamia się w konsoli, co jest widoczne na zrzucie ekranu
R.1.6 Podjęta próba uruchomienia kodu, udokumentowana zrzutem przedstawiającym uruchomiony program lub jego kompilację
R.4.6 Istnieje przynajmniej jeden zrzut ekranu z uruchomienia lub kompilacji aplikacji konsolowej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja
ok. 3 min
Polecenie z arkusza
Wykonaj zrzuty ekranu dokumentujące wykonanie programu w konsoli. Zrzuty ekranu powinny obejmować cały obszar ekranu, z widocznym paskiem zadań oraz środowiskiem programistycznym. Liczba zrzutów ekranu powinna odpowiadać wszystkim możliwym interakcjom użytkownika z programem. Zrzuty ekranu zapisz w folderze konsolowa pod nazwami konsola1.png, konsola2.png, itd.
Użytkownik ma jedną interakcję - wpisuje liczbę - ale dwa różne przypadki: liczba z zakresu 1-6 i liczba spoza zakresu, dla której konstruktor ustawia 0. Uruchamiamy program dwa razy (w podglądzie: 4 i 9) i po każdym uruchomieniu robimy zrzut całego ekranu (Print Screen, z paskiem zadań i oknem IntelliJ) - konsola1.png i konsola2.png. Widać na nich, że program działa w konsoli (R.2.8) i że go uruchomiliśmy (R.1.6, R.4.6).
Typowe błędy
Wykadrowany zrzut samej konsoli nie spełnia kryteriów - arkusz i klucz wymagają całego ekranu z paskiem zadań i środowiskiem.
Wynik programu po tym kroku
> java Main
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Liczba utworzonych kości: 1
Wyrzucono: 5 (pięć)
Plik obrazu: kosc5.png
Podaj liczbę oczek dla drugiej kości (1-6): 4
Druga kość (wartość z klawiatury, konstruktor z argumentem)
Liczba utworzonych kości: 2
Wyrzucono: 4 (cztery)
Plik obrazu: kosc4.png
> java Main
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Liczba utworzonych kości: 1
Wyrzucono: 5 (pięć)
Plik obrazu: kosc5.png
Podaj liczbę oczek dla drugiej kości (1-6): 9
Druga kość (wartość z klawiatury, konstruktor z argumentem)
Liczba utworzonych kości: 2
Wyrzucono: 0 (zero)
Plik obrazu: kosc0.png
R.4.9 Przygotowana jest dokumentacja w postaci płyty: oba projekty są spakowane oraz zmodyfikowane pliki są na zewnątrz archiwów
ok. 3 min
Polecenie z arkusza
Kod aplikacji przygotuj do nagrania na płytę. W folderze konsolowa powinno znaleźć się archiwum całego projektu o nazwie konsola.zip, skopiowany z projektu plik z kodem źródłowym programu, plik wykonywalny, jeżeli istnieje oraz zrzuty ekranu.
Cały folder projektu konsola pakujemy do konsola.zip (w Eksploratorze: prawy przycisk → Wyślij do → Folder skompresowany). Obok archiwum kopiujemy pliki źródłowe Kosc.java i Main.java - egzaminator ma je przeczytać bez rozpakowywania. Java nie tworzy pliku .exe; skompilowane klasy leżą w out/production/konsola i są w archiwum. Do tego dwa zrzuty z poprzedniego kroku.
Kroki 28-50 · po tym etapie masz 29 z 35 kryteriów (pkt)
Krok 28: Nowy projekt Kosci w Android Studio
ok. 3 min
Polecenie z arkusza
Za pomocą środowiska programistycznego dostępnego na stanowisku egzaminacyjnym wykonaj aplikację mobilną do gry w kości oraz uruchom ją w dostępnym emulatorze systemu mobilnego.
New Project → szablon Empty Views Activity (z widokami w XML - szablon Empty Activity tworzy projekt w Jetpack Compose, bez pliku układu). Nazwa Kosci, pakiet com.example.kosci, język Java. Kreator tworzy dwa pliki, które będziemy zmieniać: MainActivity.java (logika) i res/layout/activity_main.xml (wygląd), oba widać obok.
Szablon od razu włącza tryb edge-to-edge: aplikacja rysuje się pod paskiem stanu, a kod w onCreate dodaje do głównego widoku (R.id.main) odstępy od pasków systemowych. Podgląd pokazuje, jak szablon wygląda po uruchomieniu.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 29: Obrazy kości w res/drawable
ok. 2 min
Polecenie z arkusza
Do wykonania aplikacji mobilnej wykorzystaj umieszczone na pulpicie konta Egzamin obrazy z archiwum zad1.7z z hasłem: @Kosc6.
Siedem plików kosc0.png - kosc6.png kopiujemy do app/src/main/res/drawable (w Android Studio: zaznacz pliki w Eksploratorze, Ctrl+C, prawy przycisk na drawable → Paste). Każdy plik staje się zasobem z identyfikatorem: w XML @drawable/kosc3, w Javie R.drawable.kosc3. Nazwy zasobów mogą mieć tylko małe litery, cyfry i podkreślenia - nazwy z arkusza spełniają ten warunek, więc nie trzeba ich zmieniać.
W programie można wykorzystać klasę Kosc z aplikacji konsolowej.
Kopiujemy Kosc.java z konsoli do pakietu com.example.kosci (obok MainActivity.java). Jedyna zmiana to pierwsza linia package com.example.kosci; - w Androidzie każda klasa należy do pakietu aplikacji. Logika rzutu, blokowania i licznika jest gotowa i sprawdzona w konsoli, więc w aktywności zostanie tylko obsługa ekranu.
Krok 31: Układ: pionowy LinearLayout zamiast ConstraintLayout
Kryteria:
R.3.1 Zastosowany język znaczników XML/XAML lub inny do opisu interfejsu użytkownika oraz zdefiniowano przynajmniej jedną kontrolkę
ok. 2 min
Polecenie z arkusza
Interfejs użytkownika zapisany za pomocą języka znaczników wspieranego w danym środowisku (np. XAML, XML). Zastosowany dowolny układ pozwalający na rozmieszczenie wszystkich elementów tak jak na obrazie 2 lub 3.
Ekran z obrazu 2 to elementy jeden pod drugim: rząd dwóch kości, rząd trzech kości, przycisk, wynik. Najprościej opisuje to LinearLayout z android:orientation="vertical" - układa dzieci w pionie, bez więzów do ustawiania. Przechodzimy do widoku Code pliku activity_main.xml i zamieniamy cały ConstraintLayout (z napisem Hello World!) na pusty LinearLayout.
Zostawiamy android:id="@+id/main" - kod szablonu w MainActivity szuka widoku R.id.main, żeby dodać odstępy od pasków systemowych.
Typowe błędy
Usunięcie android:id="@+id/main" razem ze starym układem kończy się awarią aplikacji przy starcie - findViewById(R.id.main) zwraca null, a szablon wywołuje na nim metodę.
Kosci/app/src/main/res/layout/activity_main.xmlXMLzmienione: 3 linie
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 32: Pierwszy rząd: dwie kości z obrazem kosc0
Kryteria: ,
R.3.1 Zastosowany język znaczników XML/XAML lub inny do opisu interfejsu użytkownika oraz zdefiniowano przynajmniej jedną kontrolkę
R.3.7 W stanie początkowym aplikacji wszystkie obrazy wyświetlają grafikę kosc0.png bez przezroczystości, przycisk jest opisany „RZUT” oraz pole tekstowe zawiera napis 0 (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 3 min
Polecenie z arkusza
Elementy aplikacji w stanie początkowym (stan 1 obrazu 2 lub 3): Pięć obrazów kosc0.png bez przezroczystości (wszystkie kości są dostępne). Wielkość obrazów wyświetlających kości dopasowana do widoku z obrazu 2 lub 3.
Rząd kości to zagnieżdżony LinearLayout, tym razem poziomy (horizontal), o rozmiarze dopasowanym do zawartości (wrap_content). W nim dwa ImageView, każdy z własnym id (die1, die2 - po nim znajdziemy kontrolkę w Javie) i obrazem @drawable/kosc0, czyli pustą ścianką ze stanu 1.
Rozmiar ustawiamy na sztywno: 80dp × 80dp. Obraz ma 640 × 632 px i bez tego zająłby cały ekran; ImageView sam zmniejszy go do ramki, zachowując proporcje. Jednostka dp (piksel niezależny od gęstości) sprawia, że kość ma tę samą wielkość na każdym telefonie. contentDescription to opis dla czytnika ekranu - Android Studio ostrzega, gdy go brakuje.
Kosci/app/src/main/res/layout/activity_main.xmlXMLzmienione: 20 linii
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 33: Drugi rząd: trzy kości
Kryteria:
R.3.1 Zastosowany język znaczników XML/XAML lub inny do opisu interfejsu użytkownika oraz zdefiniowano przynajmniej jedną kontrolkę
ok. 2 min
Polecenie z arkusza
Rozmieszczenie elementów zgodne z obrazami 2 lub 3.
Drugi poziomy LinearLayout z kośćmi die3, die4, die5 - kopiujemy pierwszy rząd i dopisujemy trzecią kość. Identyfikatory muszą być różne w całym pliku: dwa widoki z tym samym id to błąd, którego Android Studio nie zgłosi od razu, a findViewById zwróci tylko pierwszy z nich. Na razie wszystko jest przyklejone do lewej krawędzi - wyśrodkujemy to jednym atrybutem na końcu.
Kosci/app/src/main/res/layout/activity_main.xmlXMLzmienione: 27 linii
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 34: Przycisk RZUT
Kryteria:
R.3.7 W stanie początkowym aplikacji wszystkie obrazy wyświetlają grafikę kosc0.png bez przezroczystości, przycisk jest opisany „RZUT” oraz pole tekstowe zawiera napis 0 (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 1 min
Polecenie z arkusza
Przycisk z napisem „RZUT”.
Button pod rzędami kości, z napisem RZUT i identyfikatorem rollButton. Przycisk ma na razie kolor motywu aplikacji (fiolet Material 3) - kolor z arkusza ustawimy w osobnym kroku, bo przy przyciskach Material działa to inaczej niż przy tle układu.
Kosci/app/src/main/res/layout/activity_main.xmlXMLzmienione: 6 linii
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 35: Pole tekstowe z wynikiem 0
Kryteria:
R.3.7 W stanie początkowym aplikacji wszystkie obrazy wyświetlają grafikę kosc0.png bez przezroczystości, przycisk jest opisany „RZUT” oraz pole tekstowe zawiera napis 0 (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 1 min
Polecenie z arkusza
Pole tekstowe z wynikiem rzutu z wartością 0, zawierające sumę oczek pięciu kości.
TextView z tekstem 0 i identyfikatorem resultText - kod wpisze tu sumę oczek po każdym rzucie. Komplet elementów ze stanu 1 jest gotowy: pięć kości kosc0, przycisk RZUT i wynik 0 (R.3.7). Teraz kolejno założenia dotyczące widoku.
Kosci/app/src/main/res/layout/activity_main.xmlXMLzmienione: 6 linii
android:background na głównym LinearLayout. Kolor ma osiem cyfr szesnastkowych, bo w Androidzie zapis to #AARRGGBB: pierwsza para to przezroczystość (alfa), dopiero potem czerwony, zielony, niebieski. ED to 237 z 255, czyli 93% krycia; 27C121 to zieleń. Prześwituje spod niej jasne tło okna motywu, stąd zieleń na ekranie jest odrobinę jaśniejsza niż czyste #27C121. Wpisujemy kolor dokładnie tak, jak w arkuszu (R.3.2).
Typowe błędy
W CSS (np. na INF.03) ośmiocyfrowy kolor to #RRGGBBAA - przezroczystość na KOŃCU. Przeniesienie tego nawyku do Androida (albo odwrotnie) daje zupełnie inny kolor.
Kosci/app/src/main/res/layout/activity_main.xmlXMLzmienione: 1 linia
Przy przycisku piszemy android:backgroundTint, nie android:background. Szablon używa motywu Material 3, a w nim Button zamienia się w MaterialButton, który rysuje własne tło (zaokrągloną pigułkę) i barwi je kolorem motywu. backgroundTint to właśnie ta barwa - podmieniamy ją na nasz kolor, w tym samym zapisie #AARRGGBB co tło układu.
Typowe błędy
android:background="#ED275021" kompiluje się bez błędu, ale Material dalej nakłada na tło fioletowy kolor motywu - przycisk zostaje fioletowy, tylko traci zaokrąglenie (sprawdzone w emulatorze). Na zrzucie kolor się nie zgadza i kryterium R.3.2 przepada.
Kosci/app/src/main/res/layout/activity_main.xmlXMLzmienione: 1 linia
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 38: Czcionka wyniku 40
Kryteria:
R.3.2 Zastosowane kolory tła: okna lub rozkładu: #ED27C121, przycisku: #ED275021, rozmiar czcionki pola tekstowego ustawiono na 40
ok. 1 min
Polecenie z arkusza
Rozmiar czcionki pola tekstowego 40.
android:textSize="40sp". Dla tekstu używamy jednostki sp zamiast dp: działa tak samo, ale dodatkowo uwzględnia rozmiar czcionki ustawiony przez użytkownika w systemie. Arkusz podaje samą liczbę 40, a 40sp to zapis, którego Android Studio oczekuje dla rozmiaru tekstu.
Kosci/app/src/main/res/layout/activity_main.xmlXMLzmienione: 2 linie
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 39: Marginesy 10 dla kości i przycisku
Kryteria:
R.3.3 Zastosowane marginesy zewnętrzne dla obrazów i przycisku 10, wyśrodkowano wszystkie elementy widoku
ok. 2 min
Polecenie z arkusza
Marginesy zewnętrzne dla obrazów i przycisku 10.
Margines zewnętrzny to android:layout_margin - odstęp od sąsiednich elementów (wewnętrzny, między krawędzią a treścią, to padding). Dopisujemy 10dp do każdego z pięciu ImageView i do przycisku. Kości przestają się stykać, a przycisk odsuwa się od rzędów i od wyniku.
Kosci/app/src/main/res/layout/activity_main.xmlXMLzmienione: 6 linii
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 40: Wyśrodkowanie wszystkich elementów
Kryteria: ,
R.3.3 Zastosowane marginesy zewnętrzne dla obrazów i przycisku 10, wyśrodkowano wszystkie elementy widoku
R.3.6 Aplikacja kompiluje się i uruchamia w emulatorze, co jest udokumentowane zrzutem ekranu, układ wszystkich kontrolek jest zgodny z obrazem 2 lub 3 w arkuszu egzaminacyjnym (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 1 min
Polecenie z arkusza
Wszystkie elementy widoku są wyśrodkowane.
Jeden atrybut na głównym układzie: android:gravity="center" ustawia zawartość LinearLayout na środku - w poziomie i w pionie. Rzędy kości mają szerokość wrap_content, więc są węższe od ekranu i mogą się wyśrodkować. Widok odpowiada teraz stanowi 1 z obrazu 2 arkusza.
Typowe błędy
android:layout_gravity ustawia element względem jego RODZICA, a android:gravity - dzieci względem elementu. Na głównym układzie potrzebne jest gravity.
Kosci/app/src/main/res/layout/activity_main.xmlXMLzmienione: 1 linia
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 41: Pola aktywności: kości i ich kontrolki
ok. 2 min
Polecenie z arkusza
Aplikacja powinna być zapisana czytelnie, z zasadami czystego formatowania kodu, należy stosować znaczące nazwy zmiennych i funkcji.
Przechodzimy do MainActivity.java. Kości są dwa razy po pięć: pięć obiektówKosc (logika) i pięć kontrolekImageView (obrazki na ekranie). Trzymamy je w dwóch tablicach o tych samych indeksach - dice[2] to kość pokazywana przez diceImages[2]. Dzięki temu cały rzut zrobi jedna pętla. Trzecie pole to pole tekstowe wyniku. Klasy ImageView i TextView trzeba zaimportować (Alt+Enter na czerwonej nazwie).
Kosci/app/src/main/java/com/example/kosci/MainActivity.javaJavazmienione: 6 linii
Krok 42: Odwołanie do kontrolek przez findViewById
Kryteria:
R.3.5 Program odwołuje się do przynajmniej jednej kontrolki w sposób zgodny z danym środowiskiem programistycznym
ok. 2 min
Polecenie z arkusza
Działanie aplikacji po wciśnięciu przycisku RZUT: W kontrolkach obrazu wyświetlana jest grafika odpowiadająca liczbie oczek na każdej kości. Liczona jest suma oczek z wszystkich kości i wyświetlana w polu tekstowym.
Żeby zmieniać obrazy i wynik, kod potrzebuje referencji do kontrolek z XML. findViewById(R.id.die1) szuka w układzie widoku o identyfikatorze die1 - tym samym, który nadaliśmy w activity_main.xml. Wywołania stoją w onCreateposetContentView, bo dopiero wtedy układ istnieje. To jest odwołanie do kontrolek zgodne z Androidem, o które pyta R.3.5.
Typowe błędy
findViewById przed setContentView zwraca null - aplikacja uruchomi się, ale pierwsze kliknięcie zakończy się awarią.
Kosci/app/src/main/java/com/example/kosci/MainActivity.javaJavazmienione: 7 linii
R.3.7 W stanie początkowym aplikacji wszystkie obrazy wyświetlają grafikę kosc0.png bez przezroczystości, przycisk jest opisany „RZUT” oraz pole tekstowe zawiera napis 0 (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 2 min
Polecenie z arkusza
Pięć obrazów kosc0.png bez przezroczystości (wszystkie kości są dostępne).
Tablica new Kosc[5] ma pięć pustych miejsc (null) - obiekty tworzymy pętlą. Konstruktor z argumentem 0 robi dokładnie to, czego chce stan 1: zero jest spoza zakresu 1-6, więc liczba oczek i obraz to 0 (kosc0.png), a kość jest dostępna. Wykorzystujemy więc tę samą regułę, którą napisaliśmy dla konsoli.
Kosci/app/src/main/java/com/example/kosci/MainActivity.javaJavazmienione: 4 linie
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 44: Metoda rollDice podpięta pod przycisk
Kryteria: ,
R.3.4 Dla przycisku oraz dla przynajmniej jednego obrazu zdefiniowana metoda kliknięcia, która jest powiązana z kontrolką
R.3.8 Kliknięcie przycisku powoduje, że są losowane wartości tylko dla kostek dostępnych, odpowiadające wartościom obrazy są wyświetlane (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 2 min
Polecenie z arkusza
Działanie aplikacji po wciśnięciu przycisku RZUT: Dla dostępnych kości losowana jest liczba oczek każdej z nich.
Najprostsze podpięcie kliknięcia to atrybut android:onClick="rollDice" w XML przycisku i metoda o tej samej nazwie w aktywności: public, void, z jednym parametrem View (to kliknięty przycisk). Pętla wywołuje roll() każdej kości - a roll() sam pomija kości zablokowane, więc warunek „dla dostępnych kości” jest już załatwiony w klasie Kosc.
Kliknij RZUT w podglądzie: nic nie widać, choć liczby w obiektach już się zmieniają - kod jeszcze nie przekłada ich na obrazy.
Typowe błędy
Literówka w nazwie (onClick="rolldice" przy metodzie rollDice) albo metoda private - kompilacja przejdzie, a aplikacja zamknie się z błędem przy pierwszym kliknięciu.
Kosci/app/src/main/java/com/example/kosci/MainActivity.javaJavazmienione: 7 linii
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 45: Obraz odpowiadający wyrzuconej liczbie oczek
Kryteria:
R.3.8 Kliknięcie przycisku powoduje, że są losowane wartości tylko dla kostek dostępnych, odpowiadające wartościom obrazy są wyświetlane (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 2 min
Polecenie z arkusza
W kontrolkach obrazu wyświetlana jest grafika odpowiadająca liczbie oczek na każdej kości.
W Androidzie obraz wskazujemy nie nazwą pliku, tylko identyfikatorem zasobuR.drawable.kosc3. Tablica imageResources ma je w tej samej kolejności co imageFiles w klasie Kosc - indeks to liczba oczek - więc imageResources[dice[i].imageId] daje obraz wyrzuconej wartości, a setImageResource wstawia go do kontrolki. Kliknij RZUT: kości pokazują wynik losowania.
Kosci/app/src/main/java/com/example/kosci/MainActivity.javaJavazmienione: 3 linie
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 46: Suma oczek w polu tekstowym
Kryteria:
R.3.9 Kliknięcie przycisku powoduje wyświetlenie pod nim sumy wszystkich oczek na wyświetlanych obrazach (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 2 min
Polecenie z arkusza
Liczona jest suma oczek z wszystkich kości i wyświetlana w polu tekstowym.
Zmienna sum zaczyna od 0, w pętli dodajemy pips każdej kości - wszystkich, także zablokowanych, bo ich oczka nadal leżą na stole (przykład z arkusza: po zablokowaniu trzech czwórek suma dalej wynosi 15). Po pętli wpisujemy wynik do resultText. setText z liczbą typu int zinterpretowałby ją jako identyfikator zasobu tekstowego i aplikacja by się zamknęła - dlatego zamiana na tekst przez String.valueOf(sum).
Typowe błędy
resultText.setText(sum) kompiluje się bez błędu (istnieje wersja setText(int resId)), ale po kliknięciu kończy się wyjątkiem Resources$NotFoundException.
Kosci/app/src/main/java/com/example/kosci/MainActivity.javaJavazmienione: 3 linie
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 47: Kliknięcie kości: blokada i przezroczystość 50%
Kryteria: ,
R.3.4 Dla przycisku oraz dla przynajmniej jednego obrazu zdefiniowana metoda kliknięcia, która jest powiązana z kontrolką
R.3.10 Dla wszystkich kości: gdy dana kość jest wyświetlana bez przezroczystości, po kliknięciu widoczna jest przezroczystość. Po kolejnym kliknięciu, kość jest wyświetlana bez przezroczystości (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 3 min
Polecenie z arkusza
Działanie aplikacji po kliknięciu na dowolny obraz kości: Jeżeli kość jest dostępna: jest ustawiana na niedostępną i przezroczystość obrazu jest ustawiana na 50%.
Wszystkie pięć obrazów dostaje w XML android:onClick="toggleDie" - jedna metoda obsługuje każdą kość. Którą kliknięto, mówi parametr view: pętla porównuje go z kontrolkami (== sprawdza, czy to ten sam obiekt) i znajduje indeks. Dla dostępnej kości wołamy block() z klasy Kosc i ustawiamy setAlpha(0.5f) - alfa 0,5 to obraz w połowie przezroczysty (f, bo metoda przyjmuje float).
Kliknij RZUT, potem jedną z kości: przygasa, a kolejny rzut jej nie zmienia. Kliknięcie przygaszonej jeszcze nic nie robi.
Kosci/app/src/main/java/com/example/kosci/MainActivity.javaJavazmienione: 11 linii
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 48: Ponowne kliknięcie: kość znów dostępna
Kryteria:
R.3.10 Dla wszystkich kości: gdy dana kość jest wyświetlana bez przezroczystości, po kliknięciu widoczna jest przezroczystość. Po kolejnym kliknięciu, kość jest wyświetlana bez przezroczystości (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 2 min
Polecenie z arkusza
Jeżeli kość jest niedostępna: jest ustawiana na dostępną i obraz jest wyświetlany bez przezroczystości.
Gałąź else odwraca blokadę: pole available jest publiczne, więc ustawiamy je wprost na true (arkusz nie wymaga w klasie metody odblokowującej), a setAlpha(1.0f) przywraca pełne krycie. Kliknięcie kości działa teraz jak przełącznik - aplikacja jest kompletna. Rozegraj w podglądzie stan 2 i 3 z arkusza: rzut, zablokowanie trzech kości, kolejny rzut.
Kosci/app/src/main/java/com/example/kosci/MainActivity.javaJavazmienione: 3 linie
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 49: Uruchomienie w emulatorze i zrzuty mobilna1-3
Kryteria: ,
R.3.6 Aplikacja kompiluje się i uruchamia w emulatorze, co jest udokumentowane zrzutem ekranu, układ wszystkich kontrolek jest zgodny z obrazem 2 lub 3 w arkuszu egzaminacyjnym (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
R.4.7 Istnieje przynajmniej jeden zrzut ekranu z uruchomienia lub kompilacji aplikacji mobilnej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja
ok. 4 min
Polecenie z arkusza
Podejmij próbę kompilacji i emulacji aplikacji. Wykonaj zrzuty ekranowe dokumentujące wszystkie stany aplikacji. Zrzuty zapisz w folderze mobilna pod nazwami mobilna1.png, mobilna2.png, itd. Wszystkie zrzuty muszą zawierać cały obszar ekranu z paskiem zadań i środowiskiem programistycznym.
W Device Manager uruchamiamy emulator (np. Pixel z najnowszym Androidem) i przyciskiem Run instalujemy aplikację. Stany z arkusza to trzy zrzuty całego ekranu, z oknem Android Studio i emulatorem: mobilna1.png - zaraz po starcie (pięć pustych kości, 0), mobilna2.png - po kliknięciu RZUT, mobilna3.png - po zablokowaniu kilku kości.
Obok jest prawdziwy ekran tej aplikacji z emulatora Pixel 8 (Android 16) w stanie 3: dwie zablokowane kości przygaszone, suma wszystkich pięciu. Na egzaminie zrzut obejmuje cały monitor, nie sam telefon.
Typowe błędy
Zrzut z samego emulatora (bez Android Studio i paska zadań) nie spełnia R.4.7 - klucz wymaga, by na zrzucie było widać środowisko, w którym powstała aplikacja.
Ekran telefonu po tym kroku
Krok 50: Folder mobilna: archiwum, źródła, zrzuty
Kryteria:
R.4.9 Przygotowana jest dokumentacja w postaci płyty: oba projekty są spakowane oraz zmodyfikowane pliki są na zewnątrz archiwów
ok. 3 min
Polecenie z arkusza
Kod aplikacji przygotuj do nagrania na płytę. W folderze mobilna powinno znaleźć się archiwum całego folderu projektu oraz skopiowane pliki z kodem źródłowym, które były modyfikowane oraz pliki z zrzutami.
Pakujemy folder projektu Kosci (z AndroidStudioProjects) do archiwum, np. Kosci.zip, i kopiujemy obok pliki, które zmienialiśmy: MainActivity.java, Kosc.java i activity_main.xml, a do tego trzy zrzuty. Folder build można przed spakowaniem usunąć (Build → Clean Project) - to wynik kompilacji, który Android Studio odtworzy, a waży najwięcej.
Ekran telefonu po tym kroku
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Etap 4: Testy jednostkowe
Kroki 51-55 · po tym etapie masz 34 z 35 kryteriów (pkt)
Krok 51: Klasa testowa KoscTest i biblioteka JUnit 5
Kryteria:
R.4.1 Co najmniej w jednej metodzie testującej została wykorzystana asercja, nazwy metod odzwierciedlają cel testu, zastosowane narzędzie testujące odpowiednie dla języka
ok. 3 min
Polecenie z arkusza
Wykonaj testy jednostkowe aplikacji konsolowej, metody realizującej rzut kością. Do napisania testów wykorzystaj bibliotekę do testów jednostkowych dostępną na stanowisku egzaminacyjnym dla języka programowania, w którym została napisana klasa Kosc.
Wracamy do projektu konsola w IntelliJ. Obok src zakładamy folder test i oznaczamy go jako katalog testów (prawy przycisk → Mark Directory as → Test Sources Root). Najszybciej klasę testu tworzy skrót: kursor na nazwie Kosc → Ctrl+Shift+T → Create New Test, biblioteka JUnit5; jeśli jej brak, przycisk Fix doda ją do projektu.
Importujemy adnotację @Test i dwie asercje: assertTrue (warunek ma być prawdziwy) i assertEquals (wartość ma być równa oczekiwanej). Klasa testu nazywa się jak testowana klasa z przyrostkiem Test. Uruchomienie pustej klasy kończy się bez błędu, ale z wynikiem „0 tests found” - biblioteka działa, testów jeszcze nie ma.
R.4.1 Co najmniej w jednej metodzie testującej została wykorzystana asercja, nazwy metod odzwierciedlają cel testu, zastosowane narzędzie testujące odpowiednie dla języka
R.4.2 W teście metody realizującej rzut kością sprawdzone czy wartość jest z zakresu <1,6>
ok. 3 min
Polecenie z arkusza
W testach jednostkowych należy rozważyć następujące przypadki testowe: Czy wyrzucona wartość jest w zakresie od 1 do 6. W testach nazwy metod testujących należy dobrać tak, aby wyrażały cel danego testu. Nazwy metod należy zapisać zgodnie z konwencją nazewnictwa w danym języku programowania. Każdy przypadek testowy powinien być sprawdzany oddzielną metodą.
Nazwa metody mówi, co sprawdza: rollReturnsValueFromOneToSix - zapis camelCase, jak każda metoda w Javie. Jeden rzut niczego nie dowodzi (może trafić akurat w środek zakresu), więc rzucamy 1000 razy i po każdym rzucie sprawdzamy assertTrue(die.pips >= 1 && die.pips <= 6). Gdyby losowanie dawało 0 albo 7, któryś z tysiąca rzutów to wyłapie, a drugi argument asercji wypisze, jaka wartość wypadła.
Uruchamiamy test zieloną strzałką przy metodzie - wynik jest obok.
konsola/test/KoscTest.javaJavazmienione: 9 linii
import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.assertEquals;import static org.junit.jupiter.api.Assertions.assertTrue;classKoscTest { @TestvoidrollReturnsValueFromOneToSix() { Kosc die = new Kosc();for (int i = 0; i < 1000; i++) { die.roll(); assertTrue(die.pips >= 1 && die.pips <= 6, "Wyrzucono " + die.pips); } }}
R.4.3 W teście metody realizującej rzut kością sprawdzone czy wartość się nie zmienia jeżeli pole dostępność jest ustawione na false
ok. 3 min
Polecenie z arkusza
Czy wartość na kości pozostaje bez zmian jeżeli kość nie jest dostępna.
Tutaj potrzebujemy kości o znanej wartości, więc tworzymy ją konstruktorem z argumentem: new Kosc(4). Blokujemy ją, rzucamy 100 razy i za każdym razem assertEquals(4, die.pips) - wartość oczekiwana jest pierwszym argumentem, rzeczywista drugim. Gdyby roll() nie sprawdzał pola available, wartość zmieniłaby się w kilku pierwszych rzutach (szansa, że 100 rzutów da same czwórki, jest praktycznie zerowa) i test byłby czerwony.
konsola/test/KoscTest.javaJavazmienione: 10 linii
import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.assertEquals;import static org.junit.jupiter.api.Assertions.assertTrue;classKoscTest { @TestvoidrollReturnsValueFromOneToSix() { Kosc die = new Kosc();for (int i = 0; i < 1000; i++) { die.roll(); assertTrue(die.pips >= 1 && die.pips <= 6, "Wyrzucono " + die.pips); } } @TestvoidrollDoesNotChangeValueWhenDieIsBlocked() { Kosc die = new Kosc(4); die.block();for (int i = 0; i < 100; i++) { die.roll(); assertEquals(4, die.pips); } }}
Krok 54: Uruchomienie wszystkich testów i zrzuty test1.png
Kryteria: ,
R.4.4 Uruchomiona przynajmniej jedna metoda testująca udokumentowana zrzutem ekranu
R.4.5 Wynik uruchomionego testu z R.4.2 lub R.4.3 wynika z danych testowych co jest udokumentowane zrzutem ekranu
ok. 2 min
Polecenie z arkusza
Po napisaniu metod testujących uruchom wszystkie metody. Wykonaj zrzuty ekranu dokumentujące uruchomienie testów, zrzuty zapisz w katalogu testy pod nazwami test1.png, test2.png, itd. Na zrzutach powinny być widoczne wyniki działania metod testujących. Zrzuty ekranu powinny obejmować cały obszar ekranu, z widocznym paskiem zadań oraz środowiskiem programistycznym.
Zielona strzałka przy klasie KoscTest uruchamia obie metody. IntelliJ pokazuje drzewko z zielonymi znacznikami przy każdej z nich i podsumowanie „Tests passed: 2” - tak jak wydruk obok (to wynik prawdziwego uruchomienia testów z tego rozwiązania). Zrzut całego ekranu z tym panelem zapisujemy jako test1.png w folderze testy.
R.4.9 Przygotowana jest dokumentacja w postaci płyty: oba projekty są spakowane oraz zmodyfikowane pliki są na zewnątrz archiwów
ok. 2 min
Polecenie z arkusza
Projekt testów przygotuj do nagrania na płytę. W folderze testy powinno znaleźć się archiwum całego folderu projektu oraz skopiowane pliki z kodem źródłowym, które były modyfikowane oraz zrzuty ekranu.
Testy są w tym samym projekcie co program konsolowy, więc do folderu testy trafia ponownie spakowany projekt konsola - teraz już z folderem test - oraz skopiowany plik KoscTest.java i zrzut test1.png.
Kroki 56-59 · po tym etapie masz 34 z 35 kryteriów (pkt)
Krok 56: Konsola: metoda printDie zamiast powtórzonych linii
ok. 3 min
Polecenie z arkusza
Po utworzeniu każdego obiektu należy wyświetlić: Liczbę utworzonych instancji klasy, Informację o liczbie oczek wyrzuconych kością (w postaci liczbowej i napisowej), Nazwę pliku odpowiadającego wyrzuconej liczbie oczek.
Te same trzy linie wypisywania stoją w programie dwa razy i różnią się tylko nazwą obiektu. Gdy coś trzeba w nich zmienić, łatwo poprawić jedną kopię i zapomnieć o drugiej. Przenosimy je do metody printDie(Kosc die) i wywołujemy ją dla każdej kości; stare linie zostają w komentarzu, żeby było widać, co zastąpiła. Wynik programu jest identyczny.
Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
> java Main
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Liczba utworzonych kości: 1
Wyrzucono: 4 (cztery)
Plik obrazu: kosc4.png
Podaj liczbę oczek dla drugiej kości (1-6): 4
Druga kość (wartość z klawiatury, konstruktor z argumentem)
Liczba utworzonych kości: 2
Wyrzucono: 4 (cztery)
Plik obrazu: kosc4.png
Krok 57: Konsola: odporność na tekst zamiast liczby
ok. 3 min
Polecenie z arkusza
W przypadku konstruktora jednoargumentowego liczba przekazana jako argument ma być pobrana z klawiatury.
Wersja podstawowa kończy się wyjątkiem InputMismatchException, gdy użytkownik wpisze np. „abc”. scanner.hasNextInt() sprawdza, czy następne słowo jest liczbą, nie zabierając go z wejścia; dopóki nie jest, wypisujemy prośbę i odrzucamy błędne słowo przez scanner.next(). Liczba spoza zakresu nadal przechodzi - tę obsługuje konstruktor, tak jak chce arkusz. W podglądzie wpisano najpierw „abc”, potem 5.
Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
konsola/src/Main.javaJavazmienione: 4 linie
import java.util.Scanner;publicclassMain {publicstaticvoidmain(String[] args) { Kosc firstDie = new Kosc(); System.out.println("Pierwsza kość (rzut losowy, konstruktor bez argumentu)"); printDie(firstDie);// System.out.println("Liczba utworzonych kości: " + Kosc.instanceCount);// System.out.println("Wyrzucono: " + firstDie.pips + " (" + firstDie.toWords() + ")");// System.out.println("Plik obrazu: " + firstDie.imageFiles[firstDie.imageId]); System.out.println(); System.out.print("Podaj liczbę oczek dla drugiej kości (1-6): "); Scanner scanner = new Scanner(System.in);while (!scanner.hasNextInt()) { System.out.print("To nie jest liczba całkowita, spróbuj jeszcze raz: "); scanner.next(); }int value = scanner.nextInt(); Kosc secondDie = new Kosc(value); System.out.println("Druga kość (wartość z klawiatury, konstruktor z argumentem)"); printDie(secondDie);// System.out.println("Liczba utworzonych kości: " + Kosc.instanceCount);// System.out.println("Wyrzucono: " + secondDie.pips + " (" + secondDie.toWords() + ")");// System.out.println("Plik obrazu: " + secondDie.imageFiles[secondDie.imageId]); }staticvoidprintDie(Kosc die) { System.out.println("Liczba utworzonych kości: " + Kosc.instanceCount); System.out.println("Wyrzucono: " + die.pips + " (" + die.toWords() + ")"); System.out.println("Plik obrazu: " + die.imageFiles[die.imageId]); }}
Wynik programu po tym kroku
> java Main
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Liczba utworzonych kości: 1
Wyrzucono: 5 (pięć)
Plik obrazu: kosc5.png
Podaj liczbę oczek dla drugiej kości (1-6): abc
To nie jest liczba całkowita, spróbuj jeszcze raz: 5
Druga kość (wartość z klawiatury, konstruktor z argumentem)
Liczba utworzonych kości: 2
Wyrzucono: 5 (pięć)
Plik obrazu: kosc5.png
Krok 58: Android: kliknięcia ustawione w kodzie zamiast android:onClick
Kryteria:
R.3.4 Dla przycisku oraz dla przynajmniej jednego obrazu zdefiniowana metoda kliknięcia, która jest powiązana z kontrolką
ok. 4 min
Polecenie z arkusza
Działanie aplikacji po wciśnięciu przycisku RZUT: Dla dostępnych kości losowana jest liczba oczek każdej z nich.
Atrybut android:onClick jest wygodny, ale kruchy: nazwa metody to zwykły napis w XML, więc literówka wychodzi dopiero po kliknięciu - awarią aplikacji. Dlatego Android Studio go odradza. W prawdziwych projektach słuchacza kliknięcia ustawia się w kodzie: setOnClickListener(this::rollDice) przekazuje referencję do metody - kompilator sprawdzi, że taka metoda istnieje i ma właściwy parametr. Kości dostają słuchacza w tej samej pętli, w której powstają obiekty Kosc.
Z XML usuwamy wszystkie sześć atrybutów android:onClick (atrybutu w znaczniku nie da się zostawić w komentarzu). Aplikacja działa tak samo.
Na egzaminie wystarczy wersja wcześniejsza - klucz sprawdza tylko, że metoda kliknięcia jest powiązana z kontrolką (R.3.4), a obie drogi to spełniają.
Kosci/app/src/main/java/com/example/kosci/MainActivity.javaJavazmienione: 2 linie
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 59: Android: napis przycisku w strings.xml
ok. 2 min
Polecenie z arkusza
Przycisk z napisem „RZUT”.
Android Studio podkreśla android:text="RZUT" ostrzeżeniem Hardcoded string. Teksty widoczne dla użytkownika trzyma się w pliku res/values/strings.xml i odwołuje do nich przez @string/nazwa - wtedy tłumaczenie aplikacji na inny język to dodanie drugiego pliku strings.xml, bez zmian w układzie. Najszybciej: Alt+Enter na napisie → Extract string resource. Na ekranie nic się nie zmienia.
Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.
Kosci/app/src/main/res/layout/activity_main.xmlXMLzmienione: 1 linia
Kroki 60-61 · po tym etapie masz 35 z 35 kryteriów (pkt)
Krok 60: Plik egzamin z dokumentacją narzędzi
Kryteria:
R.4.8 Dokumentacja zawiera: nazwę systemu operacyjnego, nazwy środowisk programistycznych, nazwy języków programowania, nazwy emulatora dla aplikacji mobilnej
ok. 3 min
Polecenie z arkusza
Utwórz plik tekstowy z dokumentacją i nazwij go egzamin. Dokument powinien zawierać informacje o narzędziach wykorzystanych na egzaminie: Nazwę systemu operacyjnego, Nazwy środowisk programistycznych, Nazwę emulatora dla aplikacji mobilnej, Nazwy języków programowania. Dokument egzamin zapisz w folderze z numerem zdającego.
Zwykły plik tekstowy (Notatnik) o nazwie egzamin w folderze z numerem zdającego - cztery informacje, po jednej w linii. Wpisujemy to, co naprawdę jest na stanowisku: wersję systemu, środowiska, nazwę urządzenia w emulatorze (widać ją w Device Manager) i języki. XML to język znaczników, ale warto go wymienić - widok aplikacji jest w nim napisany. W tym rozwiązaniu plik ma rozszerzenie .txt, na egzaminie Notatnik też je doda.
egzamin.txtTekstnowy plik
System operacyjny: Windows 11Środowiska programistyczne: IntelliJ IDEA (aplikacja konsolowa i testy), Android Studio (aplikacja mobilna)Emulator aplikacji mobilnej: Android Emulator - urządzenie Pixel 8, Android 16 (API 36)Języki programowania: Java (aplikacja konsolowa, testy JUnit 5, logika aplikacji mobilnej), XML (widok aplikacji mobilnej)
R.4.9 Przygotowana jest dokumentacja w postaci płyty: oba projekty są spakowane oraz zmodyfikowane pliki są na zewnątrz archiwów
ok. 5 min
Polecenie z arkusza
UWAGA: Nagraj płytę z rezultatami pracy. W folderze z numerem zdającego powinny się znajdować foldery: konsolowa, mobilna, testy oraz plik egzamin. Po nagraniu płyty sprawdź poprawność nagrania. Opisz płytę numerem zdającego i pozostaw na stanowisku, zapakowaną w pudełku wraz z arkuszem egzaminacyjnym.
mobilna: archiwum projektu Kosci, MainActivity.java, Kosc.java, activity_main.xml, mobilna1.png - mobilna3.png,
testy: archiwum projektu z testami, KoscTest.java, test1.png,
plik egzamin.
Oba projekty muszą być spakowane, a zmienione pliki leżeć obok archiwów (R.4.9). Nagrywamy folder z numerem zdającego, sprawdzamy odczyt płyty i opisujemy ją numerem zdającego. Pusta lub nieczytelna płyta to zero punktów za wszystkie rezultaty.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.
Autor rozwiązania: Bartosz Bryniarski. Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony). Treść arkusza i klucza oceniania pochodzi z CKE.