INF.04-01-26.01-SGStyczeń 2026 · 26 kroków · ok. 83 min · 35 kryteriów z klucza
Rozwiązanie krok po kroku: Aplikacja gry w kości (C# + .NET MAUI)
Rozwiązanie dotyczy arkusza z grą w kości w wersji C# + .NET MAUI: klasa Kosc z polem statycznym, dwoma konstruktorami i trzema metodami, program konsolowy, który tworzy dwie kości (jedną z rzutu losowego, drugą z liczby wpisanej z klawiatury), aplikacja mobilna .NET MAUI z pięcioma kośćmi, przyciskiem RZUT, sumą oczek i blokowaniem kości dotknięciem oraz dwa testy jednostkowe w MSTest.
To drugie rozwiązanie tego arkusza - pierwsze, w zakładce obok, robi to samo w Javie i Android Studio. Arkusz pokazuje oba środowiska (obraz 3 to .NET MAUI), a klucz ocenia je tymi samymi kryteriami. W C# klasa Kosc z konsoli przechodzi do aplikacji mobilnej bez zmian.
Kroki idą zdanie po zdaniu za treścią arkusza, a kod od początku jest taki, jak w porządnym projekcie. Na końcu dwa kroki porównują to rozwiązanie z wariantem w Javie.
Co widać w podglądzie. Wyniki programu konsolowego i testów pochodzą z prawdziwego uruchomienia kodu z danego kroku (.NET 10, MSTest). Ekran telefonu to symulacja w przeglądarce zbudowana z pliku XAML danego kroku, z obrazami kosc0.png - kosc6.png z archiwum zad1.7z; jej zachowanie odpowiada kodowi C# z kroku - klikaj „RZUT” i kości. Każdy stan aplikacji zbudowano też naprawdę (dotnet build) i porównano z emulatorem Pixel 8 (Android 16).
Jak liczą się punkty. Klucz ma 35 kryteriów (R.1.1 - R.4.9), każde za 1 punkt. Próg zdania części praktycznej to 75%, czyli 27 punktów - można stracić 8 kryteriów i nadal zdać. Przy każdym kroku jest napisane, które kryteria spełnia; egzaminator ocenia spełnienie kryteriów z klucza, nie zgodność z tym kodem.
Suwak i strzałki obok niego - albo ←→ na klawiaturze - przechodzą krok po kroku; wyjaśnienie, pliki i podgląd zmieniają się razem z krokiem.
Lista „Etap” przenosi od razu do wybranego etapu.
„Rozwiązuję samodzielnie” chowa rozwiązanie kroku - najpierw własna próba, potem odsłonięcie.
„Tryb prezentacji” pokazuje same kroki, bez menu strony - na rzutnik.
Etap 1: Przygotowanie
Krok 1 · po tym etapie masz 0 z 35 kryteriów (pkt)
Krok 1: Folder zdającego, podfoldery i obrazy z zad1.7z
ok. 3 min
Polecenie z arkusza
Utwórz folder i nazwij go numerem zdającego. W folderze utwórz podfoldery: konsolowa, mobilna, testy. Do wykonania aplikacji mobilnej wykorzystaj umieszczone na pulpicie konta Egzamin obrazy z archiwum zad1.7z z hasłem: @Kosc6
Na pulpicie zakładasz folder o nazwie z numerem PESEL, a w nim konsolowa, mobilna i testy. Archiwum zad1.7z rozpakowujesz hasłem z arkusza - w środku siedem obrazów kosc0.png (pusta ścianka na stan początkowy) - kosc6.png.
Etap 2: Aplikacja konsolowa
Kroki 2-10 · po tym etapie masz 17 z 35 kryteriów (pkt)
Krok 2: Projekt konsola w C#
ok. 3 min
Polecenie z arkusza
Zaprogramuj klasę o nazwie Kosc implementującą logikę działania pojedynczej kości, wykorzystywanej później w grze w kości. Zastosowany obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym: C++ lub C#, lub Java, lub Python.
Wybierasz C# - tę samą klasę Kosc wykorzystasz w aplikacji .NET MAUI. W Visual Studio: Utwórz nowy projekt → Aplikacja konsolowa, nazwa konsola (dotnet new console -n konsola). Program główny piszesz w Program.cs jako instrukcje najwyższego poziomu, klasę Kosc - w osobnym pliku Kosc.cs (Dodaj → Klasa...).
Nazwę klasy narzuca arkusz; pola i metody nazywasz po angielsku, jak w wariancie w Javie - arkusz dopuszcza oba języki nazw. Konwencja C#: pola publiczne i metody wielką literą.
konsola/Program.csC#nowy plik
Console.WriteLine("Hello, World!");
Wynik programu po tym kroku
> konsola.exe
Hello, World!
Krok 3: Pola klasy Kosc: licznik statyczny, nazwy plików, oczka, obraz, dostępność
Kryteria: , , ,
R.2.1 Zdefiniowana klasa Kosc z polami publicznymi: dwa typu całkowitego, jedno logiczne oraz polem publicznym statycznym typu całkowitego
R.2.2 Nazwy obrazów od kosc0.png do kosc6.png zostały przypisane jako elementy tablicy lub innej kolekcji
R.1.4 Polskie lub angielskie nazewnictwo pól i zmiennych. Nazewnictwo jest znaczące. Wyjątkami od reguły są zmienne bufor, tmp, iteratory pętli. Kryterium nie jest spełnione, gdy nazwy zmiennych nic nie znaczą, np. x, tab, tablica, foo
R.1.5 Typy zmiennych pasują do problemu, np. tablica przechowuje napisy, liczba oczek oraz identyfiaktor pliku graficznego są typu całkowitego, zmienna przechowująca czy kość jest dostępna jest typu logicznego (w przypadku języka Python typ wynika z przypisanych danych)
ok. 4 min
Polecenie z arkusza
Klasa Kosc powinna zawierać: pole ogólnodostępne, statyczne, przechowujące liczbę instancji klasy Kosc. Pola ogólnodostępne, przechowujące: nazwy plików przechowujących obrazy (kosc0.png, kosc1.png, kosc2.png, kosc3.png, kosc4.png, kosc5.png, kosc6.png) umieszczone w tablicy lub innej kolekcji typu napisowego, liczba oczek wyrzucona kością, typu liczbowego całkowitego (3 dla obrazu 1), identyfikator pliku graficznego odpowiadającego wyrzuconej liczbie oczek, typu całkowitego (3 dla obrazu 1, jest to indeks tablicy wskazujący na nazwę kosc3.png), informacja czy kość jest dostępna, typu logicznego.
Wszystkie pola są public (ogólnodostępne) (R.2.1):
static int InstanceCount - jedno pole wspólne dla całej klasy, nie dla każdego obiektu; będzie liczyć utworzone kości. Odwołujesz się do niego przez nazwę klasy: Kosc.InstanceCount,
string[] ImageFiles - siedem nazw plików w tablicy (R.2.2); [ ... ] to wyrażenie kolekcji z C# 12. Indeks w tablicy równa się liczbie oczek: ImageFiles[3] to "kosc3.png",
int Pips - liczba oczek, int ImageId - indeks pliku w tablicy, bool Available - czy kość jest dostępna (R.1.5).
Nazwy mówią, co przechowują (R.1.4): pips to po angielsku oczka na kości.
Krok 4: Konstruktor z argumentem: zakres, przypisanie, dostępność, licznik
Kryteria: , , ,
R.2.3 Konstruktor bezparametrowy losuje liczbę i przypisuje ją do pola wartości liczby oczek i pola identyfikatora pliku. Konstruktor z jednym argumentem przypisuje liczbie oczek i identyfikatorowi pliku: - wartość argumentu, gdy argument jest z zakresu <1, 6> - 0, w przeciwnym wypadku (w języku Python jeden konstruktor z domyślną wartością argumentu)
R.2.4 W przynajmniej jednym konstruktorze jest inkrementowane pole statyczne oraz polu logicznemu przypisywana jest wartość true
R.1.1 Kod źródłowy zapisany w sposób czytelny: instrukcje w osobnych liniach, stosowane spacje pomiędzy operatorami, konsekwentnie stosowana wybrana konwencja dla nawiasów klamrowych instrukcji blokowej
R.1.2 Kod zapisany z wcięciami dla zagnieżdżeń bloków
ok. 4 min
Polecenie z arkusza
Konstruktory klasy: jednoargumentowy, którego argument jest wartością wyrzuconej kości. W przypadku, gdy wartość argumentu jest inna niż 1, 2, 3, 4, 5 lub 6, ustawia wartość na 0. Przypisuje liczbie oczek i identyfikatorowi pliku wartość argumentu. Przypisuje wartość polu logicznemu: kość jest dostępna. Inkrementuje zmienną statyczną zliczającą instancje klasy.
Najpierw pilnujesz zakresu: liczba spoza 1-6 zamienia się w 0 - indeks obrazu kosc0.png (R.2.3). Potem ta sama wartość trafia do Pips i ImageId, kość staje się dostępna (Available = true), a licznik instancji rośnie o 1 (R.2.4).
Konstruktor ma nazwę klasy i nie ma typu zwracanego. Parametr value nadpisujesz wewnątrz konstruktora - to zwykła zmienna lokalna, zmiana nie wychodzi poza konstruktor.
Typowe błędy
Warunek value < 1 && value > 6 nigdy nie jest prawdziwy - liczba 9 przechodzi i ImageFiles[9] kończy program wyjątkiem IndexOutOfRangeException.
R.2.3 Konstruktor bezparametrowy losuje liczbę i przypisuje ją do pola wartości liczby oczek i pola identyfikatora pliku. Konstruktor z jednym argumentem przypisuje liczbie oczek i identyfikatorowi pliku: - wartość argumentu, gdy argument jest z zakresu <1, 6> - 0, w przeciwnym wypadku (w języku Python jeden konstruktor z domyślną wartością argumentu)
R.2.4 W przynajmniej jednym konstruktorze jest inkrementowane pole statyczne oraz polu logicznemu przypisywana jest wartość true
ok. 3 min
Polecenie z arkusza
Bezargumentowy: losuje liczbę pseudolosową z zakresu od 1 do 6, przypisuje liczbie oczek i identyfikatorowi pliku wylosowaną liczbę, przypisuje wartość polu logicznemu: kość jest dostępna, inkrementuje zmienną statyczną zliczającą instancje klasy.
Drugi konstruktor - przeciążenie o pustej liście parametrów. Random.Shared.Next(1, 7) losuje od 1 do 6: dolna granica jest włączona, górna wyłączona. Random.Shared to wspólny generator .NET - nie trzeba tworzyć własnego obiektu Random w każdej kości (kości tworzone tuż po sobie z osobnymi generatorami mogłyby w starszych wersjach .NET wylosować to samo). Dalej to samo co w pierwszym konstruktorze (R.2.3, R.2.4).
Typowe błędy
Random.Shared.Next(6) losuje 0-5: kość z zerem oczek, a szóstka nigdy nie wypada.
R.2.5 Metoda realizująca rzut kością losuje wartość z zakresu <1,6> i przypisuje ją do pola wartości liczby oczek i pola identyfikatora pliku tylko, gdy pole dostępności ma wartość true
R.2.6 Metoda blokująca kość jest bezparametrowa, nie zwraca wartości i ustawia pole logiczne na false
R.1.3 Polskie lub angielskie nazewnictwo metod. Nazewnictwo jest znaczące
ok. 3 min
Polecenie z arkusza
Metoda ogólnodostępna, bezparametrowa, niezwracająca wartości, która realizuje rzut kością tylko, gdy kość jest dostępna: losuje wartość z zakresu od 1 do 6, przypisuje wylosowaną wartość do pola liczby oczek i identyfikatora pliku graficznego. Metoda ogólnodostępna, bezparametrowa, niezwracająca wartości, która blokuje kość: ustawiana jest informacja, że kość jest niedostępna.
Obie metody są public void bez parametrów (R.1.3):
Roll losuje i przypisuje wartość tylko, gdy Available jest true - zablokowana kość zachowuje swoje oczka (R.2.5),
R.2.7 Istnieje metoda zwracająca wartość wyrzuconą na kości w postaci słownej np. "jeden" (w przypadku wartości spoza zakresu <1, 6> - dowolnie)
ok. 3 min
Polecenie z arkusza
Metoda ogólnodostępna, bezparametrowa, zwracająca wartość wyrzuconą na kości w postaci tekstu (np. gdy wartość jest równa 3, zwracane jest „trzy”).
Metoda zwraca string (R.2.7). Zamiast sześciu case z return używasz wyrażenia switch: każde ramię wartość => wynik daje napis, a _ łapie wszystko inne - tu jedyną inną możliwą wartość, 0 z konstruktora z liczbą spoza zakresu. Kompilator sprawdza, że wyrażenie zawsze coś zwraca.
R.2.9 Uruchomiony program inicjuje jeden obiekt konstruktorem bezargumentowym, drugi jednoargumentowym. Po każdej inicjacji wyświetlana jest liczba instancji. Dla każdego obiektu wyświetlana jest wartość wyrzucona kością w postaci liczbowej i napisowej oraz odpowiadająca jej nazwa pliku (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
R.1.7 Program nawiązuje zrozumiałą komunikację z użytkownikiem, wyświetlane komunikaty są znaczące (jeżeli kod nie uruchamia się z powodu błędów kompilacji - sprawdzić w kodzie aplikacji)
ok. 4 min
Polecenie z arkusza
Sprawdź działanie klasy w programie głównym: należy utworzyć dwa obiekty klasy Kosc, każdy za pomocą innego konstruktora. Po utworzeniu każdego obiektu należy wyświetlić: liczbę utworzonych instancji klasy, informację o liczbie oczek wyrzuconych kością (w postaci liczbowej i napisowej), nazwę pliku odpowiadającego wyrzuconej liczbie oczek. Informacja powinna być zrozumiała dla użytkownika.
using konsola; udostępnia klasę z przestrzeni nazw projektu. Pierwszą kość tworzysz konstruktorem bez argumentu (R.2.9). Trzy informacje o kości wypiszesz po każdej z dwóch kości, więc od razu zamykasz je w funkcji lokalnej PrintDie - bez powtarzania tych samych trzech linii (R.1.7):
liczba instancji - pole statyczne czytasz przez nazwę klasy: Kosc.InstanceCount,
oczka liczbowo i słownie: die.Pips i die.ToWords(),
nazwa pliku: element tablicy ImageFiles o indeksie ImageId.
Podgląd to prawdziwe uruchomienie.
konsola/Program.csC#zmienione: 12 linii
using konsola;Kosc firstDie = new Kosc();Console.WriteLine("Pierwsza kość (rzut losowy, konstruktor bez argumentu)");PrintDie(firstDie);staticvoidPrintDie(Kosc die){ Console.WriteLine($"Liczba utworzonych kości: {Kosc.InstanceCount}"); Console.WriteLine($"Wyrzucono: {die.Pips} ({die.ToWords()})"); Console.WriteLine($"Plik obrazu: {die.ImageFiles[die.ImageId]}");}
Wynik programu po tym kroku
> konsola.exe
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Liczba utworzonych kości: 1
Wyrzucono: 3 (trzy)
Plik obrazu: kosc3.png
Krok 9: Druga kość z liczbą z klawiatury
Kryteria: , ,
R.2.9 Uruchomiony program inicjuje jeden obiekt konstruktorem bezargumentowym, drugi jednoargumentowym. Po każdej inicjacji wyświetlana jest liczba instancji. Dla każdego obiektu wyświetlana jest wartość wyrzucona kością w postaci liczbowej i napisowej oraz odpowiadająca jej nazwa pliku (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
R.1.7 Program nawiązuje zrozumiałą komunikację z użytkownikiem, wyświetlane komunikaty są znaczące (jeżeli kod nie uruchamia się z powodu błędów kompilacji - sprawdzić w kodzie aplikacji)
R.2.8 Program uruchamia się w konsoli, co jest widoczne na zrzucie ekranu
ok. 3 min
Polecenie z arkusza
W przypadku konstruktora jednoargumentowego liczba przekazana jako argument ma być pobrana z klawiatury.
Liczbę czytasz przez int.TryParse(Console.ReadLine(), out int value): gdy wpisany tekst nie jest liczbą, value dostaje 0, a program się nie wywraca - konstruktor i tak zamienia wartości spoza 1-6 na 0. Drugą kość tworzysz konstruktorem z argumentem i wypisujesz tą samą funkcją (R.2.9, R.1.7).
Podgląd to trzy prawdziwe uruchomienia - wszystkie interakcje, jakie arkusz każe udokumentować zrzutami: liczba z zakresu (4), liczba spoza zakresu (9) i tekst („trzy”). Licznik instancji rośnie z 1 na 2.
konsola/Program.csC#zmienione: 7 linii
using konsola;Kosc firstDie = new Kosc();Console.WriteLine("Pierwsza kość (rzut losowy, konstruktor bez argumentu)");PrintDie(firstDie);Console.WriteLine();Console.Write("Podaj liczbę oczek drugiej kości (1-6): ");int.TryParse(Console.ReadLine(), outintvalue);Kosc secondDie = new Kosc(value);Console.WriteLine("Druga kość (wartość z klawiatury, konstruktor z argumentem)");PrintDie(secondDie);staticvoidPrintDie(Kosc die){ Console.WriteLine($"Liczba utworzonych kości: {Kosc.InstanceCount}"); Console.WriteLine($"Wyrzucono: {die.Pips} ({die.ToWords()})"); Console.WriteLine($"Plik obrazu: {die.ImageFiles[die.ImageId]}");}
Wynik programu po tym kroku
> konsola.exe
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Liczba utworzonych kości: 1
Wyrzucono: 3 (trzy)
Plik obrazu: kosc3.png
Podaj liczbę oczek drugiej kości (1-6): 4
Druga kość (wartość z klawiatury, konstruktor z argumentem)
Liczba utworzonych kości: 2
Wyrzucono: 4 (cztery)
Plik obrazu: kosc4.png
> konsola.exe
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Liczba utworzonych kości: 1
Wyrzucono: 3 (trzy)
Plik obrazu: kosc3.png
Podaj liczbę oczek drugiej kości (1-6): 9
Druga kość (wartość z klawiatury, konstruktor z argumentem)
Liczba utworzonych kości: 2
Wyrzucono: 0 (zero)
Plik obrazu: kosc0.png
> konsola.exe
Pierwsza kość (rzut losowy, konstruktor bez argumentu)
Liczba utworzonych kości: 1
Wyrzucono: 5 (pięć)
Plik obrazu: kosc5.png
Podaj liczbę oczek drugiej kości (1-6): trzy
Druga kość (wartość z klawiatury, konstruktor z argumentem)
Liczba utworzonych kości: 2
Wyrzucono: 0 (zero)
Plik obrazu: kosc0.png
Krok 10: Zrzuty konsola1.png i konsola2.png, folder konsolowa
Kryteria: , ,
R.1.6 Podjęta próba uruchomienia kodu, udokumentowana zrzutem przedstawiającym uruchomiony program lub jego kompilację
R.2.8 Program uruchamia się w konsoli, co jest widoczne na zrzucie ekranu
R.4.6 Istnieje przynajmniej jeden zrzut ekranu z uruchomienia lub kompilacji aplikacji konsolowej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja
ok. 3 min
Polecenie z arkusza
Wykonaj zrzuty ekranu dokumentujące wykonanie programu w konsoli. Zrzuty ekranu powinny obejmować cały obszar ekranu, z widocznym paskiem zadań oraz środowiskiem programistycznym. Liczba zrzutów ekranu powinna odpowiadać wszystkim możliwym interakcjom użytkownika z programem. Zrzuty ekranu zapisz w folderze konsolowa pod nazwami konsola1.png, konsola2.png, itd. W folderze konsolowa powinno znaleźć się archiwum całego projektu o nazwie konsola.zip, skopiowany z projektu plik z kodem źródłowym programu, plik wykonywalny, jeżeli istnieje oraz zrzuty ekranu.
„Wszystkie możliwe interakcje” to tu trzy przypadki z poprzedniego kroku: liczba 1-6, liczba spoza zakresu i tekst. Każdy uruchamiasz w Visual Studio (Ctrl+F5) i robisz zrzut całego ekranu - konsola1.png, konsola2.png, konsola3.png (R.1.6, R.2.8, R.4.6).
W folderze konsolowa: konsola.zip, Kosc.cs, Program.cs, plik wykonywalny konsola.exe z bin\Debug\net8.0 razem z konsola.dll i zrzuty (R.4.9).
Kroki 11-17 · po tym etapie masz 28 z 35 kryteriów (pkt)
Krok 11: Nowy projekt Kosci (.NET MAUI), obrazy i klasa Kosc
ok. 4 min
Polecenie z arkusza
Za pomocą środowiska programistycznego dostępnego na stanowisku egzaminacyjnym wykonaj aplikację mobilną do gry w kości oraz uruchom ją w dostępnym emulatorze systemu mobilnego. W programie można wykorzystać klasę Kosc z aplikacji konsolowej.
W Visual Studio: Utwórz nowy projekt → Aplikacja .NET MAUI, nazwa Kosci (dotnet new maui -n Kosci). Strona MainPage jest osadzona w Shell - stąd pasek „Home”, jak na obrazie 3 arkusza.
obrazy kosc0.png - kosc6.png przeciągasz do Resources/Images - w XAML i w kodzie wskazujesz je po nazwie pliku,
plik Kosc.cs z konsoli dodajesz do projektu (Dodaj → Istniejący element...) i zmieniasz w nim przestrzeń nazw na Kosci. Reszta klasy zostaje bez zmian - to ten sam język.
<?xml version="1.0" encoding="utf-8" ?><ContentPagexmlns="http://schemas.microsoft.com/dotnet/2021/maui"xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"x:Class="Kosci.MainPage"><ScrollView><VerticalStackLayoutPadding="30,0"Spacing="25"><ImageSource="dotnet_bot.png"HeightRequest="185"Aspect="AspectFit"SemanticProperties.Description="dot net bot in a submarine number ten"/><LabelText="Hello, World!"Style="{StaticResource Headline}"SemanticProperties.HeadingLevel="Level1"/><LabelText="Welcome to .NET Multi-platform App UI"Style="{StaticResource SubHeadline}"SemanticProperties.HeadingLevel="Level2"SemanticProperties.Description="Welcome to dot net Multi platform App U I"/><Buttonx:Name="CounterBtn"Text="Click me"SemanticProperties.Hint="Counts the number of times you click"Clicked="OnCounterClicked"HorizontalOptions="Fill"/></VerticalStackLayout></ScrollView></ContentPage>
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 12: Pięć obrazów kosc0.png w dwóch rzędach
Kryteria: , ,
R.3.1 Zastosowany język znaczników XML/XAML lub inny do opisu interfejsu użytkownika oraz zdefiniowano przynajmniej jedną kontrolkę
R.3.3 Zastosowane marginesy zewnętrzne dla obrazów i przycisku 10, wyśrodkowano wszystkie elementy widoku
R.3.7 W stanie początkowym aplikacji wszystkie obrazy wyświetlają grafikę kosc0.png bez przezroczystości, przycisk jest opisany „RZUT” oraz pole tekstowe zawiera napis 0 (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 4 min
Polecenie z arkusza
Interfejs użytkownika zapisany za pomocą języka znaczników wspieranego w danym środowisku (np. XAML, XML). Zastosowany dowolny układ pozwalający na rozmieszczenie wszystkich elementów tak jak na obrazie 2 lub 3. Pięć obrazów kosc0.png bez przezroczystości (wszystkie kości są dostępne). Wielkość obrazów wyświetlających kości dopasowana do widoku z obrazu 2 lub 3. Marginesy zewnętrzne dla obrazów i przycisku 10. Wszystkie elementy widoku są wyśrodkowane.
Usuwasz przykładową treść szablonu (i licznik z MainPage.xaml.cs). Układ z obrazu 3 to dwa rzędy kości jeden pod drugim, więc (R.3.1):
VerticalStackLayout z VerticalOptions="Center" - cała zawartość stoi na środku ekranu w pionie,
w nim dwa HorizontalStackLayout - rząd z dwiema i rząd z trzema kośćmi; HorizontalOptions="Center" stawia każdy rząd na środku w poziomie (R.3.3),
pięć kontrolek Image z obrazem kosc0.png, rozmiar 80 × 80 i margines zewnętrzny Margin="10" (R.3.3, R.3.7). Każda ma nazwę Die1 ... Die5 - pod nią kod dostanie kontrolkę.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 13: Przycisk RZUT i pole tekstowe z wynikiem 0
Kryteria: ,
R.3.7 W stanie początkowym aplikacji wszystkie obrazy wyświetlają grafikę kosc0.png bez przezroczystości, przycisk jest opisany „RZUT” oraz pole tekstowe zawiera napis 0 (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
R.3.3 Zastosowane marginesy zewnętrzne dla obrazów i przycisku 10, wyśrodkowano wszystkie elementy widoku
ok. 2 min
Polecenie z arkusza
Przycisk z napisem „RZUT”. Pole tekstowe z wynikiem rzutu z wartością 0, zawierające sumę oczek pięciu kości. Rozmieszczenie elementów zgodne z obrazami 2 lub 3.
Pod kośćmi przycisk „RZUT” z marginesem 10 i napis ResultLabel z wartością startową 0 (R.3.7). Oba wyśrodkowane HorizontalOptions="Center" - w VerticalStackLayout bez tego rozciągnęłyby się na całą szerokość (R.3.3). Układ jest już taki jak na obrazie 3 (R.3.6).
tło strony BackgroundColor="#ED27C121" i przycisku #ED275021 (R.3.2). Kolor ma osiem cyfr szesnastkowych: w MAUI, tak jak w Androidzie, pierwsze dwie (ED) to przezroczystość (237 z 255, czyli ok. 93% krycia), a dopiero dalej czerwony, zielony i niebieski. W CSS byłoby odwrotnie - przezroczystość na końcu,
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 15: RZUT: losowanie dostępnych kości, obrazy i suma
Kryteria: , , ,
R.3.4 Dla przycisku oraz dla przynajmniej jednego obrazu zdefiniowana metoda kliknięcia, która jest powiązana z kontrolką
R.3.5 Program odwołuje się do przynajmniej jednej kontrolki w sposób zgodny z danym środowiskiem programistycznym
R.3.8 Kliknięcie przycisku powoduje, że są losowane wartości tylko dla kostek dostępnych, odpowiadające wartościom obrazy są wyświetlane (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
R.3.9 Kliknięcie przycisku powoduje wyświetlenie pod nim sumy wszystkich oczek na wyświetlanych obrazach (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 4 min
Polecenie z arkusza
Działanie aplikacji po wciśnięciu przycisku RZUT: dla dostępnych kości losowana jest liczba oczek każdej z nich. W kontrolkach obrazu wyświetlana jest grafika odpowiadająca liczbie oczek na każdej kości. Liczona jest suma oczek z wszystkich kości i wyświetlana w polu tekstowym.
Stan gry trzymasz w polach strony: tablica pięciu obiektów Kosc i tablica pięciu kontrolek obrazu. Do kontrolek odwołujesz się po nazwach z x:Name (Die1 ... Die5, ResultLabel) - kompilator tworzy z nich pola klasy (R.3.5). W konstruktorze, po InitializeComponent(), tworzysz kości new Kosc(0) - wartość 0 to obraz kosc0.png, kość dostępna, jak w stanie początkowym (R.3.7).
Kliknięcie wiążesz w XAML: Clicked="OnRollClicked" (R.3.4). W metodzie dla każdej kości wywołujesz Roll() - losuje tylko dostępne kości, bo tak została napisana w konsoli (R.3.8) - wstawiasz obraz o nazwie z tablicy ImageFiles i dodajesz oczka do sumy (R.3.9). Kliknij „RZUT” w podglądzie.
namespace Kosci;publicpartialclassMainPage : ContentPage{privatereadonly Kosc[] dice = new Kosc[5];privatereadonly Image[] diceImages;publicMainPage() { InitializeComponent(); diceImages = [Die1, Die2, Die3, Die4, Die5];for (int i = 0; i < dice.Length; i++) { dice[i] = new Kosc(0); } }privatevoidOnRollClicked(object? sender, EventArgs e) {int sum = 0;for (int i = 0; i < dice.Length; i++) { dice[i].Roll(); diceImages[i].Source = dice[i].ImageFiles[dice[i].ImageId]; sum += dice[i].Pips; } ResultLabel.Text = sum.ToString(); }}
Ekran telefonu po tym kroku
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 16: Dotknięcie kości: blokada z przezroczystością i odblokowanie
Kryteria: ,
R.3.4 Dla przycisku oraz dla przynajmniej jednego obrazu zdefiniowana metoda kliknięcia, która jest powiązana z kontrolką
R.3.10 Dla wszystkich kości: gdy dana kość jest wyświetlana bez przezroczystości, po kliknięciu widoczna jest przezroczystość. Po kolejnym kliknięciu, kość jest wyświetlana bez przezroczystości (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
ok. 4 min
Polecenie z arkusza
Działanie aplikacji po kliknięciu na dowolny obraz kości: jeżeli kość jest dostępna: jest ustawiana na niedostępną i przezroczystość obrazu jest ustawiana na 50%. Jeżeli kość jest niedostępna: jest ustawiana na dostępną i obraz jest wyświetlany bez przezroczystości.
Kontrolka Image nie ma zdarzenia kliknięcia - dotknięcie rozpoznaje TapGestureRecognizer dodany do obrazu w Image.GestureRecognizers. Wszystkie pięć obrazów wskazuje tę samą metodę OnDieTapped (R.3.4).
Który obraz dotknięto? Parametr sender to kontrolka, która wywołała zdarzenie; Array.IndexOf(diceImages, sender) daje jej pozycję w tablicy, a tym samym kość o tym samym indeksie. Dalej (R.3.10):
dostępną kość blokujesz metodą Block() i ustawiasz Opacity = 0.5 - 50% przezroczystości,
zablokowaną odblokowujesz (Available = true - pole jest publiczne) i wracasz do Opacity = 1.
W podglądzie dotknij dwóch kości i kliknij „RZUT” - zablokowane zachowują oczka, jak na obrazie 3 (stan 3).
Typowe błędy
Ustawienie samego Opacity bez Block() - kość wygląda na zablokowaną, ale Roll() dalej ją losuje (R.3.8).
namespace Kosci;publicpartialclassMainPage : ContentPage{privatereadonly Kosc[] dice = new Kosc[5];privatereadonly Image[] diceImages;publicMainPage() { InitializeComponent(); diceImages = [Die1, Die2, Die3, Die4, Die5];for (int i = 0; i < dice.Length; i++) { dice[i] = new Kosc(0); } }privatevoidOnRollClicked(object? sender, EventArgs e) {int sum = 0;for (int i = 0; i < dice.Length; i++) { dice[i].Roll(); diceImages[i].Source = dice[i].ImageFiles[dice[i].ImageId]; sum += dice[i].Pips; } ResultLabel.Text = sum.ToString(); }privatevoidOnDieTapped(object? sender, TappedEventArgs e) {int index = Array.IndexOf(diceImages, sender); Kosc die = dice[index];if (die.Available) { die.Block(); diceImages[index].Opacity = 0.5; }else { die.Available = true; diceImages[index].Opacity = 1; } }}
Ekran telefonu po tym kroku
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
Krok 17: Uruchomienie w emulatorze, zrzuty i folder mobilna
Kryteria: ,
R.3.6 Aplikacja kompiluje się i uruchamia w emulatorze, co jest udokumentowane zrzutem ekranu, układ wszystkich kontrolek jest zgodny z obrazem 2 lub 3 w arkuszu egzaminacyjnym (w uruchomionej aplikacji lub na zrzucie i obowiązkowo w kodzie)
R.4.7 Istnieje przynajmniej jeden zrzut ekranu z uruchomienia lub kompilacji aplikacji mobilnej, na zrzucie widoczne jest środowisko, w którym powstała aplikacja
ok. 4 min
Polecenie z arkusza
Podejmij próbę kompilacji i emulacji aplikacji. Wykonaj zrzuty ekranowe dokumentujące wszystkie stany aplikacji. Zrzuty zapisz w folderze mobilna pod nazwami mobilna1.png, mobilna2.png, itd. Wszystkie zrzuty muszą zawierać cały obszar ekranu z paskiem zadań i środowiskiem programistycznym. W folderze mobilna powinno znaleźć się archiwum całego folderu projektu oraz skopiowane pliki z kodem źródłowym, które były modyfikowane oraz pliki z zrzutami.
Uruchamiasz aplikację (F5) na emulatorze Androida. Zrzuty całego ekranu z Visual Studio: mobilna1 - stan początkowy, mobilna2 - po rzucie, mobilna3 - po zablokowaniu kilku kości i kolejnym rzucie (R.3.6, R.4.7).
W folderze mobilna: archiwum projektu (bez folderów bin i obj - to wyniki budowania), MainPage.xaml, MainPage.xaml.cs, Kosc.cs i zrzuty (R.4.9).
Kroki 18-22 · po tym etapie masz 34 z 35 kryteriów (pkt)
Krok 18: Projekt testów MSTest z odwołaniem do konsoli
Kryteria:
R.4.1 Co najmniej w jednej metodzie testującej została wykorzystana asercja, nazwy metod odzwierciedlają cel testu, zastosowane narzędzie testujące odpowiednie dla języka
ok. 3 min
Polecenie z arkusza
Wykonaj testy jednostkowe aplikacji konsolowej, metody realizującej rzut kością. Do napisania testów wykorzystaj bibliotekę do testów jednostkowych dostępną na stanowisku egzaminacyjnym dla języka programowania, w którym została napisana klasa Kosc.
Dla C# w Visual Studio jest gotowy szablon Projekt testowy MSTest (dotnet new mstest -n testy); dodajesz go do rozwiązania obok projektu konsola. Testy muszą widzieć klasę Kosc, więc w projekcie testów dodajesz odwołanie do projektukonsola (Dodaj → Odwołanie do projektu...) - w pliku testy.csproj pojawia się ProjectReference.
Przykładowy Test1.cs szablonu zastępujesz plikiem KoscTests.cs: klasa testów z atrybutem [TestClass], a using konsola; udostępnia klasę Kosc (R.4.1).
testy/KoscTests.csC#nowy plik
using konsola;namespace testy;[TestClass]publicsealedclassKoscTests{}
> dotnet new mstest -n testy
Pomyślnie utworzono szablon "MSTest — projekt testowy".
Krok 19: Test 1: wynik rzutu z zakresu 1-6
Kryteria: ,
R.4.1 Co najmniej w jednej metodzie testującej została wykorzystana asercja, nazwy metod odzwierciedlają cel testu, zastosowane narzędzie testujące odpowiednie dla języka
R.4.2 W teście metody realizującej rzut kością sprawdzone czy wartość jest z zakresu <1,6>
ok. 3 min
Polecenie z arkusza
W testach jednostkowych należy rozważyć następujące przypadki testowe: czy wyrzucona wartość jest w zakresie od 1 do 6. W testach nazwy metod testujących należy dobrać tak, aby wyrażały cel danego testu. Nazwy metod należy zapisać zgodnie z konwencją nazewnictwa w danym języku programowania. Każdy przypadek testowy powinien być sprawdzany oddzielną metodą.
Metoda testowa ma atrybut [TestMethod], jest public void i bez parametrów. Nazwa w konwencji C# - wielką literą, z podkreśleniem między testowaną metodą a oczekiwanym zachowaniem: Roll_ReturnsValueFromOneToSix (R.4.1).
Jeden rzut niczego nie dowodzi - wynik jest losowy. Rzucasz 1000 razy i po każdym rzucie sprawdzasz asercją Assert.IsTrue, że oczka mieszczą się w 1-6 (R.4.2). Komunikat z liczbą oczek pokaże się, gdyby test się nie powiódł.
testy/KoscTests.csC#zmienione: 10 linii
using konsola;namespace testy;[TestClass]publicsealedclassKoscTests{[TestMethod]publicvoidRoll_ReturnsValueFromOneToSix() { Kosc die = new Kosc();for (int i = 0; i < 1000; i++) { die.Roll(); Assert.IsTrue(die.Pips >= 1 && die.Pips <= 6, $"Wyrzucono {die.Pips}"); } }}
R.4.3 W teście metody realizującej rzut kością sprawdzone czy wartość się nie zmienia jeżeli pole dostępność jest ustawione na false
ok. 3 min
Polecenie z arkusza
Czy wartość na kości pozostaje bez zmian jeżeli kość nie jest dostępna.
Kość tworzysz z ustaloną wartością 4 (konstruktor z argumentem) - wtedy wiesz, czego oczekiwać. Blokujesz ją i rzucasz 100 razy; Assert.AreEqual(4, die.Pips) porównuje wartość oczekiwaną (pierwszy argument) z rzeczywistą (R.4.3). Gdyby Roll losował mimo blokady, test padłby niemal na pewno już w pierwszych rzutach.
testy/KoscTests.csC#zmienione: 12 linii
using konsola;namespace testy;[TestClass]publicsealedclassKoscTests{[TestMethod]publicvoidRoll_ReturnsValueFromOneToSix() { Kosc die = new Kosc();for (int i = 0; i < 1000; i++) { die.Roll(); Assert.IsTrue(die.Pips >= 1 && die.Pips <= 6, $"Wyrzucono {die.Pips}"); } }[TestMethod]publicvoidRoll_DoesNotChangeValue_WhenDieIsBlocked() { Kosc die = new Kosc(4); die.Block();for (int i = 0; i < 100; i++) { die.Roll(); Assert.AreEqual(4, die.Pips); } }}
Krok 21: Uruchomienie wszystkich testów i zrzuty test1.png
Kryteria: ,
R.4.4 Uruchomiona przynajmniej jedna metoda testująca udokumentowana zrzutem ekranu
R.4.5 Wynik uruchomionego testu z R.4.2 lub R.4.3 wynika z danych testowych co jest udokumentowane zrzutem ekranu
ok. 3 min
Polecenie z arkusza
Po napisaniu metod testujących uruchom wszystkie metody. Wykonaj zrzuty ekranu dokumentujące uruchomienie testów, zrzuty zapisz w katalogu testy pod nazwami test1.png, test2.png, itd. Na zrzutach powinny być widoczne wyniki działania metod testujących. Zrzuty ekranu powinny obejmować cały obszar ekranu, z widocznym paskiem zadań oraz środowiskiem programistycznym.
W Visual Studio: Test → Eksplorator testów → Uruchom wszystkie testy (w terminalu: dotnet test w folderze testy). Podgląd to prawdziwy wynik: oba testy przechodzą, a wynik wynika z danych testowych - tysiąca rzutów i wartości 4 (R.4.4, R.4.5). Zrzut całego ekranu z Eksploratorem testów i zielonymi znacznikami - test1.png w folderze testy.
Wynik programu po tym kroku
> dotnet test
Powodzenie Roll_ReturnsValueFromOneToSix [10 ms]
Powodzenie Roll_DoesNotChangeValue_WhenDieIsBlocked [< 1 ms]
Przebieg testu zakończony powodzeniem.
Łączna liczba testów: 2
Zakończone pomyślnie: 2
Łączny czas: 0,9613 Sekundy
R.4.9 Przygotowana jest dokumentacja w postaci płyty: oba projekty są spakowane oraz zmodyfikowane pliki są na zewnątrz archiwów
ok. 2 min
Polecenie z arkusza
Projekt testów przygotuj do nagrania na płytę. W folderze testy powinno znaleźć się archiwum całego folderu projektu oraz skopiowane pliki z kodem źródłowym, które były modyfikowane oraz zrzuty ekranu.
Folder projektu testy pakujesz do archiwum (bez bin, obj i TestResults), obok kopiujesz KoscTests.cs i zrzut test1.png (R.4.9).
Kroki 23-24 · po tym etapie masz 35 z 35 kryteriów (pkt)
Krok 23: Plik egzamin z dokumentacją narzędzi
Kryteria:
R.4.8 Dokumentacja zawiera: nazwę systemu operacyjnego, nazwy środowisk programistycznych, nazwy języków programowania, nazwy emulatora dla aplikacji mobilnej
ok. 2 min
Polecenie z arkusza
Utwórz plik tekstowy z dokumentacją i nazwij go egzamin. Dokument powinien zawierać informacje o narzędziach wykorzystanych na egzaminie: nazwę systemu operacyjnego, nazwy środowisk programistycznych, nazwę emulatora dla aplikacji mobilnej, nazwy języków programowania. Dokument egzamin zapisz w folderze z numerem zdającego.
Plik tekstowy egzamin.txt bezpośrednio w folderze z numerem zdającego (nie w podfolderze) - system, środowisko, emulator i języki (R.4.8).
egzamin.txtTekstnowy plik
System operacyjny: Windows 11Środowisko programistyczne: Visual Studio (aplikacja konsolowa, testy MSTest, aplikacja .NET MAUI)Emulator: Android Emulator - Pixel 8 (Android 16, API 36)Języki programowania: C# (aplikacja konsolowa, testy i aplikacja mobilna), XAML (wygląd aplikacji mobilnej)
Kroki 25-26 · po tym etapie masz 35 z 35 kryteriów (pkt)
Krok 25: Te same kryteria, inny zapis
ok. 3 min
Polecenie z arkusza
Zastosowany obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym: C++ lub C#, lub Java, lub Python.
wymaganie
C# + .NET MAUI
Java + Android
losowanie 1-6
Random.Shared.Next(1, 7)
random.nextInt(6) + 1
liczba słownie
wyrażenie switch
instrukcja switch z return
układ
VerticalStackLayout + dwa HorizontalStackLayout
LinearLayout pionowy + dwa poziome
kolor #ED27C121
przezroczystość na początku (ARGB)
tak samo (ARGB)
kliknięcie przycisku
Clicked="OnRollClicked"
setOnClickListener / android:onClick
dotknięcie obrazu
TapGestureRecognizer
setOnClickListener na ImageView
przezroczystość
Opacity = 0.5
setAlpha(0.5f)
testy
MSTest: [TestMethod], Assert.AreEqual
JUnit 5: @Test, assertEquals
Klasa Kosc jest w obu wariantach ta sama w konsoli i w aplikacji - w C# i w Javie przenosi się ją do projektu mobilnego, zmieniając tylko przestrzeń nazw albo pakiet.
Za pomocą środowiska programistycznego dostępnego na stanowisku egzaminacyjnym wykonaj aplikację mobilną do gry w kości oraz uruchom ją w dostępnym emulatorze systemu mobilnego.
Klucz ocenia oba środowiska tymi samymi kryteriami. C# + .NET MAUI - jedno środowisko (Visual Studio) na konsolę, testy i aplikację mobilną, a błąd w nazwie metody zdarzenia wychodzi już przy kompilacji. Pierwsze budowanie projektu MAUI na Androida trwa kilka minut, więc emulator i pusty projekt warto uruchomić na samym początku egzaminu. Java + Android Studio - najczęstsze środowisko mobilne na stanowiskach; konsola i testy JUnit w IntelliJ.
W MAUI łatwo przeoczyć, że Image nie reaguje na kliknięcia bez TapGestureRecognizer - bez niego kryterium R.3.10 nie jest spełnione.
Symulacja ekranu w przeglądarce - w Android Studio / Visual Studio wygląd może się nieco różnić.
To jedno z możliwych rozwiązań. Egzaminator ocenia spełnienie kryteriów z klucza odpowiedzi, a nie zgodność z tym kodem - inna, poprawna droga też daje punkty.
Autor rozwiązania: Bartosz Bryniarski. Licencja CC BY-NC 4.0 - kopiowanie i przeróbki do celów niekomercyjnych, z podaniem autora i źródła (link do tej strony) (zasady wykorzystania). Treść arkusza i klucza oceniania pochodzi z CKE.