Przejdź do głównej treści
INF.04-01-24.06-SGCzerwiec 2024 · 30 kroków · ok. 82 min · 35 kryteriów z klucza

Rozwiązanie krok po kroku: Gra w kości (Java + Android)

Rozwiązujemy arkusz z grą w kości w wersji Java + Android Studio: w konsoli program, który pyta o liczbę kostek (od 3 do 10, aż do skutku), rzuca nimi w osobnej metodzie, liczy punkty w drugiej metodzie - sumę oczek, które wypadły co najmniej dwa razy - i pyta, czy grać dalej; w aplikacji mobilnej ekran z pięcioma obrazami kości, przyciskiem rzutu, wynikiem rzutu, wynikiem całej gry i przyciskiem resetu. Do tego dokumentacja metody według wzoru z arkusza, zrzuty i dokument egzamin.

Kroki idą zdanie po zdaniu za treścią arkusza - każdy zaczyna się poleceniem z arkusza, a kod pokazuje dokładnie te linie, które je spełniają. Najpierw piszemy najprostszą wersję, której wymaga klucz, a w etapie „Dobre praktyki” poprawiamy to, czego klucz nie sprawdza.

Co widać w podglądzie. Wyniki programu konsolowego pochodzą z prawdziwego uruchomienia kodu z danego kroku (JDK 21) z danymi wpisanymi z klawiatury, a punkty w każdym rzucie przeliczyliśmy niezależnie z wypisanych oczek. Ekran telefonu to symulacja w przeglądarce zbudowana z pliku XML danego kroku, z obrazami z archiwum pliki1.zip; jej zachowanie odpowiada kodowi Javy z kroku - możesz klikać „RZUĆ KOŚĆMI” i „RESETUJ WYNIK”. Każdy stan aplikacji zbudowaliśmy też w Android Studio (Gradle) i porównaliśmy z emulatorem Pixel 8.

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.

Jak liczą się punkty. Klucz ma 35 kryteriów (R.1.1 - R.4.8), 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.

  1. Etap 1: Przygotowanie

    Krok 1 · po tym etapie masz 0 z 35 kryteriów (pkt)

    Krok 1: Folder zdającego, podfoldery i obrazy z pliki1.zip

    ok. 3 min
    Polecenie z arkusza

    Utwórz folder i nazwij go numerem zdającego. W folderze utwórz podfoldery: konsolowa, mobilna, dokumentacja. Do zbudowania aplikacji zastosuj obrazy z archiwum pliki1.zip zabezpieczonego hasłem Gra^Kosci5.

    Na pulpicie zakładamy folder o nazwie z numerem PESEL, a w nim konsolowa, mobilna i dokumentacja. Archiwum pliki1.zip rozpakowujemy hasłem z arkusza - jest w nim siedem obrazów: k1.jpg - k6.jpg (ścianki kości z jednym do sześciu oczek) i question.jpg (znak zapytania na stan początkowy). Przydadzą się w aplikacji mobilnej.

  2. Etap 2: Aplikacja konsolowa

    Kroki 2-9 · po tym etapie masz 16 z 35 kryteriów (pkt)

    Krok 2: Projekt konsola w Javie

    ok. 3 min
    Polecenie z arkusza

    Napisz program implementujący logikę gry w kości. Zastosowany obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym: C++ lub C#, lub Java, lub Python. Dowolne podejście: strukturalne lub obiektowe.

    Wybieramy Javę - ten sam język posłuży w Android Studio, więc metody z konsoli przeniesiemy do aplikacji mobilnej prawie bez zmian. W IntelliJ IDEA: New Project → Java, nazwa konsola. Podejście strukturalne: wszystko w klasie Main, metody statyczne. Zaczynamy od pustej metody main.

    konsola/src/Main.java Java nowy plik
    public class Main {
        public static void main(String[] args) {
        }
    }
  3. Krok 3: Metoda rollDice: losowanie liczb 1-6 do tablicy

    Kryteria: , , , ,

    R.2.1 Program składa się z programu głównego oraz przynajmniej dwóch funkcji (metod): losującej i liczącej punkty (mogą być niedokończone, lub z błędami) oraz zastosowano zmienną typu tablicowego dla liczb całkowitych, wypełnioną wartościami całkowitymi od 1 do 6

    R.2.3 Wyświetlanie zawartości tablicy i wypełnianie jej wartościami losowymi zostało zaimplementowane w oparciu o pętlę. Pętla ma właściwą liczbę iteracji

    R.2.5 Liczby są losowane z przedziału od 1 do 6. Losowane jest tyle liczb, ile kostek wskazał użytkownik. Losowanie odbywa się w metodzie / funkcji. W podejściu strukturalnym funkcja musi mieć parametry wejściowe (nie są stosowane zmienne globalne)

    R.1.3 Użyto polskie lub angielskie, znaczące nazewnictwo funkcji (metod)

    R.1.5 Zastosowano typy zmiennych pasujące do problemu (np. tablica dowolnego typu całkowitego, zmienne całkowite dla punktów, liczby losowań, zmienna znakowa dla zgody 't'/'n') W przypadku języka Python, tam gdzie jest to wymagane, zastosowano jawną konwersję do odpowiednich typów

    ok. 3 min
    Polecenie z arkusza

    Losuje tyle liczb całkowitych z przedziału od 1 do 6, ile podano z klawiatury, co odpowiada rzutom kośćmi. Wynik pojedynczego losowania kostek jest zapisywany do tablicy lub kolekcji. Program zawiera funkcję / metodę losującą liczby z przedziału od 1 do 6 (rzucającą wszystkimi kośćmi). W przypadku podejścia strukturalnego funkcja nie może korzystać ze zmiennych globalnych.

    Metoda dostaje liczbę kostek jako parametr i zwraca tablicę int[] z wynikami - nie korzysta z żadnych zmiennych spoza siebie, jak wymaga arkusz (R.2.5, R.1.5). W pętli for wypełniamy tyle komórek, ile jest kostek (R.2.3).

    random.nextInt(6) losuje liczbę od 0 do 5 - górna granica jest wyłączona. Dlatego dodajemy 1 i dostajemy oczka od 1 do 6.

    Typowe błędy

    random.nextInt(6) bez + 1 daje liczby 0-5: kość z zerem oczek, a szóstka nigdy nie wypada.

    konsola/src/Main.java Java zmienione: 11 linii
    import java.util.Random;
    
    public class Main {
        static int[] rollDice(int count) {
            Random random = new Random();
            int[] dice = new int[count];
            for (int i = 0; i < count; i++) {
                dice[i] = random.nextInt(6) + 1;
            }
            return dice;
        }
    
        public static void main(String[] args) {
        }
    }
  4. Krok 4: Liczba kostek z klawiatury, powtarzana do skutku

    Kryteria: , ,

    R.2.4 Zastosowano przynajmniej jedną pętlę do wprowadzania liczby kostek lub sprawdzania zgody na dalsze działanie programu

    R.1.7 Program nawiązuje zrozumiałą komunikację z użytkownikiem: monit o wprowadzenie danych, wyprowadzanie wyników opatrzone komentarzem. Jeżeli kod nie uruchamia się z powodu błędów kompilacji - sprawdzić w kodzie aplikacji

    R.1.4 Użyto polskie lub angielskie, znaczące nazewnictwo zmiennych (pól). Wyjątkami od reguły są zmienne: bufor, tmp, iteratory pętli itp. Kryterium nie jest spełnione tylko wtedy, gdy nazwy zmiennych nic nie znaczą, np.: x, fun, foo, tab, tablica, …

    ok. 3 min
    Polecenie z arkusza

    Pobiera z klawiatury liczbę kostek do rzucenia z przedziału od 3 do 10. Punkt 1 jest powtarzany dopóki podana liczba nie należy do przedziału <3, 10> - obraz 2.

    Scanner czyta dane z klawiatury, nextInt() - liczbę całkowitą. Pętla do ... while wykonuje się co najmniej raz (pytanie musi paść), a powtarza się, dopóki liczba jest poza przedziałem: mniejsza od 3 lub większa od 10 (R.2.4, R.1.7). Komunikat jest jak na obrazie 1.

    Podgląd to prawdziwe uruchomienie: wpisujemy 2, potem 12 - program pyta ponownie - i dopiero 5 kończy pętlę.

    Typowe błędy

    Warunek count < 3 && count > 10 nie jest nigdy prawdziwy (liczba nie może być jednocześnie mniejsza od 3 i większa od 10) - pętla przyjmie każdą liczbę.

    konsola/src/Main.java Java zmienione: 7 linii
    import java.util.Scanner;
    import java.util.Random;
    
    public class Main {
        static int[] rollDice(int count) {
            Random random = new Random();
            int[] dice = new int[count];
            for (int i = 0; i < count; i++) {
                dice[i] = random.nextInt(6) + 1;
            }
            return dice;
        }
    
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int count;
            do {
                System.out.println("Ile kostek chcesz rzucić?(3 - 10)");
                count = scanner.nextInt();
            } while (count < 3 || count > 10);
        }
    }
    Wynik programu po tym kroku
    > java Main
    Ile kostek chcesz rzucić?(3 - 10)
    2
    Ile kostek chcesz rzucić?(3 - 10)
    12
    Ile kostek chcesz rzucić?(3 - 10)
    5
  5. Krok 5: Rzut i wypisanie oczek każdej kostki

    Kryteria: ,

    R.2.3 Wyświetlanie zawartości tablicy i wypełnianie jej wartościami losowymi zostało zaimplementowane w oparciu o pętlę. Pętla ma właściwą liczbę iteracji

    R.2.8 Program wyświetla tyle liczb z zakresu 1..6 ile użytkownik podał na początku działania aplikacji

    ok. 2 min
    Polecenie z arkusza

    Wypisuje ile wyrzucono oczek na każdej kostce w formacie „Kostka <numer-kostki>: <liczba-oczek>”.

    Wywołujemy rollDice(count) i pętlą wypisujemy tablicę (R.2.3, R.2.8). Indeksy tablicy zaczynają się od 0, a kostki numerujemy od 1 - stąd i + 1 w nawiasie (bez nawiasu + skleiłoby napis z i i z jedynką: „Kostka 01”).

    konsola/src/Main.java Java zmienione: 5 linii
    import java.util.Scanner;
    import java.util.Random;
    
    public class Main {
        static int[] rollDice(int count) {
            Random random = new Random();
            int[] dice = new int[count];
            for (int i = 0; i < count; i++) {
                dice[i] = random.nextInt(6) + 1;
            }
            return dice;
        }
    
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int count;
            do {
                System.out.println("Ile kostek chcesz rzucić?(3 - 10)");
                count = scanner.nextInt();
            } while (count < 3 || count > 10);
    
            int[] dice = rollDice(count);
            for (int i = 0; i < dice.length; i++) {
                System.out.println("Kostka " + (i + 1) + ": " + dice[i]);
            }
        }
    }
    Wynik programu po tym kroku
    > java Main
    Ile kostek chcesz rzucić?(3 - 10)
    5
    Kostka 1: 3
    Kostka 2: 3
    Kostka 3: 5
    Kostka 4: 5
    Kostka 5: 4
  6. Krok 6: Metoda countPoints: suma oczek powtórzonych

    Kryteria: , , ,

    R.2.1 Program składa się z programu głównego oraz przynajmniej dwóch funkcji (metod): losującej i liczącej punkty (mogą być niedokończone, lub z błędami) oraz zastosowano zmienną typu tablicowego dla liczb całkowitych, wypełnioną wartościami całkowitymi od 1 do 6

    R.2.2 Funkcja/metoda licząca punkty jest typu liczbowego całkowitego i zawiera zapisaną instrukcję zwracającą wartość

    R.2.6 Punkty są liczone jako suma oczek, dla tych wartości, które zostały wylosowane przynajmniej dwa razy

    R.1.2 Kod zapisano z wcięciami dla zagnieżdżeń bloków

    ok. 4 min
    Polecenie z arkusza

    Punkty są sumą oczek, gdy dana liczba została wylosowana dwa razy lub więcej. Program zawiera funkcję / metodę liczącą punkty. Suma punktów jest zwracana z funkcji / metody. W przypadku podejścia strukturalnego funkcja nie może korzystać ze zmiennych globalnych.

    Dla każdej kostki liczymy, ile kostek ma tyle samo oczek (pętla wewnętrzna, razem z nią samą). Jeśli takich kostek jest co najmniej dwie, oczka tej kostki dodajemy do punktów. Metoda ma typ int i zwraca sumę (R.2.2, R.2.6).

    Sprawdźmy na przykładzie 1 z arkusza - 1, 5, 2, 2, 5: jedynka występuje raz, więc jej nie liczymy; każda dwójka występuje dwa razy - dodajemy 2 + 2; każda piątka też - 5 + 5. Razem 14. Przykład 2 - 2, 1, 2, 3, 2: każda z trzech dwójek ma „towarzystwo”, więc 2 + 2 + 2 = 6. Liczenie per kostka samo obsługuje i pary, i trójki.

    konsola/src/Main.java Java zmienione: 16 linii
    import java.util.Scanner;
    import java.util.Random;
    
    public class Main {
        static int[] rollDice(int count) {
            Random random = new Random();
            int[] dice = new int[count];
            for (int i = 0; i < count; i++) {
                dice[i] = random.nextInt(6) + 1;
            }
            return dice;
        }
    
        static int countPoints(int[] dice) {
            int points = 0;
            for (int i = 0; i < dice.length; i++) {
                int repeats = 0;
                for (int j = 0; j < dice.length; j++) {
                    if (dice[j] == dice[i]) {
                        repeats++;
                    }
                }
                if (repeats >= 2) {
                    points += dice[i];
                }
            }
            return points;
        }
    
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int count;
            do {
                System.out.println("Ile kostek chcesz rzucić?(3 - 10)");
                count = scanner.nextInt();
            } while (count < 3 || count > 10);
    
            int[] dice = rollDice(count);
            for (int i = 0; i < dice.length; i++) {
                System.out.println("Kostka " + (i + 1) + ": " + dice[i]);
            }
        }
    }

    Wynik programu bez zmian - taki jak po kroku 5.

  7. Krok 7: Wypisanie liczby punktów

    Kryteria:

    R.2.9 Program wyświetla obliczoną sumę punktów

    ok. 1 min
    Polecenie z arkusza

    Liczy punkty i je wyświetla zgodnie z obrazem 1.

    Wynik metody wypisujemy z komunikatem z obrazu 1 (R.2.9). Podgląd to prawdziwe uruchomienie z pięcioma kostkami; punkty przeliczyliśmy niezależnie z wypisanych oczek - zgadzają się.

    konsola/src/Main.java Java zmienione: 1 linia
    import java.util.Scanner;
    import java.util.Random;
    
    public class Main {
        static int[] rollDice(int count) {
            Random random = new Random();
            int[] dice = new int[count];
            for (int i = 0; i < count; i++) {
                dice[i] = random.nextInt(6) + 1;
            }
            return dice;
        }
    
        static int countPoints(int[] dice) {
            int points = 0;
            for (int i = 0; i < dice.length; i++) {
                int repeats = 0;
                for (int j = 0; j < dice.length; j++) {
                    if (dice[j] == dice[i]) {
                        repeats++;
                    }
                }
                if (repeats >= 2) {
                    points += dice[i];
                }
            }
            return points;
        }
    
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int count;
            do {
                System.out.println("Ile kostek chcesz rzucić?(3 - 10)");
                count = scanner.nextInt();
            } while (count < 3 || count > 10);
    
            int[] dice = rollDice(count);
            for (int i = 0; i < dice.length; i++) {
                System.out.println("Kostka " + (i + 1) + ": " + dice[i]);
            }
            System.out.println("Liczba uzyskanych punktów: " + countPoints(dice));
        }
    }
    Wynik programu po tym kroku
    > java Main
    Ile kostek chcesz rzucić?(3 - 10)
    5
    Kostka 1: 1
    Kostka 2: 2
    Kostka 3: 3
    Kostka 4: 1
    Kostka 5: 6
    Liczba uzyskanych punktów: 2
  8. Krok 8: Pytanie Jeszcze raz? i powtórzenie gry

    Kryteria: , , ,

    R.2.10 Podanie 't' kontynuuje grę, wybranie 'n' przerywa grę

    R.2.4 Zastosowano przynajmniej jedną pętlę do wprowadzania liczby kostek lub sprawdzania zgody na dalsze działanie programu

    R.2.7 Program kompiluje się i uruchamia w konsoli, co udokumentowano zrzutem ekranu. Pytanie o liczbę kostek jest powtarzane tak długo, aż zostanie podana liczba z zakresu 3..10 (sprawdzić dla granicznych: 2 i 11 oraz 3 i 10)

    R.1.1 Kod źródłowy zapisano w sposób czytelny: instrukcje w osobnych liniach, stosowane spacje pomiędzy operatorami, konsekwentnie stosowana wybrana konwencja dla nawiasów klamrowych

    ok. 3 min
    Polecenie z arkusza

    Pyta grającego czy powtórzyć grę, gdy podano: ‘t’: idź do punktu 2, ‘n’: skończ działanie programu.

    Rzut, wypisanie i punkty obejmujemy drugą pętlą do ... while. Na końcu pytamy „Jeszcze raz? (t/n)” i czytamy odpowiedź: scanner.next() zwraca słowo, a charAt(0) jego pierwszy znak - typ char pasuje do odpowiedzi jednoznakowej (R.1.5). Pętla wraca do rzutu (punktu 2 arkusza - bez ponownego pytania o liczbę kostek), dopóki odpowiedź to 't'; 'n' kończy program (R.2.10).

    Podgląd: najpierw zła liczba kostek (2), potem 5 kostek, dwa razy „t” i „n” - trzy rzuty, jak na obrazie 1.

    Typowe błędy

    Porównanie answer == "t" (cudzysłów podwójny) nie skompiluje się przy typie char: znak zapisujemy w apostrofach 't'.

    konsola/src/Main.java Java zmienione: 10 linii
    import java.util.Scanner;
    import java.util.Random;
    
    public class Main {
        static int[] rollDice(int count) {
            Random random = new Random();
            int[] dice = new int[count];
            for (int i = 0; i < count; i++) {
                dice[i] = random.nextInt(6) + 1;
            }
            return dice;
        }
    
        static int countPoints(int[] dice) {
            int points = 0;
            for (int i = 0; i < dice.length; i++) {
                int repeats = 0;
                for (int j = 0; j < dice.length; j++) {
                    if (dice[j] == dice[i]) {
                        repeats++;
                    }
                }
                if (repeats >= 2) {
                    points += dice[i];
                }
            }
            return points;
        }
    
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int count;
            do {
                System.out.println("Ile kostek chcesz rzucić?(3 - 10)");
                count = scanner.nextInt();
            } while (count < 3 || count > 10);
    
            char answer;
            do {
                int[] dice = rollDice(count);
                for (int i = 0; i < dice.length; i++) {
                    System.out.println("Kostka " + (i + 1) + ": " + dice[i]);
                }
                System.out.println("Liczba uzyskanych punktów: " + countPoints(dice));
                System.out.println("Jeszcze raz? (t/n)");
                answer = scanner.next().charAt(0);
            } while (answer == 't');
        }
    }
    Wynik programu po tym kroku
    > java Main
    Ile kostek chcesz rzucić?(3 - 10)
    2
    Ile kostek chcesz rzucić?(3 - 10)
    5
    Kostka 1: 6
    Kostka 2: 6
    Kostka 3: 1
    Kostka 4: 5
    Kostka 5: 1
    Liczba uzyskanych punktów: 14
    Jeszcze raz? (t/n)
    t
    Kostka 1: 5
    Kostka 2: 5
    Kostka 3: 3
    Kostka 4: 2
    Kostka 5: 3
    Liczba uzyskanych punktów: 16
    Jeszcze raz? (t/n)
    t
    Kostka 1: 3
    Kostka 2: 3
    Kostka 3: 4
    Kostka 4: 5
    Kostka 5: 5
    Liczba uzyskanych punktów: 16
    Jeszcze raz? (t/n)
    n
  9. Krok 9: Folder konsolowa: archiwum, źródło i zrzuty

    ok. 2 min
    Polecenie z arkusza

    Kod aplikacji przygotuj do nagrania na płytę. W podfolderze konsolowa powinno znaleźć się archiwum całego projektu o nazwie konsola.zip, skopiowany z projektu plik z kodem źródłowym programu oraz plik wykonywalny, jeżeli istnieje.

    Folder projektu pakujemy do konsola.zip, obok kopiujemy Main.java. Java nie tworzy pliku .exe - skompilowane klasy są w archiwum. Archiwum robimy na końcu pracy, po dopisaniu komentarza z części III.

    Wynik programu bez zmian - taki jak po kroku 8.

  10. Etap 3: Aplikacja mobilna

    Kroki 10-24 · po tym etapie masz 27 z 35 kryteriów (pkt)

    Krok 10: 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.

    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).

    Szablon 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.

    Kosci/app/src/main/java/com/example/kosci/MainActivity.java Java nowy plik
    package com.example.kosci;
    
    import android.os.Bundle;
    
    import androidx.activity.EdgeToEdge;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.graphics.Insets;
    import androidx.core.view.ViewCompat;
    import androidx.core.view.WindowInsetsCompat;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EdgeToEdge.enable(this);
            setContentView(R.layout.activity_main);
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
                Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
                return insets;
            });
        }
    }
    Kosci/app/src/main/res/layout/activity_main.xml XML nowy plik
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  11. Krok 11: Obrazy kości w res/drawable

    ok. 2 min
    Polecenie z arkusza

    Do zbudowania aplikacji zastosuj obrazy z archiwum pliki1.zip zabezpieczonego hasłem Gra^Kosci5.

    Siedem obrazów z archiwum kopiujemy do app/src/main/res/drawable (w Android Studio: Ctrl+C w Eksploratorze, prawy przycisk na drawable → Paste). Każdy plik staje się zasobem: w XML @drawable/k3, w Javie R.drawable.k3. Nazwy zasobów mogą mieć tylko małe litery, cyfry i podkreślenia - nazwy z archiwum spełniają ten warunek.

    Ekran telefonu bez zmian - taki jak po kroku 10.

  12. Krok 12: Pionowy LinearLayout z tłem Beige

    Kryteria: ,

    R.3.1 Zastosowano język znaczników XML/XAML lub inny do opisu interfejsu użytkownika oraz zastosowano rozkład liniowy wertykalny (LinearLayout lub StackLayout, lub VerticalStackLayout, lub inny o tej idei) z zagłębionym rozkładem liniowym horyzontalnym dla obrazów

    R.3.3 Zastosowano kolory tła: rozkład wertykalny lub strona: Beige (#F5F5DC), napis z tytułem: Brown (#A52A2A), oba przyciski: Chocolate (#D2691E), rozkład horyzontalny: biały oraz biały kolor czcionki dla napisu z tytułem gry (w MAUI nazwy kolorów obowiązkowo wielką literą)

    ok. 2 min
    Polecenie z arkusza

    Interfejs użytkownika zapisany za pomocą języka znaczników wspieranego w danym środowisku (np. XAML, XML). Zastosowany rozkład liniowy wertykalny (Linear / Stack lub inny o tej idei). Kolory tła: Rozkład wertykalny lub strona: Beige (#F5F5DC).

    Ekran to elementy jeden pod drugim, więc w widoku Code pliku activity_main.xml zamieniamy ConstraintLayout na LinearLayout z android:orientation="vertical" (R.3.1). Tło #F5F5DC (Beige) dajemy atrybutem android:background (R.3.3).

    Zostawiamy android:id="@+id/main" - kod szablonu w MainActivity szuka tego widoku, ż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ą przy starcie - findViewById(R.id.main) zwraca null.

    Kosci/app/src/main/res/layout/activity_main.xml XML zmienione: 4 linie
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#F5F5DC"
        tools:context=".MainActivity">
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  13. Krok 13: Tytuł gry na brązowym pasku

    Kryteria: , ,

    R.3.2 Umieszczono napis "Gra w kości. Autor" z numerem zdającego, dwa przyciski, pięć obrazów wypełnionych grafiką question.jpg oraz dwa napisy

    R.3.3 Zastosowano kolory tła: rozkład wertykalny lub strona: Beige (#F5F5DC), napis z tytułem: Brown (#A52A2A), oba przyciski: Chocolate (#D2691E), rozkład horyzontalny: biały oraz biały kolor czcionki dla napisu z tytułem gry (w MAUI nazwy kolorów obowiązkowo wielką literą)

    R.3.4 Dobrano marginesy, odstępy i wielkość grafiki tak aby kontrolki nie stykały się ze sobą oraz było widoczne w całości 5 obrazów, napis z tytułem oraz przyciski są wyśrodkowane, pozostałe wypełniają w poziomie całą szerokość strony (np. fill, fillAndExpand, match_parent)

    ok. 3 min
    Polecenie z arkusza

    Napis (etykieta) z tytułem gry: „Gra w kości. Autor ”, dalej wstawiony numer zdającego. Kolory tła: Napis z tytułem strony: Brown (#A52A2A). Biały kolor czcionki dla napisu z tytułem gry. Rozmiar czcionki napisu z tytułem gry jest największy względem innych napisów. Napis z tytułem oraz rozkład horyzontalny wypełniają w poziomie całą szerokość strony.

    TextView z tytułem - na egzaminie po „Autor” wpisujemy numer PESEL, tu stoi Bartosz Bryniarski (R.3.2):

    • layout_width="match_parent" - pasek na całą szerokość ekranu,
    • tło #A52A2A (Brown) i biały tekst #FFFFFF (R.3.3),
    • textSize="24sp" - największa czcionka na ekranie; pozostałe napisy zostaną przy domyślnych 14sp,
    • marginesy górny i dolny 10dp, jak w arkuszu, a padding odsuwa tekst od krawędzi paska.
    Kosci/app/src/main/res/layout/activity_main.xml XML zmienione: 12 linii
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#F5F5DC"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/titleText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:background="#A52A2A"
            android:padding="10dp"
            android:text="Gra w kości. Autor Bartosz Bryniarski"
            android:textColor="#FFFFFF"
            android:textSize="24sp" />
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  14. Krok 14: Przycisk RZUĆ KOŚĆMI

    Kryteria: , ,

    R.3.2 Umieszczono napis "Gra w kości. Autor" z numerem zdającego, dwa przyciski, pięć obrazów wypełnionych grafiką question.jpg oraz dwa napisy

    R.3.3 Zastosowano kolory tła: rozkład wertykalny lub strona: Beige (#F5F5DC), napis z tytułem: Brown (#A52A2A), oba przyciski: Chocolate (#D2691E), rozkład horyzontalny: biały oraz biały kolor czcionki dla napisu z tytułem gry (w MAUI nazwy kolorów obowiązkowo wielką literą)

    R.3.4 Dobrano marginesy, odstępy i wielkość grafiki tak aby kontrolki nie stykały się ze sobą oraz było widoczne w całości 5 obrazów, napis z tytułem oraz przyciski są wyśrodkowane, pozostałe wypełniają w poziomie całą szerokość strony (np. fill, fillAndExpand, match_parent)

    ok. 2 min
    Polecenie z arkusza

    Przycisk o treści „RZUĆ KOŚĆMI”. Kolory tła: Oba przyciski: Chocolate (#D2691E). Napisy z wynikami oraz przyciski są wyśrodkowane.

    Button wyśrodkowany w poziomie atrybutem layout_gravity="center_horizontal" (położenie elementu w rodzicu). Kolor dajemy przez android:backgroundTint, a nie android:background: w motywie Material 3 przycisk rysuje własną zaokrągloną pigułkę i barwi ją kolorem motywu - backgroundTint podmienia właśnie tę barwę na Chocolate #D2691E (R.3.3).

    Typowe błędy

    android:background="#D2691E" na przycisku Material 3 nie zmienia koloru - przycisk zostaje fioletowy, tylko traci zaokrąglenie.

    Kosci/app/src/main/res/layout/activity_main.xml XML zmienione: 10 linii
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#F5F5DC"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/titleText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:background="#A52A2A"
            android:padding="10dp"
            android:text="Gra w kości. Autor Bartosz Bryniarski"
            android:textColor="#FFFFFF"
            android:textSize="24sp" />
    
        <Button
            android:id="@+id/rollButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:backgroundTint="#D2691E"
            android:text="RZUĆ KOŚĆMI" />
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  15. Krok 15: Poziomy rząd pięciu obrazów question.jpg

    Kryteria: , , ,

    R.3.1 Zastosowano język znaczników XML/XAML lub inny do opisu interfejsu użytkownika oraz zastosowano rozkład liniowy wertykalny (LinearLayout lub StackLayout, lub VerticalStackLayout, lub inny o tej idei) z zagłębionym rozkładem liniowym horyzontalnym dla obrazów

    R.3.2 Umieszczono napis "Gra w kości. Autor" z numerem zdającego, dwa przyciski, pięć obrazów wypełnionych grafiką question.jpg oraz dwa napisy

    R.3.3 Zastosowano kolory tła: rozkład wertykalny lub strona: Beige (#F5F5DC), napis z tytułem: Brown (#A52A2A), oba przyciski: Chocolate (#D2691E), rozkład horyzontalny: biały oraz biały kolor czcionki dla napisu z tytułem gry (w MAUI nazwy kolorów obowiązkowo wielką literą)

    R.3.4 Dobrano marginesy, odstępy i wielkość grafiki tak aby kontrolki nie stykały się ze sobą oraz było widoczne w całości 5 obrazów, napis z tytułem oraz przyciski są wyśrodkowane, pozostałe wypełniają w poziomie całą szerokość strony (np. fill, fillAndExpand, match_parent)

    ok. 4 min
    Polecenie z arkusza

    Pięć obrazów w stanie początkowym wypełnionych grafiką question.jpg. Zastosowany rozkład liniowy wertykalny, z zagłębionym rozkładem liniowym horyzontalnym dla pięciu obrazów. Rozkład horyzontalny: biały. Rozmiar i marginesy dla pięciu obrazów należy dobrać tak, aby wszystkie obrazy były widoczne w całości, nie stykały się ze sobą oraz wypełniały całą szerokość rozkładu. Dla emulacji Pixel5 z obrazu 3 zastosowano wysokość obrazu 60 i marginesy 9.

    Zagnieżdżony LinearLayout, tym razem poziomy, na całą szerokość i z białym tłem. W nim pięć ImageView z obrazem @drawable/question i własnymi identyfikatorami die1 - die5 (po nich znajdziemy kontrolki w Javie).

    Żeby pięć obrazów wypełniło całą szerokość na każdym telefonie, dajemy im szerokość 0dp i layout_weight="1": LinearLayout dzieli wolne miejsce w poziomie na pięć równych części. Wysokość 60dp i marginesy 9dp z arkusza - obrazy się nie stykają, a ImageView sam zmniejsza grafikę do ramki z zachowaniem proporcji (R.3.4).

    Typowe błędy

    Pięć obrazów o stałej szerokości (np. 80dp) na wąskim telefonie wyjdzie poza ekran - ostatnia kość będzie ucięta (R.3.4).

    Kosci/app/src/main/res/layout/activity_main.xml XML zmienione: 55 linii
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#F5F5DC"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/titleText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:background="#A52A2A"
            android:padding="10dp"
            android:text="Gra w kości. Autor Bartosz Bryniarski"
            android:textColor="#FFFFFF"
            android:textSize="24sp" />
    
        <Button
            android:id="@+id/rollButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:backgroundTint="#D2691E"
            android:text="RZUĆ KOŚĆMI" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:background="#FFFFFF"
            android:orientation="horizontal">
    
            <ImageView
                android:id="@+id/die1"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 1"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die2"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 2"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die3"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 3"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die4"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 4"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die5"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 5"
                android:src="@drawable/question" />
    
        </LinearLayout>
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  16. Krok 16: Napisy z wynikiem losowania i wynikiem gry

    Kryteria: ,

    R.3.2 Umieszczono napis "Gra w kości. Autor" z numerem zdającego, dwa przyciski, pięć obrazów wypełnionych grafiką question.jpg oraz dwa napisy

    R.3.4 Dobrano marginesy, odstępy i wielkość grafiki tak aby kontrolki nie stykały się ze sobą oraz było widoczne w całości 5 obrazów, napis z tytułem oraz przyciski są wyśrodkowane, pozostałe wypełniają w poziomie całą szerokość strony (np. fill, fillAndExpand, match_parent)

    ok. 2 min
    Polecenie z arkusza

    Napis „Wynik tego losowania: ”. Napis „Wynik gry: ”. Marginesy dla pozostałych kontrolek i elementów strony należy dobrać tak, aby kontrolki nie przylegały do siebie w pionie i w poziomie. Dla emulacji Pixel5 z obrazu 3 zastosowano marginesy górny i dolny 10.

    Dwa TextView, wyśrodkowane jak przyciski, z marginesami 10dp i identyfikatorami - kod będzie dopisywał do nich liczby (rollResultText, gameResultText).

    Kosci/app/src/main/res/layout/activity_main.xml XML zmienione: 18 linii
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#F5F5DC"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/titleText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:background="#A52A2A"
            android:padding="10dp"
            android:text="Gra w kości. Autor Bartosz Bryniarski"
            android:textColor="#FFFFFF"
            android:textSize="24sp" />
    
        <Button
            android:id="@+id/rollButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:backgroundTint="#D2691E"
            android:text="RZUĆ KOŚĆMI" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:background="#FFFFFF"
            android:orientation="horizontal">
    
            <ImageView
                android:id="@+id/die1"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 1"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die2"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 2"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die3"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 3"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die4"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 4"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die5"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 5"
                android:src="@drawable/question" />
    
        </LinearLayout>
    
        <TextView
            android:id="@+id/rollResultText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:text="Wynik tego losowania: " />
    
        <TextView
            android:id="@+id/gameResultText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:text="Wynik gry: " />
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  17. Krok 17: Przycisk RESETUJ WYNIK

    Kryteria: , ,

    R.3.2 Umieszczono napis "Gra w kości. Autor" z numerem zdającego, dwa przyciski, pięć obrazów wypełnionych grafiką question.jpg oraz dwa napisy

    R.3.3 Zastosowano kolory tła: rozkład wertykalny lub strona: Beige (#F5F5DC), napis z tytułem: Brown (#A52A2A), oba przyciski: Chocolate (#D2691E), rozkład horyzontalny: biały oraz biały kolor czcionki dla napisu z tytułem gry (w MAUI nazwy kolorów obowiązkowo wielką literą)

    R.3.10 Aplikacja kompiluje się i uruchamia w emulatorze, co udokumentowano zrzutem ekranu. Jej układ jest zgodny z obrazem 3 w arkuszu egzaminacyjnym

    ok. 1 min
    Polecenie z arkusza

    Przycisk o treści „RESETUJ WYNIK”. Rozmieszczenie elementów zgodne z obrazami 3 i 4.

    Drugi przycisk w tym samym stylu co pierwszy. Ekran ma już wszystkie elementy z obrazów 3 i 4: tytuł, dwa przyciski, pięć obrazów i dwa napisy (R.3.2, R.3.10).

    Kosci/app/src/main/res/layout/activity_main.xml XML zmienione: 10 linii
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#F5F5DC"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/titleText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:background="#A52A2A"
            android:padding="10dp"
            android:text="Gra w kości. Autor Bartosz Bryniarski"
            android:textColor="#FFFFFF"
            android:textSize="24sp" />
    
        <Button
            android:id="@+id/rollButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:backgroundTint="#D2691E"
            android:text="RZUĆ KOŚĆMI" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:background="#FFFFFF"
            android:orientation="horizontal">
    
            <ImageView
                android:id="@+id/die1"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 1"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die2"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 2"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die3"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 3"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die4"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 4"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die5"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 5"
                android:src="@drawable/question" />
    
        </LinearLayout>
    
        <TextView
            android:id="@+id/rollResultText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:text="Wynik tego losowania: " />
    
        <TextView
            android:id="@+id/gameResultText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:text="Wynik gry: " />
    
        <Button
            android:id="@+id/resetButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:backgroundTint="#D2691E"
            android:text="RESETUJ WYNIK" />
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  18. Krok 18: Odwołania do kontrolek przez findViewById

    Kryteria:

    R.3.6 Program odwołuje się do kontrolek w sposób właściwy dla danego środowiska programistycznego. Wystarczy, że zastosowano poprawnie dla jednej kontrolki

    ok. 3 min
    Polecenie z arkusza

    Do wykonania aplikacji można wykorzystać fragmenty kodu z aplikacji konsolowej. Dla uproszczenia aplikacji, gra odbywa się zawsze na pięciu kościach.

    Kod potrzebuje dostępu do pięciu obrazów i dwóch napisów. Zapisujemy je w polach aktywności: obrazy w tablicy ImageView[5] (pięć kości - tyle, ile w arkuszu), napisy w dwóch polach TextView. Wypełniamy je w onCreate, po setContentView, metodą findViewById(R.id....) - szuka w układzie widoku o podanym identyfikatorze z XML (R.3.6).

    Kosci/app/src/main/java/com/example/kosci/MainActivity.java Java zmienione: 14 linii
    package com.example.kosci;
    
    import android.os.Bundle;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import androidx.activity.EdgeToEdge;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.graphics.Insets;
    import androidx.core.view.ViewCompat;
    import androidx.core.view.WindowInsetsCompat;
    
    public class MainActivity extends AppCompatActivity {
    
        private ImageView[] diceImages = new ImageView[5];
        private TextView rollResultText;
        private TextView gameResultText;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EdgeToEdge.enable(this);
            setContentView(R.layout.activity_main);
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
                Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
                return insets;
            });
    
            diceImages[0] = findViewById(R.id.die1);
            diceImages[1] = findViewById(R.id.die2);
            diceImages[2] = findViewById(R.id.die3);
            diceImages[3] = findViewById(R.id.die4);
            diceImages[4] = findViewById(R.id.die5);
            rollResultText = findViewById(R.id.rollResultText);
            gameResultText = findViewById(R.id.gameResultText);
        }
    }

    Ekran telefonu bez zmian - taki jak po kroku 17.

  19. Krok 19: Metoda rollDice podpięta pod przycisk

    Kryteria:

    R.3.5 Program obsługuje przynajmniej jedno zdarzenie kliknięcia przycisku w sposób właściwy dla danego środowiska programistycznego. Wystarczy, że kontrolka przycisku jest odpowiednio powiązana ze zdarzeniem

    ok. 3 min
    Polecenie z arkusza

    Po wciśnięciu przycisku „RZUĆ KOŚĆMI”: Losowanych jest 5 liczb z zakresu od 1 do 6.

    Kliknięcie wiążemy w XML atrybutem android:onClick="rollDice": Android wywoła metodę aktywności o tej nazwie. Musi być publiczna, zwracać void i przyjmować jeden parametr View - kliknięty przycisk (R.3.5).

    W środku losowanie z konsoli: pięć liczb od 1 do 6 do tablicy. Na ekranie jeszcze nic się nie zmienia - obrazy podepniemy w następnym kroku.

    Typowe błędy

    Literówka w nazwie metody w android:onClick (np. rolDice) kompiluje się, ale aplikacja zamyka się przy pierwszym kliknięciu.

    Kosci/app/src/main/java/com/example/kosci/MainActivity.java Java zmienione: 11 linii
    package com.example.kosci;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import androidx.activity.EdgeToEdge;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.graphics.Insets;
    import androidx.core.view.ViewCompat;
    import androidx.core.view.WindowInsetsCompat;
    
    import java.util.Random;
    
    public class MainActivity extends AppCompatActivity {
    
        private ImageView[] diceImages = new ImageView[5];
        private TextView rollResultText;
        private TextView gameResultText;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EdgeToEdge.enable(this);
            setContentView(R.layout.activity_main);
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
                Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
                return insets;
            });
    
            diceImages[0] = findViewById(R.id.die1);
            diceImages[1] = findViewById(R.id.die2);
            diceImages[2] = findViewById(R.id.die3);
            diceImages[3] = findViewById(R.id.die4);
            diceImages[4] = findViewById(R.id.die5);
            rollResultText = findViewById(R.id.rollResultText);
            gameResultText = findViewById(R.id.gameResultText);
        }
    
        public void rollDice(View view) {
            Random random = new Random();
            int[] dice = new int[5];
            for (int i = 0; i < 5; i++) {
                dice[i] = random.nextInt(6) + 1;
            }
        }
    }
    Kosci/app/src/main/res/layout/activity_main.xml XML zmienione: 1 linia
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#F5F5DC"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/titleText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:background="#A52A2A"
            android:padding="10dp"
            android:text="Gra w kości. Autor Bartosz Bryniarski"
            android:textColor="#FFFFFF"
            android:textSize="24sp" />
    
        <Button
            android:id="@+id/rollButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:backgroundTint="#D2691E"
            android:onClick="rollDice"
            android:text="RZUĆ KOŚĆMI" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:background="#FFFFFF"
            android:orientation="horizontal">
    
            <ImageView
                android:id="@+id/die1"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 1"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die2"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 2"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die3"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 3"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die4"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 4"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die5"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 5"
                android:src="@drawable/question" />
    
        </LinearLayout>
    
        <TextView
            android:id="@+id/rollResultText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:text="Wynik tego losowania: " />
    
        <TextView
            android:id="@+id/gameResultText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:text="Wynik gry: " />
    
        <Button
            android:id="@+id/resetButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:backgroundTint="#D2691E"
            android:text="RESETUJ WYNIK" />
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  20. Krok 20: Obraz kości odpowiadający wyrzuconym oczkom

    Kryteria:

    R.3.7 Po wciśnięciu przycisku RZUĆ KOŚĆMI wyświetlane są wylosowane liczby w postaci 5 obrazów kości, każdy obraz odpowiada wyrzuconej liczbie oczek (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    ok. 3 min
    Polecenie z arkusza

    Losowanych jest 5 liczb z zakresu od 1 do 6, które są wyświetlone w postaci pięciu obrazów kości.

    Identyfikatory sześciu obrazów zbieramy w tablicy diceImageIds w kolejności oczek: pod indeksem 0 jest k1, pod 5 - k6. Obraz dla liczby oczek n to więc diceImageIds[n - 1], a setImageResource wstawia go do kontrolki (R.3.7). Kliknij w podglądzie „RZUĆ KOŚĆMI” - kości się zmieniają.

    Kosci/app/src/main/java/com/example/kosci/MainActivity.java Java zmienione: 5 linii
    package com.example.kosci;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import androidx.activity.EdgeToEdge;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.graphics.Insets;
    import androidx.core.view.ViewCompat;
    import androidx.core.view.WindowInsetsCompat;
    
    import java.util.Random;
    
    public class MainActivity extends AppCompatActivity {
    
        private ImageView[] diceImages = new ImageView[5];
        private TextView rollResultText;
        private TextView gameResultText;
        private final int[] diceImageIds = {
                R.drawable.k1, R.drawable.k2, R.drawable.k3,
                R.drawable.k4, R.drawable.k5, R.drawable.k6
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EdgeToEdge.enable(this);
            setContentView(R.layout.activity_main);
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
                Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
                return insets;
            });
    
            diceImages[0] = findViewById(R.id.die1);
            diceImages[1] = findViewById(R.id.die2);
            diceImages[2] = findViewById(R.id.die3);
            diceImages[3] = findViewById(R.id.die4);
            diceImages[4] = findViewById(R.id.die5);
            rollResultText = findViewById(R.id.rollResultText);
            gameResultText = findViewById(R.id.gameResultText);
        }
    
        public void rollDice(View view) {
            Random random = new Random();
            int[] dice = new int[5];
            for (int i = 0; i < 5; i++) {
                dice[i] = random.nextInt(6) + 1;
                diceImages[i].setImageResource(diceImageIds[dice[i] - 1]);
            }
        }
    }
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  21. Krok 21: Punkty za rzut w napisie z wynikiem losowania

    Kryteria:

    R.3.8 Po wciśnięciu przycisku RZUĆ KOŚĆMI wyświetlana jest liczba punktów za wykonany rzut (kryterium poprawne również, gdy algorytm nieprawidłowo zaimplementowany) oraz wyświetlany jest wynik gry, który jest powiększony o wynik aktualnego rzutu (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    ok. 2 min
    Polecenie z arkusza

    Obliczana jest suma punktów dla rzutu kośćmi zgodnie z algorytmem podanym w opisie aplikacji konsolowej oraz wynik wyświetlany jest w napisie z wynikiem losowania.

    Metodę countPoints kopiujemy z konsoli bez zmian (bez static - w aktywności to zwykła metoda prywatna). Wynik wstawiamy do napisu metodą setText (R.3.8).

    Kosci/app/src/main/java/com/example/kosci/MainActivity.java Java zmienione: 18 linii
    package com.example.kosci;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import androidx.activity.EdgeToEdge;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.graphics.Insets;
    import androidx.core.view.ViewCompat;
    import androidx.core.view.WindowInsetsCompat;
    
    import java.util.Random;
    
    public class MainActivity extends AppCompatActivity {
    
        private ImageView[] diceImages = new ImageView[5];
        private TextView rollResultText;
        private TextView gameResultText;
        private final int[] diceImageIds = {
                R.drawable.k1, R.drawable.k2, R.drawable.k3,
                R.drawable.k4, R.drawable.k5, R.drawable.k6
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EdgeToEdge.enable(this);
            setContentView(R.layout.activity_main);
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
                Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
                return insets;
            });
    
            diceImages[0] = findViewById(R.id.die1);
            diceImages[1] = findViewById(R.id.die2);
            diceImages[2] = findViewById(R.id.die3);
            diceImages[3] = findViewById(R.id.die4);
            diceImages[4] = findViewById(R.id.die5);
            rollResultText = findViewById(R.id.rollResultText);
            gameResultText = findViewById(R.id.gameResultText);
        }
    
        private int countPoints(int[] dice) {
            int points = 0;
            for (int i = 0; i < dice.length; i++) {
                int repeats = 0;
                for (int j = 0; j < dice.length; j++) {
                    if (dice[j] == dice[i]) {
                        repeats++;
                    }
                }
                if (repeats >= 2) {
                    points += dice[i];
                }
            }
            return points;
        }
    
        public void rollDice(View view) {
            Random random = new Random();
            int[] dice = new int[5];
            for (int i = 0; i < 5; i++) {
                dice[i] = random.nextInt(6) + 1;
                diceImages[i].setImageResource(diceImageIds[dice[i] - 1]);
            }
            int points = countPoints(dice);
            rollResultText.setText("Wynik tego losowania: " + points);
        }
    }
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  22. Krok 22: Wynik gry rośnie o wynik rzutu

    Kryteria:

    R.3.8 Po wciśnięciu przycisku RZUĆ KOŚĆMI wyświetlana jest liczba punktów za wykonany rzut (kryterium poprawne również, gdy algorytm nieprawidłowo zaimplementowany) oraz wyświetlany jest wynik gry, który jest powiększony o wynik aktualnego rzutu (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    ok. 2 min
    Polecenie z arkusza

    Wynik gry jest powiększany o obliczony wynik rzutu i wyświetlany w napisie z wynikiem gry.

    Wynik gry musi przetrwać między kliknięciami, więc trzymamy go w polu aktywności gameScore, a nie w zmiennej lokalnej metody (ta znika po jej zakończeniu). Po każdym rzucie dodajemy punkty i wypisujemy sumę (R.3.8). Kliknij kilka razy „RZUĆ KOŚĆMI” - wynik gry rośnie (obraz 5).

    Typowe błędy

    int gameScore = 0; wewnątrz rollDice zeruje wynik przy każdym kliknięciu - wynik gry zawsze równa się wynikowi ostatniego rzutu.

    Kosci/app/src/main/java/com/example/kosci/MainActivity.java Java zmienione: 3 linie
    package com.example.kosci;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import androidx.activity.EdgeToEdge;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.graphics.Insets;
    import androidx.core.view.ViewCompat;
    import androidx.core.view.WindowInsetsCompat;
    
    import java.util.Random;
    
    public class MainActivity extends AppCompatActivity {
    
        private ImageView[] diceImages = new ImageView[5];
        private TextView rollResultText;
        private TextView gameResultText;
        private int gameScore = 0;
        private final int[] diceImageIds = {
                R.drawable.k1, R.drawable.k2, R.drawable.k3,
                R.drawable.k4, R.drawable.k5, R.drawable.k6
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EdgeToEdge.enable(this);
            setContentView(R.layout.activity_main);
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
                Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
                return insets;
            });
    
            diceImages[0] = findViewById(R.id.die1);
            diceImages[1] = findViewById(R.id.die2);
            diceImages[2] = findViewById(R.id.die3);
            diceImages[3] = findViewById(R.id.die4);
            diceImages[4] = findViewById(R.id.die5);
            rollResultText = findViewById(R.id.rollResultText);
            gameResultText = findViewById(R.id.gameResultText);
        }
    
        private int countPoints(int[] dice) {
            int points = 0;
            for (int i = 0; i < dice.length; i++) {
                int repeats = 0;
                for (int j = 0; j < dice.length; j++) {
                    if (dice[j] == dice[i]) {
                        repeats++;
                    }
                }
                if (repeats >= 2) {
                    points += dice[i];
                }
            }
            return points;
        }
    
        public void rollDice(View view) {
            Random random = new Random();
            int[] dice = new int[5];
            for (int i = 0; i < 5; i++) {
                dice[i] = random.nextInt(6) + 1;
                diceImages[i].setImageResource(diceImageIds[dice[i] - 1]);
            }
            int points = countPoints(dice);
            rollResultText.setText("Wynik tego losowania: " + points);
            gameScore += points;
            gameResultText.setText("Wynik gry: " + gameScore);
        }
    }
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  23. Krok 23: RESETUJ WYNIK: znaki zapytania i zera

    Kryteria: ,

    R.3.9 Po wciśnięciu przycisku „RESETUJ WYNIK” zerowany jest wynik gry oraz wyświetlane są oba wyniki jako 0 (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)

    R.3.5 Program obsługuje przynajmniej jedno zdarzenie kliknięcia przycisku w sposób właściwy dla danego środowiska programistycznego. Wystarczy, że kontrolka przycisku jest odpowiednio powiązana ze zdarzeniem

    ok. 2 min
    Polecenie z arkusza

    Po wciśnięciu przycisku „RESETUJ WYNIK” (obraz 6): Pięć obrazów kości wypełnione zostaje grafiką question.jpg. Wynik całej gry jest resetowany do wartości 0. W napisach dotyczących wyniku losowania i wyniku gry jest zapisana wartość 0.

    Druga metoda podpięta atrybutem onClick drugiego przycisku: wraca obraz question we wszystkich pięciu kontrolkach, pole gameScore dostaje 0, a oba napisy - wartość 0 (R.3.9). Obraz 6 pokazuje dokładnie ten stan.

    Kosci/app/src/main/java/com/example/kosci/MainActivity.java Java zmienione: 9 linii
    package com.example.kosci;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import androidx.activity.EdgeToEdge;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.graphics.Insets;
    import androidx.core.view.ViewCompat;
    import androidx.core.view.WindowInsetsCompat;
    
    import java.util.Random;
    
    public class MainActivity extends AppCompatActivity {
    
        private ImageView[] diceImages = new ImageView[5];
        private TextView rollResultText;
        private TextView gameResultText;
        private int gameScore = 0;
        private final int[] diceImageIds = {
                R.drawable.k1, R.drawable.k2, R.drawable.k3,
                R.drawable.k4, R.drawable.k5, R.drawable.k6
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EdgeToEdge.enable(this);
            setContentView(R.layout.activity_main);
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
                Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
                return insets;
            });
    
            diceImages[0] = findViewById(R.id.die1);
            diceImages[1] = findViewById(R.id.die2);
            diceImages[2] = findViewById(R.id.die3);
            diceImages[3] = findViewById(R.id.die4);
            diceImages[4] = findViewById(R.id.die5);
            rollResultText = findViewById(R.id.rollResultText);
            gameResultText = findViewById(R.id.gameResultText);
        }
    
        private int countPoints(int[] dice) {
            int points = 0;
            for (int i = 0; i < dice.length; i++) {
                int repeats = 0;
                for (int j = 0; j < dice.length; j++) {
                    if (dice[j] == dice[i]) {
                        repeats++;
                    }
                }
                if (repeats >= 2) {
                    points += dice[i];
                }
            }
            return points;
        }
    
        public void rollDice(View view) {
            Random random = new Random();
            int[] dice = new int[5];
            for (int i = 0; i < 5; i++) {
                dice[i] = random.nextInt(6) + 1;
                diceImages[i].setImageResource(diceImageIds[dice[i] - 1]);
            }
            int points = countPoints(dice);
            rollResultText.setText("Wynik tego losowania: " + points);
            gameScore += points;
            gameResultText.setText("Wynik gry: " + gameScore);
        }
    
        public void resetScore(View view) {
            for (int i = 0; i < 5; i++) {
                diceImages[i].setImageResource(R.drawable.question);
            }
            gameScore = 0;
            rollResultText.setText("Wynik tego losowania: 0");
            gameResultText.setText("Wynik gry: 0");
        }
    }
    Kosci/app/src/main/res/layout/activity_main.xml XML zmienione: 1 linia
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:background="#F5F5DC"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/titleText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:background="#A52A2A"
            android:padding="10dp"
            android:text="Gra w kości. Autor Bartosz Bryniarski"
            android:textColor="#FFFFFF"
            android:textSize="24sp" />
    
        <Button
            android:id="@+id/rollButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:backgroundTint="#D2691E"
            android:onClick="rollDice"
            android:text="RZUĆ KOŚĆMI" />
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:background="#FFFFFF"
            android:orientation="horizontal">
    
            <ImageView
                android:id="@+id/die1"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 1"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die2"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 2"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die3"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 3"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die4"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 4"
                android:src="@drawable/question" />
    
            <ImageView
                android:id="@+id/die5"
                android:layout_width="0dp"
                android:layout_height="60dp"
                android:layout_weight="1"
                android:layout_margin="9dp"
                android:contentDescription="Kość 5"
                android:src="@drawable/question" />
    
        </LinearLayout>
    
        <TextView
            android:id="@+id/rollResultText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:text="Wynik tego losowania: " />
    
        <TextView
            android:id="@+id/gameResultText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:text="Wynik gry: " />
    
        <Button
            android:id="@+id/resetButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="10dp"
            android:backgroundTint="#D2691E"
            android:onClick="resetScore"
            android:text="RESETUJ WYNIK" />
    
    </LinearLayout>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  24. Krok 24: Uruchomienie w emulatorze i folder mobilna

    Kryteria: ,

    R.3.10 Aplikacja kompiluje się i uruchamia w emulatorze, co udokumentowano zrzutem ekranu. Jej układ jest zgodny z obrazem 3 w arkuszu egzaminacyjnym

    R.4.7 Zapisano 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. W podfolderze mobilna powinno znaleźć się archiwum całego projektu o nazwie mobilna.zip, skopiowane z projektu plik (lub pliki) z kodem źródłowym interfejsu użytkownika (XAML lub XML) oraz plik źródłowy kodu skojarzonego z interfejsem użytkownika.

    Uruchamiamy aplikację zielonym trójkątem Run na emulatorze. Zrzuty całego ekranu z Android Studio i emulatorem: stan początkowy (obraz 4), po kilku rzutach (obraz 5) i po resecie (obraz 6) - w folderze dokumentacja (R.3.10, R.4.7).

    W folderze mobilna: mobilna.zip z całym projektem Kosci, activity_main.xml i MainActivity.java.

    Ekran telefonu bez zmian - taki jak po kroku 23.

  25. Etap 4: Dokumentacja

    Kroki 25-27 · po tym etapie masz 35 z 35 kryteriów (pkt)

    Krok 25: Nagłówek metody countPoints według listingu 1

    Kryteria: , , , ,

    R.4.1 Dla jednej z funkcji/metody z aplikacji konsolowej zapisano nagłówek w postaci komentarza zgodny z Listingiem 1 z arkusza egzaminacyjnego (nie liczymy gwiazdek), komentarz może być wieloliniowy lub kilka jednoliniowych lub Docstrings (potrójny cudzysłów) - w tym przypadku opis znajduje się pod nazwą funkcji

    R.4.2 W komentarzu ujęto nazwę i opis działania funkcji / metody

    R.4.3 W komentarzu ujęto nazwy i opis wszystkich parametrów funkcji / metody

    R.4.4 W przypadku gdy funkcja / metoda zwraca wartość, ujęto w komentarzu opis tej wartości. W przeciwnym przypadku zapisano void, brak itp.

    R.4.5 W komentarzu ujęto numer zdającego

    ok. 4 min
    Polecenie z arkusza

    W kodzie źródłowym aplikacji konsolowej za pomocą komentarza utwórz nagłówek wybranej funkcji (metody) według wzoru z listingu 1. Komentarz powinien znaleźć się nad lub pod nazwą funkcji. W miejscu nawiasów <> należy podać odpowiednie opisy.

    Komentarz wieloliniowy nad metodą, z polami listingu 1 (R.4.1): nazwa i opis działania (R.4.2), parametr dice z opisem (R.4.3), zwracany typ int z opisem (R.4.4) i autor (R.4.5). Na egzaminie w polu autor wpisujemy numer PESEL - tu stoi Bartosz Bryniarski.

    konsola/src/Main.java Java zmienione: 10 linii
    import java.util.Scanner;
    import java.util.Random;
    
    public class Main {
        static int[] rollDice(int count) {
            Random random = new Random();
            int[] dice = new int[count];
            for (int i = 0; i < count; i++) {
                dice[i] = random.nextInt(6) + 1;
            }
            return dice;
        }
    
        /*
        ************************************************
          nazwa:     countPoints
          opis:      liczy punkty za rzut kośćmi - sumę oczek tych kości, których liczba oczek
                     wypadła co najmniej dwa razy
          parametry: dice - tablica z liczbami oczek wyrzuconymi na kolejnych kościach
          zwracany typ i opis: int - liczba punktów za rzut
          autor:     Bartosz Bryniarski
        ************************************************
        */
        static int countPoints(int[] dice) {
            int points = 0;
            for (int i = 0; i < dice.length; i++) {
                int repeats = 0;
                for (int j = 0; j < dice.length; j++) {
                    if (dice[j] == dice[i]) {
                        repeats++;
                    }
                }
                if (repeats >= 2) {
                    points += dice[i];
                }
            }
            return points;
        }
    
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int count;
            do {
                System.out.println("Ile kostek chcesz rzucić?(3 - 10)");
                count = scanner.nextInt();
            } while (count < 3 || count > 10);
    
            char answer;
            do {
                int[] dice = rollDice(count);
                for (int i = 0; i < dice.length; i++) {
                    System.out.println("Kostka " + (i + 1) + ": " + dice[i]);
                }
                System.out.println("Liczba uzyskanych punktów: " + countPoints(dice));
                System.out.println("Jeszcze raz? (t/n)");
                answer = scanner.next().charAt(0);
            } while (answer == 't');
        }
    }
    Wynik programu po tym kroku
    > java Main
    Ile kostek chcesz rzucić?(3 - 10)
    2
    Ile kostek chcesz rzucić?(3 - 10)
    5
    Kostka 1: 3
    Kostka 2: 4
    Kostka 3: 2
    Kostka 4: 1
    Kostka 5: 4
    Liczba uzyskanych punktów: 8
    Jeszcze raz? (t/n)
    t
    Kostka 1: 6
    Kostka 2: 3
    Kostka 3: 3
    Kostka 4: 1
    Kostka 5: 2
    Liczba uzyskanych punktów: 6
    Jeszcze raz? (t/n)
    t
    Kostka 1: 3
    Kostka 2: 6
    Kostka 3: 3
    Kostka 4: 3
    Kostka 5: 2
    Liczba uzyskanych punktów: 9
    Jeszcze raz? (t/n)
    n
  26. Krok 26: Zrzuty konsoli

    Kryteria: , ,

    R.1.6 Podjęto próbę skompilowania lub interpretowania kodu, co udokumentowano zrzutem ekranowym przedstawiającym uruchomiony program ew. kompilację lub skrypt

    R.2.7 Program kompiluje się i uruchamia w konsoli, co udokumentowano zrzutem ekranu. Pytanie o liczbę kostek jest powtarzane tak długo, aż zostanie podana liczba z zakresu 3..10 (sprawdzić dla granicznych: 2 i 11 oraz 3 i 10)

    R.4.6 Zapisano przynajmniej jeden zrzut ekranu z uruchomienia lub kompilacji aplikacji konsolowej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja

    ok. 2 min
    Polecenie z arkusza

    Wykonaj zrzuty ekranu dokumentujące uruchomienie aplikacji utworzonych podczas egzaminu. Zrzuty powinny obejmować cały obszar ekranu monitora z widocznym paskiem zadań.

    Uruchamiamy program w IntelliJ: zła liczba kostek, potem poprawna, kilka rzutów z „t” i „n” na końcu. Zrzut całego ekranu z oknem Run i paskiem zadań - do folderu dokumentacja (R.1.6, R.2.7, R.4.6). Obraz 2 arkusza pokazuje dokładnie powtórzone pytanie o liczbę kostek - warto mieć je na zrzucie.

    Wynik programu bez zmian - taki jak po kroku 25.

  27. Krok 27: Dokument egzamin

    Kryteria:

    R.4.8 Dokumentacja zawiera nazwy: systemu operacyjnego, środowisk programistycznych, emulatora oraz języków programowania

    ok. 2 min
    Polecenie z arkusza

    W edytorze tekstu pakietu biurowego utwórz plik z dokumentacją i nazwij go egzamin. Dokument powinien zawierać nazwy: systemu operacyjnego, środowisk programistycznych, emulatora oraz języków programowania.

    W Wordzie albo Writerze dokument egzamin w folderze dokumentacja. W tym arkuszu klucz wymaga także nazwy emulatora (R.4.8). Plik obok to treść tekstowa dokumentu.

    egzamin.txt Tekst nowy plik
    System operacyjny: Windows 11
    Środowiska programistyczne: IntelliJ IDEA (aplikacja konsolowa), Android Studio (aplikacja mobilna)
    Emulator: Pixel 8 (Android 16, API 36) z Android Studio
    Języki programowania: Java (aplikacja konsolowa i mobilna), XML (układ aplikacji mobilnej)

    Wynik programu bez zmian - taki jak po kroku 25.

  28. Etap 5: Dobre praktyki (poza kluczem)

    Kroki 28-29 · po tym etapie masz 35 z 35 kryteriów (pkt)

    Krok 28: Konsola: tekst zamiast liczby i odpowiedź inna niż t/n

    ok. 3 min
    Polecenie z arkusza

    Program powinien podejmować zrozumiałą komunikację z użytkownikiem.

    Dwie luki wersji egzaminacyjnej:

    • scanner.nextInt() na słowie „pięć” rzuca wyjątek InputMismatchException i kończy program. hasNextInt() najpierw sprawdza, czy następne słowo jest liczbą; jeśli nie, pomijamy je i pytamy dalej,
    • odpowiedź „x” kończyła grę jak „n”. Teraz program pyta, dopóki nie dostanie t albo n, a Character.toLowerCase przyjmuje też wielkie T i N.

    Podgląd: „pięć”, potem 4 kostki, „x”, „T” i „n”. Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    konsola/src/Main.java Java zmienione: 11 linii
    import java.util.Scanner;
    import java.util.Random;
    
    public class Main {
        static int[] rollDice(int count) {
            Random random = new Random();
            int[] dice = new int[count];
            for (int i = 0; i < count; i++) {
                dice[i] = random.nextInt(6) + 1;
            }
            return dice;
        }
    
        /*
        ************************************************
          nazwa:     countPoints
          opis:      liczy punkty za rzut kośćmi - sumę oczek tych kości, których liczba oczek
                     wypadła co najmniej dwa razy
          parametry: dice - tablica z liczbami oczek wyrzuconymi na kolejnych kościach
          zwracany typ i opis: int - liczba punktów za rzut
          autor:     Bartosz Bryniarski
        ************************************************
        */
        static int countPoints(int[] dice) {
            int points = 0;
            for (int i = 0; i < dice.length; i++) {
                int repeats = 0;
                for (int j = 0; j < dice.length; j++) {
                    if (dice[j] == dice[i]) {
                        repeats++;
                    }
                }
                if (repeats >= 2) {
                    points += dice[i];
                }
            }
            return points;
        }
    
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            int count = 0;
            do {
                System.out.println("Ile kostek chcesz rzucić?(3 - 10)");
                if (scanner.hasNextInt()) {
                    count = scanner.nextInt();
                } else {
                    scanner.next();   // pomijamy słowo, które nie jest liczbą
                }
            } while (count < 3 || count > 10);
    
            char answer;
            do {
                int[] dice = rollDice(count);
                for (int i = 0; i < dice.length; i++) {
                    System.out.println("Kostka " + (i + 1) + ": " + dice[i]);
                }
                System.out.println("Liczba uzyskanych punktów: " + countPoints(dice));
                System.out.println("Jeszcze raz? (t/n)");
                answer = Character.toLowerCase(scanner.next().charAt(0));
                while (answer != 't' && answer != 'n') {
                    System.out.println("Wpisz t albo n:");
                    answer = Character.toLowerCase(scanner.next().charAt(0));
                }
            } while (answer == 't');
        }
    }
    Wynik programu po tym kroku
    > java Main
    Ile kostek chcesz rzucić?(3 - 10)
    pięć
    Ile kostek chcesz rzucić?(3 - 10)
    4
    Kostka 1: 2
    Kostka 2: 4
    Kostka 3: 6
    Kostka 4: 4
    Liczba uzyskanych punktów: 8
    Jeszcze raz? (t/n)
    x
    Wpisz t albo n:
    T
    Kostka 1: 4
    Kostka 2: 4
    Kostka 3: 5
    Kostka 4: 5
    Liczba uzyskanych punktów: 18
    Jeszcze raz? (t/n)
    n
  29. Krok 29: Android: napisy w strings.xml i jedna metoda wyświetlania wyników

    ok. 4 min
    Polecenie z arkusza

    Aplikacja powinna być zapisana czytelnie, z zachowaniem zasad czystego formatowania kodu, należy stosować znaczące nazwy zmiennych i funkcji.

    Trzy poprawki w aktywności:

    • teksty wyników przenosimy do strings.xml z miejscem na liczbę %d; getString(R.string.roll_result, points) wstawia liczbę w to miejsce. Teksty w zasobach można przetłumaczyć bez zmiany kodu, a Android Studio przestaje ostrzegać o napisach wpisanych na sztywno,
    • oba napisy ustawia jedna metoda showScores - rzut i reset korzystają z tego samego kodu, więc format wyników nie rozjedzie się między nimi,
    • Random tworzymy raz, jako pole aktywności, a nie przy każdym kliknięciu.

    Na egzaminie wystarczy wersja wcześniejsza - klucz tego nie sprawdza.

    Kosci/app/src/main/java/com/example/kosci/MainActivity.java Java zmienione: 9 linii
    package com.example.kosci;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import androidx.activity.EdgeToEdge;
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.graphics.Insets;
    import androidx.core.view.ViewCompat;
    import androidx.core.view.WindowInsetsCompat;
    
    import java.util.Random;
    
    public class MainActivity extends AppCompatActivity {
    
        private ImageView[] diceImages = new ImageView[5];
        private TextView rollResultText;
        private TextView gameResultText;
        private int gameScore = 0;
        private final int[] diceImageIds = {
                R.drawable.k1, R.drawable.k2, R.drawable.k3,
                R.drawable.k4, R.drawable.k5, R.drawable.k6
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            EdgeToEdge.enable(this);
            setContentView(R.layout.activity_main);
            ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
                Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
                return insets;
            });
    
            diceImages[0] = findViewById(R.id.die1);
            diceImages[1] = findViewById(R.id.die2);
            diceImages[2] = findViewById(R.id.die3);
            diceImages[3] = findViewById(R.id.die4);
            diceImages[4] = findViewById(R.id.die5);
            rollResultText = findViewById(R.id.rollResultText);
            gameResultText = findViewById(R.id.gameResultText);
        }
    
        private int countPoints(int[] dice) {
            int points = 0;
            for (int i = 0; i < dice.length; i++) {
                int repeats = 0;
                for (int j = 0; j < dice.length; j++) {
                    if (dice[j] == dice[i]) {
                        repeats++;
                    }
                }
                if (repeats >= 2) {
                    points += dice[i];
                }
            }
            return points;
        }
    
        private final Random random = new Random();
    
        public void rollDice(View view) {
            int[] dice = new int[5];
            for (int i = 0; i < 5; i++) {
                dice[i] = random.nextInt(6) + 1;
                diceImages[i].setImageResource(diceImageIds[dice[i] - 1]);
            }
            int points = countPoints(dice);
            gameScore += points;
            showScores(points);
        }
    
        public void resetScore(View view) {
            for (int i = 0; i < 5; i++) {
                diceImages[i].setImageResource(R.drawable.question);
            }
            gameScore = 0;
            showScores(0);
        }
    
        private void showScores(int rollPoints) {
            rollResultText.setText(getString(R.string.roll_result, rollPoints));
            gameResultText.setText(getString(R.string.game_result, gameScore));
        }
    }
    Kosci/app/src/main/res/values/strings.xml XML nowy plik
    <resources>
        <string name="app_name">Kosci</string>
        <string name="roll_result">Wynik tego losowania: %d</string>
        <string name="game_result">Wynik gry: %d</string>
    </resources>
    Ekran telefonu po tym kroku

    Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.

  30. Etap 6: Oddanie pracy

    Krok 30 · po tym etapie masz 35 z 35 kryteriów (pkt)

    Krok 30: Nagranie płyty

    ok. 5 min
    Polecenie z arkusza

    Nagraj płytę z rezultatami pracy. W folderze z numerem zdającego powinny się znajdować podfoldery: konsolowa, mobilna, dokumentacja.

    Sprawdzamy zawartość przed nagraniem:

    • konsolowa: konsola.zip (spakowany po dopisaniu komentarza), Main.java,
    • mobilna: mobilna.zip, activity_main.xml, MainActivity.java,
    • dokumentacja: zrzuty konsoli i emulatora, egzamin.

    Nagrywamy, sprawdzamy odczyt płyty, opisujemy ją numerem zdającego.

    Ekran telefonu bez zmian - taki jak po kroku 29.

Podgląd

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: . 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.