Naloge - razredi (Želva)

Unittestov ta teden ne bo.

Obrnljiva želva

Za ogrevanje dodaj želvi metodo turnAround, ki jo obrne v nasprotno smer.

Rešitev

Metodo turnAround dodaj razredu Turtle

    def turnAround(self):
        self.turn(180)

t = Turtle()
t.turnAround()

Želva+

Razredu Turtle dodaj metodi setWidth in setColor, s katerima določiš debelino in barvo črte, ki jo za seboj pušča želva. Uporabili ju bomo takole:

>>> t.forward(20) 
>>> t.setWidth(10)
>>> t.forward(20) 
>>> t.setColor(risar.rdeca) 
>>> t.forward(20)

Rešitev

Prikazane so le metode, ki jih je treba spremeniti oz. dodati

    def __init__(self):
        self.x, self.y = risar.maxX/2, risar.maxY/2
        self.angle = 0
        self.penActive = True
        self.width = 1  ## DODANO ##
        self.color = risar.bela  ## DODANO ##

        self.pause = 0
        self.body = risar.krog(0, 0, 5, risar.zelena, 3)
        self.head = risar.krog(0, 0, 2, risar.zelena, 3)
        self.update()

    def forward(self, l):
        angle = radians(90 - self.angle)
        nx, ny = self.x+l*cos(angle), self.y-l*sin(angle)
        nx, ny = max(0, nx), max(0, ny)
        nx, ny = min(nx, risar.maxX), min(ny, risar.maxY)
        if self.penActive:
            risar.crta(self.x, self.y, nx, ny, self.color, self.width)  ## SPREMENJENO ##
        self.x, self.y = nx, ny
        self.update()

    def setWidth(self, width):  ## NOVA METODA ##
        self.width = width

    def setColor(self, color):  ## NOVA METODA ##
        self.color = color


# Testiranje
t = Turtle()
t.setWidth(10)
t.forward(20)
t.setColor(risar.rdeca)
t.forward(20)

Indikator peresa

K izrisu želve dodaj še indikator, ali je pero spuščeno ali ne. Pri programiranju pazi, da bodo pravilno delovale tudi kombinacije, kot na primer

>>> t.penUp() 
>>> t.hide() 
>>> t.show()

Po tem mora biti pero nevidno, ker je dvignjeno.

>>> t.hide()
>>> t.penDown()

Pero mora biti nevidno, ker je želva nevidna.

Želva s spuščenim peresom

zelva_dol

Želva z dvignjenim peresom

zelva_gor

Pomoč: Ali je želvja glava vidna, preverite z self.head.isVisible().

Rešitev

Razredu Turtle dodajte oz. popravite naslednje metode:

    def __init__(self):
        self.x, self.y = risar.maxX/2, risar.maxY/2
        self.angle = 0
        self.penActive = True
        self.width = 1
        self.color = risar.bela

        self.pause = 0
        self.body = risar.krog_s(0, 0, 5, risar.zelena, 3)
        self.head = risar.krog_s(0, 0, 2, risar.zelena, 3)
        self.pen = risar.krog_s(0, 0, 2, risar.rumena, 3)  ## DODANO ##
        self.update()

    def show(self):
        self.body.show()
        self.head.show()
        if self.penActive:  ## DODANO ##
            self.pen.show()  ## DODANO ##

    def hide(self):
        self.body.hide()
        self.head.hide()
        self.pen.hide()  ## DODANO ##

    def penUp(self):
        self.penActive = False
        self.pen.hide()  ## DODANO ##

    def penDown(self):
        self.penActive = True
        if self.head.isVisible():  ## DODANO ##
            self.pen.show()  ## DODANO ##

# Testiranje
import turtle

t = turtle.Turtle()
t.hide()
t.penDown()
t.wait()

Štempelj

Dodaj metodi stamp(), ki naredi odtis želve, torej izriše želvo, ki ostane izrisana tudi, ko gre želva naprej, in clearStamps(), 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

stamp1

Če nato rečemo clearStamps(), želvice izginejo:

stamp2

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.

Rešitev

Najprej je bilo potrebno v funkcijo __init__ dodati seznam, v katerega bomo shranjevali odtise želv. Dodamo, recimo

self.stamps = []

Funkciji za odtis želve in brisanje odtisov sta takšni

def stamp(self):
    angle = radians(90 - self.angle)
    body = risar.krog(self.x, self.y, 5, risar.zelena, 3)
    head = risar.krog(self.x+5*cos(angle), self.y-5*sin(angle), 2, risar.zelena, 3)
    self.stamps.append(body)
    self.stamps.append(head)

def clearStamps(self):
    for stamp in self.stamps:
        stamp.hide()
    self.stamps = []

ali takšni

def stamp(self):
    t = Turtle()
    t.fly(self.x, self.y, self.angle)
    self.stamps.append(t)

def clearStamps(self):
    for t in self.stamps:
        t.hide()
    self.stamps = []

Snemalnik makrov

želvi dodaj metode startRecording(), ki sproži snemalnik makrov, stopRecording(), ki ustavi snemanje in vrne posneti makro, ter play(makro), ki izvede posnetek.

t = Turtle()
t.startRecording()
for i in range(4):
    t.forward(100)
    t.right()
kvadrat = t.stopRecording()

for i in range(10):
    t.turn(36)
    t.play(kvadrat)
risar.stoj()

Namig: Če stvari pravilno pripravite, bo metoda play takšna

def play(self, trace):
    for func, pars in trace: 
        func(*pars)

Kaj počne * v vrstici func(*pars)?

Rešitev

Razred Turtle je treba popraviti tako:

    def __init__(self):
        self.x, self.y = risar.maxX/2, risar.maxY/2
        self.angle = 0
        self.penActive = True
        self.width = 1
        self.color = risar.bela
        self.trace = []  ## DODANO ##

        self.pause = 0
        self.body = risar.krog_s(0, 0, 5, risar.zelena, 3)
        self.head = risar.krog_s(0, 0, 2, risar.zelena, 3)
        self.pen = risar.krog_s(0, 0, 2, risar.rumena, 3)
        self.update()

    def startRecording(self):  ## NOVA METODA ##
        self.trace = []

    def stopRecording(self):  ## NOVA METODA ##
        return self.trace[:]

    def play(self, trace):  ## NOVA METODA ##
        for func, pars in trace:
            func(*pars)

    def forward(self, l):
        angle = radians(90 - self.angle)
        nx, ny = self.x+l*cos(angle), self.y-l*sin(angle)
        nx, ny = max(0, nx), max(0, ny)
        nx, ny = min(nx, risar.maxX), min(ny, risar.maxY)
        if self.penActive:
            risar.crta(self.x, self.y, nx, ny, self.color, self.width)
        self.x, self.y = nx, ny
        self.update()
        self.trace.append((self.forward, (l,)))  ## DODANO ##

    def turn(self, angle):
        self.angle += angle
        self.update()
        self.trace.append((self.turn, (angle,)))  ## DODANO ##

# Testiranje
t = Turtle()
t.startRecording()
for i in range(4):
    t.forward(100)
    t.right()
kvadrat = t.stopRecording()

for i in range(10):
    t.turn(36)
    t.play(kvadrat)
risar.stoj()

Ali z dekoratorji:

def __init__(self):
    self.x, self.y = risar.maxX/2, risar.maxY/2
    self.angle = 0
    self.penActive = True
    self.width = 1
    self.color = risar.bela
    self.trace = []  ## DODANO ##

    self.pause = 0
    self.body = risar.krog_s(0, 0, 5, risar.zelena, 3)
    self.head = risar.krog_s(0, 0, 2, risar.zelena, 3)
    self.pen = risar.krog_s(0, 0, 2, risar.rumena, 3)
    self.update()

def startRecording(self):  ## NOVA METODA ##
    self.trace = []

def stopRecording(self):  ## NOVA METODA ##
    return self.trace[:]

def play(self, trace):  ## NOVA METODA ##
    for func, pars in trace:
        func(*pars)

def recorded(f):
    def g(*args):
        args[0].trace.append((f, args))
        f(*args)
    return g

@recorded
def forward(self, l):
    angle = radians(90 - self.angle)
    nx, ny = self.x+l*cos(angle), self.y-l*sin(angle)
    nx, ny = max(0, nx), max(0, ny)
    nx, ny = min(nx, risar.maxX), min(ny, risar.maxY)
    if self.penActive:
        risar.crta(self.x, self.y, nx, ny)
    self.x, self.y = nx, ny
    self.update()

@recorded
def turn(self, angle):
    self.angle += angle
    self.update()

Zadnja sprememba: sreda, 11. januar 2023, 10.41