Želva z žigom
Naloga
Želvi dodaj metodi
stamp(), ki naredi odtis želve, torej izriše želvo, ki ostane izrisana tudi, ko gre želva naprej), inclearStamps(), ki pobriše vse odtisnjene želve s trenutne slike
| Program | t.forward(10)
t.stamp()
t.left()
t.forward(100)
t.turn(45)
t.forward(20)
t.stamp()
t.right()
t.forward(40)
t.left()
t.forward(40)
t.right()
t.forward(40)
t.stamp()
t.right()
t.forward(40)
t.hide()
| nariše | ![]() | . Če nato rečemo clearStamps(), želvice izginejo: | ![]() |
Zahteva: metodi morata pravilno delovati tudi, če imamo več želv, ki se odtiskujejo in brišejo svoje odtise!
Namig: stamps naj vse, kar riše, shranjuje v seznam, clearStamps pa pobriše narisano.
Tolažba: metodi imata po štiri vrstice, in še v __init__ dodamo eno, pa smo.
Rešitev
Najprej je bilo potrebno v funkcijo __init__ dodati seznam, v katerega bomo shranjevali odtise želv. Dodamo, recimo
Funkciji za odtis želve in brisanje odtisov sta takšni
(Funkcija je dve vrstici daljša, kot sem obljubil, ker oba kroga zaradi pregledanosti najprej spravim v body in head ter od ondod v seznam. Šlo bi tudi self.stamps.append(risar.krog(self.x, self.y, 5, risar.zelena, 3))...)
Način, na katerega brišemo odtise, sicer ni čisto pravilen, saj so odtisi še vedno na sliki, le vidni niso. Lepše bi bilo turtle.risar.widget.scene.removeItem(stamp), a to očitno presega namen vaje in količino informacije, ki sem vam jo dal.
Druge rešitve
Pogosto sem videval tole
self.x jemljemo kar self.body.x() in tako naprej, se izognemo temu, da v okviru te funkcije računamo položaj glave in telesa. Ni mi všeč, nimam pa kakih otipljivih argumentov, zakaj. Najbrž je ravno tako OK.
Rešitev, ki mi res ni všeč, bila pa je precej pogosta, je tale
Razlog, da je ne maram, je v tem, da za seboj ne pušča le preprostih objektov, krogov, temveč kar cele želve. Njena prednost bi se pokazala, če bi se nenadoma premislili in želv ne bi več risali s krogi temveč s kvadrati: metode stamp nam kljub temu ne bi bilo potrebno spreminjati, saj ničesar ne riše sama. Slabost je v tem, da so želve bolj zapletena reč od krogov in požrejo več pomnilnika. Res pa nam je v tem primeru za teh par bajtov popolnoma vseeno. Moji argumenti proti tej rešitvi so bolj načelni kot praktični.
Nerodnosti
Pustite self.head in self.body pri miru! Načelen razlog je v tem, da dodajamo odtise in to nima zveze z glavo in telesom (razen tega, da slučajno enako izgleda). Praktičen je v tem, da se na ta način prehitro zaplezate in morate reševati probleme z želvo, ki izginja.
Tipičen primer takega gre nekako tako:
self.update(), tako da je bila želva do prvega premika celo narisana v zgornjem levem kotu.
Spolzka tla pa so tule. V __init__ dodamo
Metodo stamp napišemo kot
stamps je trenutna slika želve. Se pravi: stamps vedno vsebuje vse odtise in še želvo za povrh. Na to moramo paziti pri brisanju, ki ga pravilno napišemo takole:
Resne napake
Zelo narobe je tole
Poleg tega sem kot nepravilno rešene naloge štel tistih nekaj rešitev, ki so imele namesto metod funkcije, saj je bil cilj naloge učenje objektnega programiranja.
Izpeljevanje
Nekateri ste iz razreda Turtle izpeljali nov razred, ki zna delati odtise. To se pravilno naredi tako:
Pomembno je torej, da ima izpeljani razred svoj __init__, ki pokliče podedovanega, nato pa nastavi self.stamps. O tem, kako se kliče podedovane metode, kadar jih povozimo z novimi, na prejšnjih predavanjih nisem govoril, saj ni bilo časa. Poleg tega način, na katerega sem to naredil zgoraj, ni več v modi, vendar onega, pravega, ne moremo uporabiti, ker bi bilo za to potrebno malenkost spremeniti razred Turtle. Kogar zanima, naj si ogleda; na predavanjih pa bomo že še omenili.
Nekateri so namesto, da bi definirali svoj __init__, naredili takole
stamps lastnost razreda in ne objekta. Tudi to je nekaj, o čemer na predavanjih nisem posebej govoril in niti ne nameravam; to je ekvivalentno razrednim spremenljivkam (class variable) v C++ in presega predavanja iz Programiranja 1. Za tiste, ki jih zanima, pa je tu primer.
Zdaj je l skupen vsem objektom razreda A, k pa ima vsak objekt posebej. Preverimo:

