Klasy i instancje obiektów w Kotlin

Na potrzeby tego ćwiczenia stworzysz aplikację na rolkę kostką do gry w Androida. Gdy użytkownik rzuci kostką, zostanie wygenerowany losowy wynik. Wynik uwzględnia liczbę boków kości. Na przykład kości 6-stronne można rzucać tylko na wartości z zakresu 1–6.

Tak będzie wyglądać ostateczna wersja aplikacji.

Aby pomóc Ci skoncentrować się na nowych pojęciach związanych z programowaniem tej aplikacji, utworzysz w przeglądarce Kotlin dostępne w przeglądarce podstawowe funkcje aplikacji. Wyniki wyświetlą się w konsoli. Później zaimplementujesz interfejs w Android Studio.

W ramach pierwszego ćwiczenia z programowania stworzymy program Kotlin, który symuluje rzut kostką i wyświetla losową liczbę tak samo jak kości.

Wymagania wstępne

  • Otwieranie, edytowanie i uruchamianie kodu na stronie https://try.kotlinlang.org/
  • Utwórz i uruchom program Kotlin, który korzysta ze zmiennych i funkcji, a następnie drukuje wynik w konsoli.
  • Sformatuj liczby w tekście za pomocą szablonu ciągu znaków z notacją ${variable}.

Czego się nauczysz

  • Jak automatycznie generować losowe liczby, by symulować rzut kostką.
  • Jak utworzyć kod, tworząc klasę Dice ze zmienną i metodą.
  • Jak utworzyć instancję obiektu klasy, zmodyfikować zmienne i wywołać jego metody.

Co stworzysz

  • Program Kotlin w oprogramowaniu opartym na przeglądarce narzędzie Kotlin, które może wykonywać losowe kostki.

Wymagania

  • komputera z dostępem do internetu,

Gry często zawierają elementy losowe. Możesz zdobyć losową nagrodę lub przejść przez losową liczbę kroków na planszy. W codziennym życiu możesz korzystać z losowych cyfr i liter, aby generować bezpieczniejsze hasła.

Zamiast rzucać kostką, możesz napisać program, który symuluje rzut kostką. Za każdym razem, gdy rzucisz kostką, możesz podać dowolną wartość z zakresu możliwych wartości. Na szczęście nie musisz tworzyć własnego generatora liczb losowych na potrzeby tego programu. Większość języków programowania, w tym Kotlin, ma wbudowany sposób generowania losowych liczb. W tym zadaniu użyjesz kodu Kotlin, by wygenerować liczbę losową.

Skonfiguruj kod startowy

  1. W przeglądarce otwórz stronę https://try.kotlinlang.org/.
  2. Usuń cały istniejący kod w edytorze kodu i zastąp go poniższym kodem. To funkcja z main() używana przez Ciebie podczas wcześniejszych ćwiczeń z programowania (zobacz artykuł Tworzenie pierwszego programu Kotlin).
fun main() {

}

Używanie funkcji losowej

Aby rzucić kostką, należy podać sposób reprezentowania wszystkich prawidłowych. W przypadku zwykłej kości 6-stronnej dozwolone są rzuty kostką: 1, 2, 3, 4, 5 i 6.

Wcześniej dowiedzieliśmy się, że dostępne są takie typy danych jak Int (liczba całkowita) oraz String (tekst). IntRange to inny typ danych, który reprezentuje zakres liczb całkowitych od punktu początkowego do punktu końcowego. IntRange to odpowiedni typ danych, który reprezentuje możliwe wartości rzutu kostką.

  1. W ramach funkcji main() zdefiniuj zmienną jako val o nazwie diceRange. Przypisz ją do IntRange z zakresu od 1 do 6. Podaje zakres liczb całkowitych, które może rzucić kostką.
val diceRange = 1..6

Możesz rozpoznać, że zakres 1..6 to kotlin, ponieważ zawiera on numer początkowy, dwie kropki, a następnie numer końcowy (bez spacji między słowami). Inne przykłady zakresów liczb całkowitych to 2..5 dla liczb od 2 do 5 oraz 100..200 dla liczb od 100 do 200.

Podobnie jak wywołanie println() informuje system, że ma wydrukować konkretny tekst, możesz użyć funkcji o nazwie random(), która wygeneruje i zwróci liczbę losową dla wybranego zakresu. Tak jak wcześniej, możesz zapisać wynik w zmiennej.

  1. W zasadzie main() zdefiniuj zmienną jako val o nazwie randomNumber.
  2. Ustaw wartość randomNumber jako wartość wywołania random() w zakresie diceRange, jak pokazano poniżej.
 val randomNumber = diceRange.random()

Zwróć uwagę, że w wywołaniu funkcji random() diceRange występuje kropka (kropka) między zmienną a wywołaniem funkcji. Możesz to odczytać jako &generujące liczby losowe z operatora diceRange" wynik jest przechowywany w zmiennej randomNumber.

  1. Aby zobaczyć wygenerowany losowo numer, użyj formatu formatowania ciągu (nazywanego też „szablonem ciągu”) ${randomNumber}, by go wydrukować, jak widać poniżej.
println("Random number: ${randomNumber}")

Gotowy kod powinien wyglądać następująco.

fun main() {
    val diceRange = 1..6
    val randomNumber = diceRange.random()
    println("Random number: ${randomNumber}")
}
  1. Uruchom kod kilka razy. Za każdym razem wyniki powinny być widoczne poniżej, ale z różnymi losowymi liczbami.
Random number: 4

Rzut kostką to prawdziwy przedmiot w Twoich rękach. Wpisany właśnie kod świetnie działa, ale trudno sobie wyobrazić, że chodzi o kostkę. Organizowanie programu w taki sposób, aby przypominał to, co przedstawia, ułatwia zrozumienie jego treści. Fajnie jest też mieć rzut kolekcjonerski.

Wszystkie kości działają tak samo. Mają te same właściwości (np. boki) i działają tak samo jak wcześniej. W Kotlin możesz utworzyć zautomatyzowany plan kości kości, który informuje, że kostki mają boki i mogą losować liczbę. Ten plan nazywa się klasą.

Na podstawie tych zajęć możesz tworzyć obiekty zwane kościami, czyli wystąpienia obiektów. Możesz na przykład utworzyć kostkę dwunastokątną lub czworokątną.

Definiowanie klasy kości

W kolejnych krokach zdefiniujesz nową klasę o nazwie Dice, która reprezentuje kości do zwijania.

  1. Aby zacząć od nowa, wyczyść kod w funkcji main(), tak by wyglądał tak, jak na ilustracji poniżej.
fun main() {

}
  1. Poniżej tej funkcji main() dodaj pusty wiersz, a następnie dodaj kod, aby utworzyć klasę Dice. Jak pokazano poniżej, zacznij od słowa kluczowego class, a następnie nazwy klasy, po której następuje otwierający i zamykający nawias klamrowy. Rozdziel je nawiasami klamrowymi.
class Dice {

}

W definicji klasy możesz określić co najmniej jedną właściwość klasy, używając zmiennych. Kostki mogą mieć kilka boków, koloru lub wagi. W tym zadaniu skupisz się na liczbie boków kości.

  1. W ramach klasy Dice dodaj var o nazwie sides, określającej liczbę stron kości do gry. Ustaw: sides na 6.
class Dice {
    var sides = 6
}

To wszystko. Masz teraz bardzo prostą klasę, która reprezentuje kości.

Tworzenie instancji klasy kości

Ta klasa Dice zawiera plan działania kostki. Aby wstawić kości do swojego programu, musisz utworzyć instancję obiektu Dice. Jeśli musisz mieć 3 kostki, musisz utworzyć 3 instancje obiektu.

  1. Aby utworzyć instancję obiektu typu Dice, w funkcji main() utwórz val o nazwie myFirstDice i zainicjuj go jako instancję klasy Dice. Zwróć uwagę na nawiasy po nazwie klasy, które wskazują, że tworzysz nową instancję obiektu z klasy.
fun main() {
    val myFirstDice = Dice()
}

Teraz gdy masz obiekt myFirstDice, obiekt utworzony na podstawie planu, możesz uzyskać dostęp do jego właściwości. Jedyną właściwością elementu Dice jest sides. Aby uzyskać dostęp do usługi, użyj &notacji; Aby uzyskać dostęp do właściwości sides elementu myFirstDice, wywołujesz funkcję myFirstDice.sides, której wymowa "myFirstDice; kropka sides&quot.

  1. Pod deklaracją myFirstDice dodaj instrukcję println(), by wyświetlać liczbę sides z myFirstDice.
println(myFirstDice.sides)

Twój kod powinien wyglądać tak.

fun main() {
    val myFirstDice = Dice()
    println(myFirstDice.sides)
}

class Dice {
    var sides = 6
}
  1. Uruchom program, a jego wartość powinna odpowiadać liczbie sides określonej w klasie Dice.
6

Masz teraz klasę Dice i rzeczywistą kostkę myFirstDice z 6 sides.

Rzuć kostką!

Rzuć kostką

Wcześniej do wykonywania czynności drukowanych warstw ciasta była funkcja. Rzut kostką to czynność, którą można zaimplementować jako funkcję. Ponieważ można rzucić kostką, można dodać dla niej funkcję w klasie Dice. Funkcja zdefiniowana w klasie jest również nazywana metodą.

  1. W klasie Dice pod zmienną sides wstaw pusty wiersz i utwórz nową funkcję rzucania kostką. Zacznij od słowa kluczowego fun Kotlin, po którym następuje nazwa metody, po których następuje nawiasy (), a następnie nawiasy klamrowe otwierające i zamykające {}. Między nawiasami klamrowymi możesz pozostawić pusty wiersz, aby zrobić więcej miejsca, jak widać poniżej. Klasa powinna wyglądać następująco.
class Dice {
    var sides = 6

    fun roll() {

    }
}

Rzut kostką ma losową liczbę od 1 do 6.

  1. W metodzie roll() utwórz val randomNumber. Przypisz losową liczbę w zakresie 1..6. Aby zapisać random() w zakresie, użyj kropki.
val randomNumber = (1..6).random()
  1. Po wygenerowaniu liczby losowej wydrukuj ją w konsoli. Ukończona metoda roll() powinna wyglądać tak jak poniżej.
fun roll() {
     val randomNumber = (1..6).random()
     println(randomNumber)
}
  1. Aby rozpocząć, myFirstDice wywołaj metodę main() dla roll() metodę myFirstDice. Wywołujesz metodę za pomocą &notacji; Aby wywołać metodę roll() myFirstDice, wpisz myFirstDice.roll(), jak wymówić: myFirstDice, kropka roll()&quot.
myFirstDice.roll()

Ukończony kod powinien wyglądać tak.

fun main() {
    val myFirstDice = Dice()
    println(myFirstDice.sides)
    myFirstDice.roll()
}

class Dice {
    var sides = 6

    fun roll() {
        val randomNumber = (1..6).random()
        println(randomNumber)
    }
}
  1. Uruchom kod. Wynik liczby rzutów kostką powinien być widoczny poniżej liczby boków. Uruchamiaj swój kod kilka razy i zauważ, że liczba boków jest taka sama, a końcowa rzut kostką się zmienia.
6
4

Gratulacje! Klasa Dice została zdefiniowana przez zmienną sides i funkcję roll(). W funkcji main() utworzono nową instancję obiektu Dice, a następnie wywołałeś dla niej metodę roll(), by wygenerować liczbę losową.

Obecnie drukujesz wartość randomNumber w funkcji roll() i działa to doskonale. Czasami jednak lepiej jest wrócić do wyniku dowolnej funkcji nazywanej funkcją. Możesz na przykład przypisać wynik metody roll() do zmiennej i przenieść odtwarzacz o taką samą kwotę. Zobaczmy, jak to się robi.

  1. W main() zmień wiersz o nazwie myFirstDice.roll(). Utwórz val o nazwie diceRoll. Ustaw jego wartość, która jest zwracana przez metodę roll().
val diceRoll = myFirstDice.roll()

Na razie to nic nie dzieje się, bo roll() nie zwraca jeszcze żadnych wyników. Aby kod działał poprawnie, roll() musi zwrócić jakiś element.

Z wcześniejszych ćwiczeń z programowania dowiesz się, że musisz określić typ danych dla argumentów wejściowych dla funkcji. W ten sam sposób musisz określić typ danych, które zwraca funkcja.

  1. Zmień funkcję roll(), by określić, jakie typy danych będą zwracane. W tym przypadku losowa liczba to Int, więc typ zwrotu to Int. Składnia określająca typ zwracania: po nazwie funkcji po nawiasie dodaj dwukropek, spację, a następnie słowo kluczowe Int dla typu zwracanego działania. Definicja funkcji powinna wyglądać jak w poniższym kodzie.
fun roll(): Int {
  1. Uruchom ten kod. W widoku problemów pojawi się błąd. Wiadomość brzmi:
A ‘return'  expression is required in a function with a block body. 

Zmiana definicji funkcji powoduje zwrócenie Int, ale system zgłasza,

nie zwraca Int. "Zablokuj treść" lub "body body" dotyczy kodu między nawiasami klamrowymi funkcji. Możesz naprawić ten błąd, zwracając wartość z funkcji przy użyciu instrukcji return na końcu treści.

  1. W sekcji roll() usuń instrukcję println() i zastąp ją instrukcją return dla atrybutu randomNumber. Twoja funkcja roll() powinna przypominać poniższy kod.
fun roll(): Int {
     val randomNumber = (1..6).random()
     return randomNumber
}
  1. W main() musisz usunąć informacje o drukowanych krawędziach kości.
  2. Dodaj oświadczenie, aby wydrukować wartości sides i diceRoll w zrozumiałym zdaniu. Twoja gotowa funkcja main() powinna wyglądać podobnie do tego.
fun main() {
    val myFirstDice = Dice()
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.sides} sided dice rolled ${diceRoll}!")
}
  1. Uruchom kod, a wynik powinien wyglądać tak.
Your 6 sided dice rolled 4!

Oto Twój cały kod.

fun main() {
    val myFirstDice = Dice()
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.sides} sided dice rolled ${diceRoll}!")
}


class Dice {
    var sides = 6

    fun roll(): Int {
        val randomNumber = (1..6).random()
        return randomNumber
    }
}

Nie wszystkie kostki mają 6 boków. Kostki mogą mieć różne kształty i rozmiary: 4 strony, 8 boków, do 120 boków!

  1. W metodzie roll() w metodzie roll() zmień zakodowany na stałe 1..6 na sides, tak by zakres, a tym samym liczba losowa, była zawsze odpowiednia dla liczby boków.
val randomNumber = (1..sides).random()
  1. W funkcji main() poniżej i po wydrukowaniu rzutu kostką zmień sides mojejFirstDice na 20.
myFirstDice.sides = 20
  1. Skopiuj i wklej istniejącą deklarację drukowania po zmianie liczby boków.
  2. Zastąp drukowanie diceRoll wynikiem drukowania metody roll() z metodą myFirstDice.
println("Your ${myFirstDice.sides} sided dice has rolled a ${myFirstDice.roll()}!")

Twój program powinien wyglądać tak.

fun main() {
   
    val myFirstDice = Dice()
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.sides} sided dice rolled ${diceRoll}!")

    myFirstDice.sides = 20
    println("Your ${myFirstDice.sides} sided dice rolled ${myFirstDice.roll()}!")
}

class Dice {
    var sides = 6

    fun roll(): Int {
        val randomNumber = (1..sides).random()
        return randomNumber
    }
}
  1. Uruchom program, powinien pojawić się komunikat dla kości 6-stronnych i drugi dla 20.
Your 6 sided dice rolled 3!
Your 20 sided dice rolled 15!

Zajęcia pozwalają reprezentować rzeczy, często w świecie rzeczywistym, W tym przypadku klasa Dice reprezentuje kostki fizyczne. W świecie rzeczywistym kostki nie mogą zmienić liczby boków. Jeśli chcesz mieć różne boki, musisz zdobyć inną kostkę. Oznacza to, że zamiast zmieniać właściwość boków istniejącego wystąpienia obiektu Dice, musisz utworzyć nową instancję kości do gry z potrzebną liczbą boków.

W tym zadaniu będziesz modyfikować klasę Dice, aby określić liczbę stron podczas tworzenia nowej instancji. Zmień definicję klasy Dice, aby zaakceptować argument dla liczby boków. Przypomina to sposób, w jaki funkcja może przyjmować argumenty wejściowe.

  1. Edytuj definicję klasy Dice, aby zaakceptować argument liczby całkowitej o nazwie numSides. Kod zajęć nie zmieni się.
class Dice(val numSides: Int) {
   // Code inside does not change.
}
  1. Usuń klasę sides z klasy Dice, ponieważ teraz możesz używać właściwości numSides.
  2. Popraw zakres, aby numSides.

Klasa Dice powinna wyglądać następująco.

class Dice (val numSides: Int) {

    fun roll(): Int {
        val randomNumber = (1..numSides).random()
        return randomNumber
    }
}

Jeśli uruchomisz ten kod, wyświetli się wiele błędów, bo musisz zaktualizować main(), by dostosować się do zmian w klasie Dice.

  1. W funkcji main(), aby utworzyć myFirstDice z 6 bokami, musisz teraz podać liczbę boków w postaci argumentu klasy Dice, jak pokazano poniżej.
    val myFirstDice = Dice(6)
  1. W zestawieniu operacji zmień sides na numSides.
  2. Poniżej usuń kod, który zmienia sides na 20, bo ta zmienna już nie istnieje.
  3. Możesz też usunąć instrukcje println pod spodem.

Twoja funkcja main() powinna wyglądać tak jak poniżej, a jeśli ją uruchomisz, nie powinno być żadnych błędów.

fun main() {
    val myFirstDice = Dice(6)
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.numSides} sided dice rolled ${diceRoll}!")
}
  1. Po wydrukowaniu pierwszej kostki dodaj kod, aby utworzyć i wydrukować drugi obiekt Dice o nazwie mySecondDice z 20 bokami.
    val mySecondDice = Dice(20)
  1. Dodaj oświadczenie drukowane, które zwraca i wyświetla zwróconą wartość.
println("Your ${mySecondDice.numSides} sided dice rolled  ${mySecondDice.roll()}!")
  1. Twoja gotowa funkcja main() powinna wyglądać tak.
fun main() {
    val myFirstDice = Dice(6)
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.numSides} sided dice rolled ${diceRoll}!")
    
    val mySecondDice = Dice(20)
    println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
}

class Dice (val numSides: Int) {

    fun roll(): Int {
        val randomNumber = (1..numSides).random()
        return randomNumber
    }
}
  1. Uruchom gotowy program, a wynik powinien wyglądać tak.
Your 6 sided dice rolled 5!
Your 20 sided dice rolled 7!

W kodowaniu zwięzłym tekst jest lepszy. Możesz się pozbyć zmiennej randomNumber i zwrócić liczbę losową.

  1. Zmień instrukcję return, by zwracała liczbę losową bezpośrednio.
    fun roll(): Int {
        return (1..numSides).random()
    }

W 2 informacji drukujesz wywołanie, by uzyskać losowy numer do szablonu ciągu znaków. Aby pozbyć się zmiennej diceRoll, możesz zrobić to samo w pierwszej instrukcji drukowania.

  1. Wywołaj myFirstDice.roll() w szablonie ciągu znaków i usuń zmienną diceRoll. Pierwsze 2 wiersze kodu main() wyglądają teraz tak.
    val myFirstDice = Dice(6)
    println("Your ${myFirstDice.numSides} sided dice rolled ${myFirstDice.roll()}!")
  1. Uruchom kod. Dane wyjściowe powinny się nie różnić.

Jest to ostateczny kod po refaktoryzacji go .

fun main() {
    val myFirstDice = Dice(6)
    println("Your ${myFirstDice.numSides} sided dice rolled ${myFirstDice.roll()}!")
    
    val mySecondDice = Dice(20)
    println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
}

class Dice (val numSides: Int) {

    fun roll(): Int {
        return (1..numSides).random()
    }
}
fun main() {
    val myFirstDice = Dice(6)
    val diceRoll = myFirstDice.roll()
    println("Your ${myFirstDice.numSides} sided dice rolled ${diceRoll}!")
    
    val mySecondDice = Dice(20)
    println("Your ${mySecondDice.numSides} sided dice rolled ${mySecondDice.roll()}!")
}

class Dice (val numSides: Int) {

    fun roll(): Int {
        return (1..numSides).random()
    }
}
  • Wywołaj funkcję random() w IntRange, aby wygenerować liczbę losową: (1..6).random()
  • Klasy są planem obiektu. Mogą mieć właściwości i zachowania zaimplementowane jako zmienne i funkcje.
  • Wystąpienie klasy reprezentuje obiekt, często obiekt fizyczny, taki jak kości. Możesz wywołać działania na obiekcie i zmienić jego atrybuty.
  • Podczas tworzenia instancji możesz przekazać dane wejściowe do klasy, określając argument definicji klasy. Przykład: class Dice(val numSides: Int), a następnie utwórz instancję Dice(6).
  • Funkcje mogą zwracać wyniki. Określ typ danych, który zostanie zwrócony w definicji funkcji, i użyj instrukcji return w treści funkcji, aby coś zwrócić. Na przykład: fun example(): Int { return 5 }.

Wykonaj te czynności:

  • Nadaj swojej klasie Dice inny atrybut koloru i utwórz kilka wystąpień kości kości, które będą miały różne boki i kolory.
  • Utwórz klasę Coin, nadaj jej funkcję odwracania, utwórz instancję klasy i rzuć kilka monet. W jaki sposób użyjesz funkcji losowej z zakresem do uzyskania rzutu monetą?