W poprzedniej części przygotowaliśmy strukturę Smok, Owca i mieszkaniec. Zostało nam uzupełnienie Struktury Smok i spięcie wszystkich elementów programu razem.
ILE SMOK MOŻE ZJEŚĆ?
Za każdym razem, gdy smok będzie zjadał owcę, musi zapamiętać ile zjadł siarki. Jest to jego wewnętrzny stan, więc zmienna przechowująca tą wartość musi być polem struktury Smoka [1].
Dodamy więc do klasy Smok pole zjedzonaSiarka, typu Int
var zjedzonaSiarka = 0
Za każdym razem, gdy smok zje jakąś owcę, będziemy zwiększać wartość tego pola
zjedzonaSiarka += owca.siarka
STAN SMOKA
Po drugie musimy wiedzieć, jaki smok ma stan. Pole przechowujące aktualny stan zadeklarowaliśmy już w poprzedniej części, przypisując mu wartość stanu początkowego Zly:
var stan = Stan.Zly
Jego stan może się zmienić wtedy, gdy osiągnie pewien próg wytrzymałości. A więć Lakomy będzie, gdy zjedzonaSiarka przekroczy 10 (kilogramów), Zmeczony, gdy przekroczy 30 (kilogramów). W stanie Wykonczony pozostanie niezależnie od ilości zjedzonej siarki.
let progi:[Stan:Int] = [Stan.Zly : 10,Stan.Lakomy : 20,Stan.Zmeczony : 30,Stan.Wykonczony : Int.max]
Potrzebujemy więc stałej progi, która zdefiniuje nam progi zjedzonej siarki skutkujące zmianą stanu smoka.
ZJEDZMY COŚ WRESZCIE
Po trzecie musimy zaimplementować funkcję, która pozwoli smokowi najeść się. Niech to będzie funkcja zjedz. Funkcje reprezentują zwykle pewnne czynności, które wykonują obiekty struktur[2]. Dlatego dobrą praktyką będzie nazywanie ich czasownikami [3].
mutating func zjedz(owca:Owca){
if stan == .Wykonczony {
print("S: Jestem \(stan)")
return
}
print("S: Mniam")
zjedzonaSiarka += owca.siarka
if(zjedzonaSiarka >= progi[stan]!){
stan.next()
print("S: Jestem \(stan)")
}
}
Definicja funkcji składa się z nagłówka
mutating func zjedz(owca:Owca)
zawierającego słowo kluczowe
mutating func zjedz(owca:Owca)
nazwę
mutating func zjedz(owca:Owca)
Listy parametrów
mutating func zjedz(owca:Owca)
oraz zawartego między nawiasami {} kodu funkcji. Mutating oznacza, że funkcja będzie mogła zmieniać wartości w strukturze, w której jest zdefiniowana. Inaczej nie dałoby się przypisać do pola zjedzonaSiarka nowej wartości.
Parametrem funkcji jest obiekt struktury Owca. Nie ilość siarki czy ilosć owiec[4]
Powyższy kod sprawdza, jaki jest stan Smoka. Jeśli wykończony, to już nie je. Jeśli smok jest wykończony, wypisuje tylko swój stan i kończy jedzenie. Jeśli jednak nie, to zjada owcę. Jednocześnie dodaje do swojej właściwości (zjedzonaSiarka) ilość siarki, która była w zjedzonej owcy. Jeśli zjedzona siarka przekroczy próg określony w tablicy progi, stan smoka zmienia się na następny.
Pełna wersja struktury Smok wygląda więc tak:
struct Smok{
var zjedzonaSiarka = 0
let progi:[Stan:Int] = [Stan.Zly : 10,Stan.Zmeczony : 30,Stan.Lakomy : 20,Stan.Wykonczony : 40]
var stan = Stan.Zly
mutating func zjedz(owca:Owca){
if stan == .Wykonczony {return}
print("S: Mniam")
zjedzonaSiarka += owca.siarka
if(zjedzonaSiarka >= progi[stan]!){
stan.next()
print("S: Jestem \(stan). Zjadłem \(zjedzonaSiarka)")
}
}
func powitaj(m: Mieszkaniec){
if (stan != .Wykonczony){
print("S: Arrrrr ")
m.przypal()
}
}
}
Pozostaje zatem napisać program, w którym mieszkaniec nakarmi smoka owcami. Potrzebujemy stada owiec, które będziemy przechowywać w tablicy stado
var smok = Smok()
var mieszkaniec = Mieszkaniec()
mieszkaniec.powitaj(smoka: smok)
var stado = [Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:3),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:3),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:2)]
for owca in stado{
smok.zjedz(owca: owca)
}
mieszkaniec.powitaj(smoka: smok)
Jaki będzie wynik działania tego programu? Bajka o smoku jak się patrzy! W dodatku w formie scenariusza ?
M: Witaj smoku
S: Arrrrr
M: Auuuu
S: Mniam
S: Mniam
S: Mniam
S: Mniam
S: Mniam
S: Mniam
S: Jestem Lakomy. Zjadłem 11
S: Mniam
S: Mniam
S: Mniam
S: Mniam
S: Mniam
S: Mniam
S: Jestem Zmeczony. Zjadłem 20
S: Mniam
S: Mniam
S: Mniam
S: Mniam
S: Mniam
S: Mniam
S: Jestem Wykonczony. Zjadłem 31
M: Witaj smoku
PONIŻEJ PEŁEN KOD ROZWIĄZANIA
import Cocoa
var str = "Hello, playground"
enum Stan{
case Zly, Lakomy, Zmeczony, Wykonczony
mutating func next(){
switch self{
case .Zly: self = .Lakomy
case .Lakomy: self = .Zmeczony
case .Zmeczony: self = .Wykonczony
case .Wykonczony: self = .Wykonczony
}
}
}
struct Owca{
var siarka:Int
}
struct Smok{
var zjedzonaSiarka = 0
let progi:[Stan:Int] = [Stan.Zly : 10,Stan.Zmeczony : 30,Stan.Lakomy : 20,Stan.Wykonczony : 40]
var stan = Stan.Zly
mutating func zjedz(owca:Owca){
if stan == .Wykonczony {return}
print("S: Mniam")
zjedzonaSiarka += owca.siarka
if(zjedzonaSiarka >= progi[stan]!){
stan.next()
print("S: Jestem \(stan). Zjadłem \(zjedzonaSiarka)")
}
}
func powitaj(mieszkanca m: Mieszkaniec){
print("S: Arrrrr ")
m.przypal()
}
}
struct Mieszkaniec{
func powitaj(smoka s: Smok){
print("M: Witaj smoku ")
s.powitaj(mieszkanca: self)
}
func przypal(){
print("M: Auuuu ")
}
}
var smok = Smok()
var mieszkaniec = Mieszkaniec()
mieszkaniec.powitaj(smoka: smok)
var stado = [Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:3),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:3),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:2),
Owca(siarka:1),
Owca(siarka:2)]
for owca in stado{
smok.zjedz(owca: owca)
}
- Tak jak w prawdziwym świecie, ilości zjedzonej siarki byłby świadom żołądek Smoka lub klas
- Na razie po polsku, ale w prawdziwych programach będziemy używać języka angielskiego, jako standardu
- Jak w prawdziwym świecie o ilości siarki Smok dowie się dopiero jak zje owcę.