Naloga

Ogrevalna naloga

Napiši program, ki izpiše

( 0, 0): 0 (125, 0): 1 (250, 0): 2 (375, 0): 3 (500, 0): 4 (625, 0): 5 ( 0, 125): 6 (125, 125): 7 (250, 125): 8 (375, 125): 9 (500, 125): 10 (625, 125): 11 ( 0, 250): 12 (125, 250): 13 (250, 250): 14 (375, 250): 15 (500, 250): 16 (625, 250): 17 ( 0, 375): 18 (125, 375): 19 (250, 375): 20 (375, 375): 21 (500, 375): 22 (625, 375): 23

Prva vrstica programa mora biti for i in range(24):. Celoten program (skupaj s prvo vrstico bo dolg kvečjemu štiri vrstice) naj bo znotraj te zanke in naj ne vsebuje nobene druge zanke. Torej: program bo imel, recimo, dva print-a in en if. Uporabljal bo eno samo spremenljivko, i.

Funkcija print gre vedno v novo vrstico; temu se izognemo tako, da dodamo poimenovani argument end, npr. print("bla bla", end="").

Obvezna naloga

Napiši program, ki pokaže vse slike v datotekah s končnico png iz trenutnega direktorija v takšni obliki:

Tisto, kar si izpisoval v ogrevalni nalogi, so koordinate slik. Besedilo, to je, imena datotek, je 100 točk nižje, velikost pisave je 10.

Uporabite lahko primere slik, objavljene na Učilnici.

Pazi:

  • "Brati iz trenutnega direktorija" pomeni os.listdir("."), ne da bi prej spreminjal trenutni direktorij z os.chdir ali čim podobnim.
  • Slike naj bodo urejene po abecedi.
  • Program sme predpostavljati, da slike niso večje kot 100x100 točk;
  • Program ne sme računati na to, da gre vedno za te slike ali da jih je vedno natančno 23.
  • Če je slik več kot 24, naj jih pokaže le 24.

Dodatna naloga

V dodatni nalogi bo potrebno narediti kolaž slik.

Najprej napiši program, ki takole razdeli sliko.

Postopek je takšen: program (načelno) najprej prereže sliko z navpično črto. Ta je na poljubnem mestu na sliki, vendar vsaj 100 točk od levega ali desnega roba. Nastala dela reže vodoravno, pri čemer mora biti rez vsaj 100 točk od zgornjega in od spodnjega roba. Nastale dele reže navpično, te potem spet vodoravno in tako naprej. Ker mora biti rez vedno vsaj 100 točk od roba, pravokotnikov, ki so široki manj kot 200 točk, ni več mogoče rezati navpično. V tem primeru jih prerežemo vodoravno, če gre. Prav tako pravokotnikov, ki so visoki manj kot 200 točk, ne moremo rezati vodoravno, pač pa jih režemo navpično, če gre.

Ko si uspel izrisati gornjo sliko (seveda bo pri tebi drugačna - in to vsakič, ko znova poženeš program), dodaj še fotografije. Te vstaviš v pravokotnike, ki jih ne moreš več rezati. Postavi jih na sredo pravokotnika (predpostavi, da je velikost slike 100x100 točk). Tako kot v prejšnji nalogi uporabi slike iz trenutnega direktorija. Slike morajo biti naključno premešane. Vsaka se sme pojaviti samo enkrat. Če jih zmanjka, pusti preostale pravokotnike prazne. Če je slik preveč, odvečnih slik ne prikaži.

Rešitev

Ogrevalna naloga: izpis številk in koordinat

Ogrevalna naloga navadno predstavlja korak proti rešitvi "prave". Tudi tokrat je bilo sicer tako, vendar bi lahko pravo brez večjih težav rešili tudi brez ogrevalne. Pač pa je bil namen ogrevalne naloge, da vam pomaga, da bi pravo nalogo rešili elegantneje, kot bi jo sicer.

for i in range(24): print("({:3}, {:3}): {:2} ".format(i % 6 * 125, i // 6 * 125, i), end="") if i % 6 == 5: print()

Poskušal sem vam pokazati, da lahko koordinate slike (ki jih morate računati v pravi nalogi) brez težav izračunate iz zaporedne številke slike. Stolpec je enak ostanku po deljenju zaporedne številke s 6, številko vrstice pa dobimo s celoštevilskim deljenjem s 6. Kadar je ostanek po deljenju s 6 enak 5, je potrebno iti tudi v novo vrsto, sicer pa ne (end="").

Obvezna naloga: Album

Za rešitev sem oglašal, da je dolga (izvzemši importe) samo štiri vrstice. Je, vendar bi morali programirati malo grše, kot hočemo; problem je v filtriranju (hočemo samo PNG-je) in urejanju. Bistveno daljša pa le ni.

import risar import os w = h = 125 slike = [] for fn in os.listdir("."): if os.path.splitext(fn)[1] == ".png": slike.append(fn) slike = sorted(slike)[:24] for i, fn in enumerate(slike): x, y = i % 6 * w, i // 6 * h risar.slika(x, y, fn) risar.besedilo(x, y + 100, fn, velikost=10)

Prvi del je nekaj, kar bi moralo biti po nalogi "Direktoriji" trivialno: izberemo vse datoteke s končnico png, jih uredimo in potem vzamemo samo prvih 24.

Drugi del so tiste "štiri vrstice". Spremenljivki i in fn vsebujeta zaporedno številko in ime datoteke (Guido, hvala za enumerate!). Iz zaporedne številke izračunamo koordinate ter postavimo v okno sliko in podnapis.

Dodatna naloga: Kolaž

Ta naloga pa je predvsem vaja iz rekurzije. Malo spominja na trikotnik Sierpinskega. Nekoliko lažja je, ker je lažje preračunavati koordinate, istočasno pa nekoliko težja, ker je potrebno obračati smer. Tole rešitev vsekakor dobro preberite, če se slučajno prikrade kaj podobnega na izpit.

import os import random import risar def kolaz(x0, y0, x1, y1, navp, slike): if x1 - x0 < 200 and y1 - y0 < 200: if slike: risar.slika((x0+x1)/2 - 50, (y0+y1)/2 - 50, slike.pop()) elif navp: if x1 - x0 >= 200: xs = random.randint(x0+100, x1-100) risar.crta(xs, y0, xs, y1, sirina=3) kolaz(x0, y0, xs, y1, not navp, slike) kolaz(xs, y0, x1, y1, not navp, slike) else: kolaz(x0, y0, x1, y1, not navp, slike) else: if y1 - y0 >= 200: ys = random.randint(y0+100, y1-100) risar.crta(x0, ys, x1, ys, sirina=3) kolaz(x0, y0, x1, ys, not navp, slike) kolaz(x0, ys, x1, y1, not navp, slike) else: kolaz(x0, y0, x1, y1, not navp, slike) slike = [] for fn in os.listdir("."): if os.path.splitext(fn)[1] == ".png": slike.append(fn) random.shuffle(slike) kolaz(0, 0, risar.maxX, risar.maxY, True, slike)

Poglejmo najprej spodnji del: spet zložimo imena vseh datotek s slikami v seznam, le da ga zdaj naključno premešamo. Nato pokličemo rekurzivno funkcijo kolaz. Ta bo imela pet argumentov (v prvem koraku lahko zadnjega, seznam slik, izpustimo). Prvi štirje so koordinate pravokotnika, ki ga je potrebno razdeliti. Naslednji argument pove, ali ga je potrebno razdeliti z navpično črto; to je lahko res ali ne (True ali False). Zadnji je premešani seznam slik.

Funkcija dela takole: najprej preveri, ali je pravokotnik slučajno že premajhen, da bi ga delili v katerikoli smeri. Če je tako, pogleda, ali imamo še kakšno sliko (lahko bi jih tudi že zmanjkalo...). Če jo imamo, jo vstavi. Do slike pride s slike.pop(), ki vrne zadnjo sliko na seznamu in jo odstrani z njega - natačno tisto, kar potrebujemo.

Če pravokotnik še ni premajhen, preveri, ali ga je potrebno razdeliti v navpični smeri. Če je tako, preveri, ali ga je sploh še mogoče deliti v navpični smeri. Če je še dovolj velik, izbere koordinato, kjer bo potegnil navpično črto; ta mora biti med x0+100 in x1-100, da bo dovolj daleč od roba. Koordinati y sta seveda takšni, kot smo ju dobili ob klicu funkcije. Potegne torej črto, potem pa pokliče funkcijo kolaz (torej samo sebe) dvakrat - enkrat za levi, enkrat za desni pravokotnik. Pozorno poglejte in razmislite koordinate! Bodite tudi pozorni na to, kaj storimo z argumentom, ki določa smer: obrnemo ga. Ker vemo, da je True, bi sicer lahko namesto not navp pisali tudi False.

Če je pravokotnik premajhen, da bi ga delili z navpično črto, ga bomo z vodoravno. To naredimo tako da, preprosto, ponovno pokličemo kolaz z enakimi argumenti, le smer obrnemo.

V drugi polovici funckije naredimo isto še za delitev z vodoravno črto.

Funkcijo bi bilo možno napisati z manj klici kolaz. Vendar bi bila potem najbrž bolj in ne manj zapletena.

Zadnja sprememba: četrtek, 25. marec 2021, 20.55