Rozwiązania. Arkusz egzaminacyjny INF.04 czerwiec 2023 wersja 2
INF 04 egzamin praktyczny Rozwiązanie arkusza czerwiec 2023Część I. Aplikacja konsolowa. Sortowanie bąbelkowe
Napisz program sortujący tablicę metodą bąbelkową. Założenia do programu:
- Program wykonywany w konsoli.
- Obiektowy język programowania zgodny z zainstalowanym na stanowisku egzaminacyjnym, jeden z: C++, C#, Java, Python.
- Sortowanie odbywa się rosnąco, nie wykorzystuje gotowych funkcji do sortowania oraz zamiany miejscami elementów.
- Sortowana jest tablica 100 pseudolosowych liczb całkowitych.
- Wszystkie elementy posortowanej tablicy są wyświetlane na ekranie, oddzielone dowolnym separatorem, poprzedzone znaczącym komunikatem.
- Sortowanie odbywa się w funkcji, której argumentem jest tablica, funkcja nie zwraca wartości.
- Program powinien być zapisany czytelnie, z zachowaniem zasad czystego formatowania kodu, należy stosować znaczące nazwy zmiennych i funkcji.
- Program główny powinien zawierać test działania funkcji sortującej, który jest opisany w części III zadania egzaminacyjnego.
Kod aplikacji przygotuj do nagrania na płytę. W podfolderze konsola powinno znaleźć się archiwum całego projektu o nazwie konsola.zip, plik z kodem źródłowym programu oraz plik wykonywalny, jeżeli istnieje.
Część II. Aplikacja mobilna. Właściwości czcionki
Wykonaj aplikację mobilną za pomocą środowiska programistycznego dostępnego na stanowisku egzaminacyjnym oraz uruchom ją w dostępnym emulatorze systemu mobilnego. Aplikacja służy do zarządzania ustawieniami czcionki.
Na obrazach 1a i 1c przedstawiono stan po uruchomieniu aplikacji mobilnej. W zależności od zastosowanego środowiska programistycznego oraz emulatora wynik końcowy może nieznacznie się różnić od przedstawionego. Obraz 1b przedstawia zachowanie aplikacji, gdy suwak przesunięto do wartości 30 oraz dwa razy wybrano przycisk o treści: >>
Działanie aplikacji:
- Po przesunięciu suwaka następuje akcja (obraz 1b):
- wartość aktualna suwaka jest zapisywana po napisie Rozmiar:
- rozmiar czcionki cytatu jest zmieniany na aktualną wartość suwaka (rozmiar czcionki powinien być liczbą całkowitą).
- Po wybraniu przycisku następuje akcja:
- zamieniany jest tekst w napisie cytatu. Kolejne napisy: Dzień dobry, Good morning, Buenos dias. Jeżeli wyświetlony jest tekst Buenos dias, wybranie przycisku powoduje wyświetlenie Dzień dobry itd.
Założenia aplikacji
- Interfejs użytkownika zapisany za pomocą języka znaczników wspieranego w danym środowisku (np. XAML, XML).
- Zastosowany typ rozkładu liniowy (Linear / Stack lub inny o tej idei).
- Zastosowano marginesy dla całej strony 20
- Wszystkie pola są rozciągnięte na szerokość strony
- Zastosowany kolor tła elementów: #558B2F, zgodnie z Obrazem 1a.
- Zastosowany kolory czcionki: czarny i biały, zgodnie z Obrazem 1a.
- Czcionka napisu ?Właściwości czcionki? ma rozmiar największy i jest pogrubiona,
- Czcionka napisu ?Rozmiar:? ma rozmiar średni.
- Suwak ma wartość maksymalną 40, jeżeli ustawienie minimum jest wymagane ? ustawić wartość 0.
- Przycisk jest wyśrodkowany oraz jego tekst jest wyśrodkowany i pogrubiony.
- Teksty pojawiające się w polu napisu cytatu są zdefiniowane w kodzie jako tablica 3-elementowa.
- Aplikacja powinna być zapisana czytelnie, z zachowaniem zasad czystego formatowania kodu, należy stosować znaczące nazwy zmiennych i funkcji.
Podejmij próbę kompilacji i uruchomienia aplikacji. Wykonaj zrzut ekranu emulacji aplikacji, ze środowiskiem programistycznym w tle. Jeżeli aplikacja uruchamia się, na zrzucie należy umieścić okno z wynikiem emulacji, kilka zrzutów ekranu dokumentujących interakcje aplikacji, nazwane mobilna1, mobilna2 itd. oraz otwarte środowisko programistyczne z projektem. Jeżeli aplikacja nie uruchamia się, na zrzucie powinno być widoczne okno z błędami kompilacji oraz środowisko programistyczne. Zrzut zawierający cały obszar ekranu z widocznym paskiem zadań zapisz jako mobilna.jpg w folderze numerem zdającego/mobilna.
Utwórz plik tekstowy o nazwie srodowisko.txt w folderze numerem zdającego/mobilna. Zapisz w nim nazwę środowiska programistycznego, w którym została wykonana aplikacja oraz nazwę emulowanego urządzenia lub systemu, na którym uruchomiono aplikację.
Kod aplikacji przygotuj do nagrania na płytę. W podfolderze mobilna powinno znaleźć się archiwum całego projektu o nazwie mobilna.zip, 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.
Część III. Test aplikacji konsolowej
Wykonaj test aplikacji konsolowej. Test powinien być fragmentem kodu, który należy umieścić w programie głównym aplikacji. Test zapisz w folderze testy, w pliku o nazwie test, z rozszerzeniem charakterystycznym dla aplikacji pisanych w danym języku programowania. W teście sprawdź działanie funkcji sortującej dla wylosowanych liczb pseudolosowych. Liczby powinny być całkowite dodatnie z przedziału 0..1000. Uruchom aplikację z testem i udokumentuj to zrzutem ekranu. Jeżeli aplikacja nie kompiluje się, na zrzucie umieść środowisko programistyczne z oknem kompilacji. Zrzut powinien obejmować cały obszar ekranu z widocznym paskiem zadań i nazywać się konsola_testy.jpg. Zrzut umieść w folderze testy.Ocenie będą podlegać 4 rezultaty:
- implementacja, kompilacja, uruchomienie programu,
- aplikacja konsolowa,
- aplikacja mobilna,
- testy aplikacji konsolowej.
Rozwiązanie części I: aplikacja konsolowa: Sortowanie bąbelkowe
Zgodnie z arkuszem egzaminacyjny w rozwiązaniu należy użyć algorytmu sortującego bąbelkowo od najmniejszej wartości do największej. Dane są zebrane w 100 elementowej tablicy i są liczbami losowymi z przedziału od 0 do 1000.
Opis algorytmu sortowania bąbelkowego znajdziesz w tym serwisie www pod linkiem sortowane bąbelkowe
Deklaracja zmiennych
Deklarujemy zmienne wykorzystywane w programie. Będzie to tablica oraz generator liczb losowych
Wskazówka:
internal class Program
{
static int[] tab = new int[100];
static Random los = new Random();
Funkcja losująca
Losowanie danych do tablicy przygotujemy w możliwie prostej bezparametrowej funkcji.
Wskazówka:
static void losujTablice()
{
for (int i = 0; i < tab.GetLength(0); i++)
//przedział ma być od 0 do 1000
tab[i] = los.Next(1001);
}
Funkcja pokazująca tablicę
W treści zadania nie jest podane jak ma być wyświetlana na ekranie zawartość tablicy. Zastosujemy funkcje, którą wywołamy dwukrotnie. Raz przed sortowanie, a drugi raz po sortowaniu. Funkcja będzie argumentowa, jej argumentem będzie tablica danych.
Wskazówka:
static void pokazTablice(int[] t)
{
for (int i = 0; i < t.GetLength(0); i++)
//sepeartor to przecinek
Console.Write(String.Format("{0},", t[i]));
}
W tym momencie możemy sprawdzić jak jest losowana tablica oraz wyświetlić jej zawartość. W głównej funkcji aplikacji wywołamy utworzone funkcje.
Wskazówka:
static void Main(string[] args)
{
Console.WriteLine("Witaj w CzD!");
losujTablice();
Console.WriteLine("TABLICA NIEPOSORTOWANA:");
pokazTablice(tab);
Console.ReadKey();
}
Wynik losowania tablicy (bez sortowania)
Funkcja sortująca bąbelkowo
Zgodnie z warunkami arkusza egzaminacyjnego funkcja sortująca ma mieć jeden parametr, którym jest sortowana tablicy. Dodatkowo funkcja nie ma zwracać wyniku- jest bezpostaciowa (void). Do naszej funkcji po sortowaniu dodamy funkcje pokazująca tablicę. Tym razem będzie to już posortowana tablica.
Wskazówka:
static void sortuj_i_pokazTablice(int[] t)
{
for(int i=t.GetLength(0)-1;i>0;i--)
for(int j=0;j<i;j++)
if (t[j] > t[j + 1])
{
int bufor = t[j];
t[j] = t[j+1];
t[j+1] = bufor;
}
pokazTablice(t);
}
Funkcje sortująca wywołamy w głównej funkcji aplikacji.
Wskazówka:
static void Main(string[] args)
{
Console.WriteLine("Witaj w CzD!");
losujTablice();
Console.WriteLine("TABLICA NIEPOSORTOWANA:");
pokazTablice(tab);
Console.WriteLine("\nTABLICA POSORTOWANA:");
sortuj_i_pokazTablice(tab);
Console.ReadKey();
}
Wynik działającej aplikacji konsolowej sortującej bąbelkowo.
Pełny kod aplikacji konsolowej
Wskazówka:
using System;
namespace czerwiec_2023_problem_1_sortowanie_babelkowe
{
internal class Program
{
static int[] tab = new int[100];
static Random los = new Random();
static void losujTablice()
{
for (int i = 0; i < tab.GetLength(0); i++)
//przedział ma być od 0 do 1000
tab[i] = los.Next(1001);
}
static void pokazTablice(int[] t)
{
for (int i = 0; i < t.GetLength(0); i++)
//sepeartor to przecinek
Console.Write(String.Format("{0},", t[i]));
}
static void sortuj_i_pokazTablice(int[] t)
{
for(int i=t.GetLength(0)-1;i>0;i--)
for(int j=0;j<i;j++)
if (t[j] > t[j + 1])
{
int bufor = t[j];
t[j] = t[j+1];
t[j+1] = bufor;
}
pokazTablice(t);
}
static void Main(string[] args)
{
Console.WriteLine("Witaj w CzD!");
losujTablice();
Console.WriteLine("TABLICA NIEPOSORTOWANA:");
pokazTablice(tab);
Console.WriteLine("\nTABLICA POSORTOWANA:");
sortuj_i_pokazTablice(tab);
Console.ReadKey();
}
}
}
Rozwiązanie część II. Aplikacja mobilna: Właściwości czcionki
UWAGA. Do rozwiązania użyto języka Kotlin.Inicjujemy pusty projekt
Otwieramy kompilator Android Studio i wybieramy New Project/ Empty Views Activity. Wybór zatwierdzamy klawiszem Next.
Ustalamy nazwę projektu aplikacji, folder lokalizacji projektu i wybieramy język. Omawiane rozwiązanie jest pisane w Kotlinie, stąd wybierz jak poniżej (nazwę projektu podaj zgodnie z wymaganiami zapisanymi w arkuszu egzaminacyjnym).
Projekt jest gotowy do wprowadzania kodu, ale zanim zaczniesz kodować przygotuj wirtualny emulator urządzenia mobilnego.
Jeżeli nie masz przygotowanego emulatora urządzenia mobilenego i nie wiesz jak to zrobić, to przejdź do tej instrukcji: Jak zainstalować emulator ?
Układ widoku
Przygotowujemy główny widok aktywności aplikacji. Cały układ widoku standardowo jest zapisywany w pliku XML w lokalizacji app/res/layout/activity_main.xml. Zostawiamy proponowane nazwy- szkoda czasu na egzaminie na ich zmianę. Ponadto, osobom sprawdzającym kod, łatwiej jest się poruszać po projekcie ze standardowymi nazwami i lokalizacjami plików.
Usuwamy standardową kontrolkę TextView i osadzamy LinearLayout (vertical). Przypisujemy atrybuty dla layout_width oraz layout_height na 0dp. Ustawiamy marginesy zewnętrzne na 20dp.
Ustawienia w pliku XML układu wyglądu aktywności dla LinearLayout podane są poniżej
Wskazówka:
<LinearLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="20dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
Dodajemy kontrolkę TextView, w której ustawiamy parametry podane w arkuszu
Dodajemy kolejną kontrolkę TextView oraz kontrolkę suwaka (SeekBar), dla którego ustawienia dobieramy zgodnie z poniższym rysunkiem
Kolejne kontrolki to TextView przeznaczona na cytat oraz Button. Ustawienia kontrolki TextView pozostawiamy bez zmian. Kontrolkę przycisku wyśrodkowujemy (layout_gravity: center), zmieniamy tekst (>>) oraz kolor tła (backgroundTint: #558B2F).
Układ widoku aplikacji jest gotowy.
Obsługa rozmiaru czcionki
Rozmiar czcionki kontrolki TextView dla zmiany rozmiaru treści cytatu obsłużymy w zdarzeniu zmiany położenia suwak. Do listy interfejsów aktywności dodamy interfejs obsługi suwaka- OnSeekBarChangeListener. Dla ułatwienia można skorzystać z podpowiedzi edytora Android Studio, co na egzaminie jest bardzo przydatne- jest to dozwolona forma podpowiedzi.
Po dołączeniu dodatkowego interfejsu obsługi paska postępu edytor poinformuje o błędzie braku implementacji funkcji obsługi zdarzeń związanych z paskiem postępu. Wybierz jak poniżej
W kolejnym oknie dialogowym zaznacz jak poniżej i zatwierdź wybór klawiszem OK.
Kod głównej aktywności zmieni się na poniższy
Wskazówka:
import android.os.Bundle
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity(), OnSeekBarChangeListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
TODO("Not yet implemented")
}
override fun onStartTrackingTouch(p0: SeekBar?) {
TODO("Not yet implemented")
}
override fun onStopTrackingTouch(p0: SeekBar?) {
TODO("Not yet implemented")
}
}
UWAGA! Usuń z ciał nowododanych funkcji zdarzeń obsługi suwaka tekst: TODO("Not yet implemented"). Może być to przyczyną błędu podczas kompilacji projektu.
W funkcji onCreate zaimplementujmy kontrolkę suwaka z równoczesnym powiązaniem z obsługą. Dodaj poniższe linie kodu
Wskazówka:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val suwak=findViewById<SeekBar>(R.id.seekBar)
suwak.setOnSeekBarChangeListener(this)
}
Rejestrowanie zmian położenia suwaka przedstawiane są w kontrolce TextView. Połączymy tę kontrolkę ze zdarzeniem obsługi zmiany położenia suwaka. Kontrolka będzie reprezentowana w zmiennej o zasięgu prywatnym.
Wskazówka:
class MainActivity : AppCompatActivity(), OnSeekBarChangeListener {
private var txtRozmiar:TextView?=null;
override fun onCreate(savedInstanceState: Bundle?) {
Do kodu wprowadź zmiany jak poniżej.
Wskazówka:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val suwak=findViewById<SeekBar>(R.id.seekBar)
suwak.setOnSeekBarChangeListener(this)
//TextView dla informacji o rozmiarze
txtRozmiar= findViewById<TextView>(R.id.textView2)
}
override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
txtRozmiar!!.text="Rozmiar: "+p1.toString()
}
override fun onStartTrackingTouch(p0: SeekBar?) {
}
override fun onStopTrackingTouch(p0: SeekBar?) {
}
Skompiluj program i sprawdź zmiany wysyłane do kontrolki TextView podczas przesuwania suwaka.
Zmiana rozmiaru czcionki cytatu
Jednostką podawania rozmiaru czcionek w systemie Android jest jednostka typu sp (skalowane piksele). I to jest prawidłowe podejście. Ale na egzaminie można dużo zapomnieć. Łatwiej jest użyć wartości typu float (przy int kompilacja zgłosi błąd). Podam dwa rozwiązania. Zaczniemy od deklaracji zmiennej typu TextView reprezentującej kontrolkę cytatu.
Wskazówka:
class MainActivity : AppCompatActivity(), OnSeekBarChangeListener {
private var txtRozmiar:TextView?=null;
private var txtCytat:TextView?=null;
W funkcji onCreate() dopisz
Wskazówka:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val suwak=findViewById<SeekBar>(R.id.seekBar)
suwak.setOnSeekBarChangeListener(this)
//TextView dla informacji o rozmiarze
txtRozmiar= findViewById<TextView>(R.id.textView2)
//TextView dla treści cytatu
txtCytat= findViewById<TextView>(R.id.textView3)
}
W funkcji onProgressChange() dopisz
Wskazówka:
override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
txtRozmiar!!.text="Rozmiar: "+p1.toString()
txtCytat!!.setTextSize(p1.toFloat())
//po zimportowaniu import android.util.TypedValue
//działa poniższa linijka
//txtCytat!!.setTextSize(TypedValue.COMPLEX_UNIT_SP,p1.toFloat())
}
Skompiluj program i sprawdź jak zmienia się rozmiar czcionki przy ruszaniu suwakiem.
Zmiana tekstu cytatu- obsługa klawisza Button
Z godnie z warunkami arkusza egzaminacyjnego kolejne cytaty mają być przechowywane w tablicy. Deklarujemy taką tablicę oraz indeks aktywnego cytatu.
Wskazówka:
private var txtRozmiar:TextView?=null;
private var txtCytat:TextView?=null;
private val tab= arrayOf(
"Dzień dobry",
"Good morning",
"Buenos dias"
)
//indeks aktywnego cytatu
private var id:Int=0;
W funkcji onCreate() zdefiniujemy obsługę klikania w przycisk oraz ustawimy cytat, który jest początkowo pokazywany w kontrolce cytatu.
Wskazówka:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val suwak=findViewById<SeekBar>(R.id.seekBar)
suwak.setOnSeekBarChangeListener(this)
//TextView dla informacji o rozmiarze
txtRozmiar= findViewById<TextView>(R.id.textView2)
//TextView dla treści cytatu
txtCytat= findViewById<TextView>(R.id.textView3)
txtCytat!!.text=tab[0]
val bt=findViewById<Button>(R.id.button)
bt.setOnClickListener{
id++
if(id>tab.size-1)id=0
txtCytat!!.text=tab[id]
}
}
Skompiluj program i sprawdź zachowanie aplikacji oraz jej zgodność z wymaganiami arkusza egzaminacyjnego. Prawidłowo działająca aplikacja zmienia cyklicznie cytat po kliknięciu w przycisk.
Pełny kod aplikacji- zawartość pliku MainActivity.kt
Wskazówka:
package pl.afizyka.czerwiec_2023_problem_2_czcionki
import android.os.Bundle
import android.util.TypedValue
import android.widget.Button
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity(), OnSeekBarChangeListener {
private var txtRozmiar:TextView?=null;
private var txtCytat:TextView?=null;
private val tab= arrayOf(
"Dzień dobry",
"Good morning",
"Buenos dias"
)
//indeks aktywnego cytatu
private var id:Int=0;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val suwak=findViewById<SeekBar>(R.id.seekBar)
suwak.setOnSeekBarChangeListener(this)
//TextView dla informacji o rozmiarze
txtRozmiar= findViewById<TextView>(R.id.textView2)
//TextView dla treści cytatu
txtCytat= findViewById<TextView>(R.id.textView3)
txtCytat!!.text=tab[0]
val bt=findViewById<Button>(R.id.button)
bt.setOnClickListener{
id++
if(id>tab.size-1)id=0
txtCytat!!.text=tab[id]
}
}
override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
txtRozmiar!!.text="Rozmiar: "+p1.toString()
txtCytat!!.setTextSize(p1.toFloat())
//po zimportowaniu import android.util.TypedValue
//działa poniższa linijka
//txtCytat!!.setTextSize(TypedValue.COMPLEX_UNIT_SP,p1.toFloat())
}
override fun onStartTrackingTouch(p0: SeekBar?) {
}
override fun onStopTrackingTouch(p0: SeekBar?) {
}
}
Zawartość pliku układu widoku activity_main.xml
Wskazówka:
<?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">
<LinearLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:layout_marginBottom="20dp"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#558B2F"
android:text="Właściwości czcionki"
android:textColor="@color/white"
android:textSize="34sp" />
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Rozmiar:"
android:textSize="20sp" />
<SeekBar
android:id="@+id/seekBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="40" />
<TextView
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:backgroundTint="#558B2F"
android:text=">>" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>