Naloga se nanaša na nalogi prejšnjih dveh tednov (Šikaniranje, Lokacije ovir): večinoma je potrebno le preoblikovati to, kar ste programirali takrat, v funkcije. Pri reševanju smete uporabiti tudi objavljene rešitve prejšnjih dveh nalog.

Napisati je potrebno naslednje funkcije:

Rešitev

def stevilo_ovir(ovire):
    return len(ovire)

def dolzina_ovir(ovire):
    dolzina = 0
    for x0, x1, _ in ovire:
        dolzina += x1 - x0 + 1
    return dolzina

def sirina(ovire):
    najx = 0
    for _, x1, _ in ovire:
        if x1 > najx:
            najx = x1
    return najx

def pretvori_vrstico(vrstica):
    vrstica = "." + vrstica + "."
    bloki = []
    for i, znak in enumerate(vrstica):
        if znak == "#":
            if vrstica[i - 1] == ".":
                zacetek = i
            if vrstica[i + 1] == ".":
                bloki.append((zacetek, i))
    return bloki

def dodaj_vrstico(bloki, y):
    z_vrstico = []
    for x0, x1 in bloki:
        z_vrstico.append((x0, x1, y))
    return z_vrstico

def pretvori_zemljevid(zemljevid):
    ovire = []
    for y, vrstica in enumerate(zemljevid, start=1):
        ovire += dodaj_vrstico(pretvori_vrstico(vrstica), y)
    return ovire

def globina(ovire, x):
    najy = None
    for x0, x1, y in ovire:
        if x0 <= x <= x1 and (najy == None or y < najy):
            najy = y
    return najy

def naj_stolpec(ovire):
    naj_y = 0
    for x in range(1, sirina(ovire) + 1):
        g = globina(ovire, x)
        if g == None:
            return x, None
        if g > naj_y:
            naj_y = g
            naj_x = x
    return naj_x, naj_y

def senca(ovire):
    zaprti = []
    for x in range(1, sirina(ovire) + 1):
        zaprti.append(globina(ovire, x) == None)
    return zaprti

Komentar si zasluži le par funkcij.

pretvori_zemljevid

V pretvori_zemljevid dodamo vrstico z += ne z append.

# Tole ne deluje!
    for y, vrstica in enumerate(zemljevid, start=1):
        ovire.append(dodaj_vrstico(pretvori_vrstico(vrstica), y))

Metoda append bi dodala vrstico kot nov element seznama - se pravi vrstico, ne njenih elementov. Tako bi dobili seznam seznamov.

Alternative so extend, ki naredi isto kot +=,

    for y, vrstica in enumerate(zemljevid, start=1):
        ovire.extend(dodaj_vrstico(pretvori_vrstico(vrstica), y))

ali pa dodajanje posamičnih elementov, kar pa je daljše, nepotrebno in počasnejše

    for y, vrstica in enumerate(zemljevid, start=1):
        for ovira in dodaj_vrstico(pretvori_vrstico(vrstica), y):
            ovire.append(ovira)

V tej funkciji je zanimivo tudi, kako pridemo do številke vrstice. Lahko štejemo sami, s spremenljivko, ki jo sami povečujemo, lahko pa uporabimo enumerate. Če funkciji enumerate dodamo argument start=1, bo štela od 1. Sicer pa pač šteje od 0 in kot številko vrstice uporabimo y + 1.

naj_stolpec

V tej funkciji je praktično, da takrat, ko najdemo prost stolpec, kar takoj vrnemo x, None. To prekine zanko, konča funkcijo, vrne rezultat.

senca

Dve stvari. Ta funkcija lahko kliče funkcijo globina. Pravzaprav je zelo koristno, da jo, saj sicer ponovimo večino kode te funkcije.

Druga:

zaprti.append(globina(ovire, x) == None)

in ne

if globina(ovire, x) == None:
    zaprti.append(True)
else:
    zaprti.append(False)

Seveda deluje tudi drugo, vendar ni smiselno, saj je globina(ovire, x) == None že vrednost, ki jo želimo dodati v seznam. (Zanimivo: študenti rezultat primerjanja stalno dojemajo kot pogoj, ki ga lahko uporabljajo v if in while, ne pa kot vrednost, ki jo lahko uporabijo, kjerkoli. Mogoče bi se to rešilo tako, da bi že eno predavanje, preden začnemo s pogoji, predstavil logične izraze, kot nekaj, kar pač vrne True ali False?!)