Trdoživi kolesarji, eksplozije in duhovi
Pri reševanju te naloge se trudi programirati čim manj. Seveda ne tako, da prepustiš del drugim :), pač pa naj bodo razredi smiselno izpeljani eden iz drugega in naj ne ponavljajo kode, ki jo lahko nadomestijo metode starševskih razredov.
Pred reševanjem preberi celotno nalogo, da ne boš pri nalogi za oceno 7 ali 8 spreminjal tega, kar si naredil za 6. Kateri razred bo izpeljan iz katerega, se odloči sam. Vrstni red opisov v nalogi ne implicira nujno hierarhije razredov.
Atribute imenuj, kakor želiš. Po mili volji smeš dodajati tudi svoje metode (tako kot smo na predavanjih dodali želvi metodo update
). Pač pa avtor naloge (= jaz) ne vidi potrebe, da bi vsak razred definiral svoje metode prevozi
, lokacija
, razdalja
, pot
in obiskana_polja
: te definiraj le v osnovnem razredu. Početi torej smeš kar želiš, dokler bodo vse metode počele vse, kar zahteva naloga, in bo tvoj izdelek prestal teste.
Ocena 6
Napiši razred
Kolesar
.Konstruktor
__init__(self, vrstica, stolpec, zemljevid)
kot argument prejme začetni koordinati kolesarja in množico koordinat ovir, podanih s terkami(vrstica, stolpec)
.Primer na sliki je opisan z množico
{(2, 4), (2, 11), (2, 12), (2, 13), (4, 2), (4, 10), (5, 2), (5, 8), (6, 7), (7, 11), (8, 4), (8, 5), (8, 6), (9, 2), (10, 6), (10, 11), (11, 3), (11, 10), (12, 4), (12, 11), (13, 7), (13, 12)}
Kako dodati konstruktorju argumente, smo videli na predavanju, v zapiskih pa to najdeš takoj na začetku zapiskov naslednjega tedna.
premik(self, smer)
prejme smer"<"
,">"
,"^"
ali"v"
. Metoda premakne kolesarja za en kvadratek v podano smer, če tam ni ovire. Če se na ciljnem kvadratku nahaja ovira, pa kolesar ne spremeni pozicije, temveč obleži, kjer je in se poslej ne odziva več na nadaljnje ukazepremik
alipojdi
.prevozi(self, pot)
prejme niz z zaporedjem premikov. V nizu se izmenjujejo števke (= enomestna števila) in smeri. Tako, na primer,"3>1v2^4^"
pomeni tri korake desno, enega dol, 2 gor in potem še štiri gor. Funkcija mora izvesti vse podane korake do konca ali do trenutka, ko se kolesar zaleti v oviro.
Recimo, da kolesar izvaja
"3>"
, tri korake desno. Rezultat mora biti ekvivalenten temu, da trikrat izvede premik>
. Če je že takoj desno od njega ovira, obleži še preden se začne premikati. Če pa je desno eno prazno polje in nato ovira, se zapelje na to, prazno polje in ustavi.lokacija()
vrne trenutne koordinate kolesarja v obliki terke(vrstica, stolpec)
.
Ocena 7
Dodaj naslednje metode.
razdalja()
vrne razdaljo (v številu) kvadratkov, ki jih je doslej (oz. do nesreče) prevozil kolesar.obiskana_polja()
vrne množico koordinat polj, ki jih je obiskal kolesar. Obiskana polja vključujejo tudi začetno polje. Pazi: razdalja ni nujno enaka številu obiskanih polj (+1, za začetno polje), saj se lahko polja ponavljajo, v množici pa nastopajo le enkrat!pot
vrne prevoženo pot v obliki, v kakršni jo sprejema metodaprevozi
.Rezultat funkcije
pot
naj bo zapisana strnjeno. Recimo, da kolesarkaana
prevozi takšno pot:ana = Kolesar(2, 2, zemljevid) ana.premik(">") ana.premik(">") ana.prevozi("2>") ana.prevozi("8v") ana.prevozi("4v") ana.premik(">")
Po tem zaporedju klicev mora
ana.pot()
vrniti"4>9v3v1>"
.- Prvi trije klici (oba
premik
in še enprevozi
) so shranjeni v4>
. - 12 premikov v smeri navzdol ni zapisanih kot
12v
, ker morajo biti vsa števila enomestna, zato se shrani9v
in nato3v
.
Nasvet: niz s potjo sestavljaj sproti, med premikanjem, tako da "popravljaš" njegov konec in dodajaš, kadar je potrebno.
- Prvi trije klici (oba
Ocena 8
Napiši razred
Duh
. Ta je podoben razreduKolesar
, vendar zna voziti skozi ovire, kot da jih ni: če se zapelje na polje z oviro, se v isti potezi znajde na drugi strani. Če se zaleti v serijo ovir, gre v isti potezi skoznje.Duh
, ki se na gornji sliki nahaja na(9, 4)
bo po premiku v smeri^
na polju(7, 4)
. Pri tem se šteje, da je prevozil dve polji - vključno z oviro: obiskana polja so{(9, 4), (8, 4), (7, 4)}
, metodapot()
pa vrne2^
(ne"1^"
).Duh
, ki se nahaja na(8, 2)
bo po premiku4>
na polju(8, 9)
(in ne(8, 6)
ali(8, 7)
). Polja z ovirami zanj preprosto "ne štejejo", upoštevajo pa se pri razdalji: s klicemprevozi("4>")
ni prevozil 4 polj temveč 7 polj. (To pravilo je postavljeno tako, da bi bo program preprostejši - če se ga lotiš pametno.)
Napiši tudi razred
Trdozivec
, ki je podoben razreduKolesar
, vendar bolj trdoživ. Njegov konstruktor prejme še en dodatni argument,trdozivost
. Ta pove, v koliko ovir se mora kolesar zaleteti, da obleži. Če jetrdozivost
enaka 3, kolesar obleži, ko se zaleti tretjič. Premik v oviro se seveda nikoli ne izvede (trdoživec ni duh!); razlika med trdoživcem in softičem je samo v tem, da trdoživec ne obleži že pred prvo oviro.Pozor: če je ovira desno od kolesarja, klic
prevozi("3>")
povzroči, da se kolesar trikrat zaleti vanjo. Če je njegova trdoživost enaka 3 ali manj, obleži, če je 4 ali več, pa preživi.Napiši, končno, razred
Eksplozivec
. Temu ovire ne povzročajo prav nobene škode, pač pa jo on povzroči oviram: ovira, v katero se zaleti eksplozivec, izgine in eksplozivec se pomakne na to polje, kot da ovire tam sploh nikoli ne bilo.V nekem srečnem scenariju sta Ana (Eksplozivec) in Berta (Kolesar) začeli na polju 10, 2. Ana je šla gor. Za njo je šla gor še Berta -- in uspela, saj je Ana razstrelila oviro pred njo!
Če nameravaš reševati tudi dodatno naloge, ovire odstranjuj iz zemljevida tako, da kličeš metodo
discard
.
Ocena 9
Oddelek za gozdarsko dejavnost in motorni promet skliče izredno sejo, na kateri obravnava problem prevelike pretočnosti kolesarskih stez zaradi eksplozivno odstranjenih ovir. Na njem sklene in po hitrem postopku naroči trdnejše ovire. Nove ovire preživijo tri eksplozije. Eksplozivni kolesar vedno preživi trk (eksplozivni kolesar je na nek način neskončno trdoživ), vendar se ne premakne z mesta, dokler ovira ne eksplodira dovoljkrat.
Vzemimo, da je eksplozivni kolesar na polju (10, 2). Premik "1^"
ali "2^"
ga ne premakneta z mesta, temveč le načenjata oviro. Premik "3^"
(oziroma, v splošnem trije trki v to oviro, ne glede na smer trka in čas, ki mine med njimi) bi jo res uničil in premaknil kolesarja na polje z oviro ((9, 2)). Če eksplozivni kolesar na polju (10, 2) izvede premik "5^"
, se premakne na polje (7, 2): prva dva premika sta zgolj uničevala oviro, v tretjem, ki je uničil oviro, pa se je že prekamnil na (9, 2) (in v naslednjih dveh do (7, 2)).
Da poskrbiš za ta scenarij, pusti pri miru vse razrede s kolesarji (ob predpostavki, da so sprogramirani pravilno).
Pač pa napiši razred Ovire
. Izpeljan naj bo iz razreda dict
. Testi za dodatno nalogo bodo ponovno izvedli vse teste za obvezno nalogo (razen teh, ki vključujejo posebne efekte, se prvi eksplozije), a kot argument zemljevid
namesto množice podali tvoj razred Ovire
. Zato poskrbi, da boš v obvezni nalogi uporabljal množice tako, da bo delovala tudi, če bodo Ovire
v resnici slovar. (Namig: razmisliti moraš, kaj bodo tvoji ključi.)
Če bo razred Ovire
izpeljan iz razreda dict
, zadošča, da definiraš
- konstruktor, ki prejme množico ovir,
- metodo
discard
, ki kot argument prejme koordinate ovire, vendar jo dejansko odstrani šele ob tretjem klicu. (Na tem mestu razmisli, kaj so vrednosti v tvojem slovarju.) Če na podanih koordinatah ni ovire,discard
ne stori ničesar.
Tvoj slovar se mora torej vesti tako:
>>> ovire = Ovire({(1, 1), (2, 4)})
>>> ovire.discard((1, 1))
>>> (1, 1) in ovire
True
>>> ovire.discard((2, 4))
>>> (2, 4) in ovire
True
>>> ovire.discard((1, 1))
>>> (1, 1) in ovire
True
>>> ovire.discard((1, 1))
>>> (1, 1) in ovire
False
>>> (2, 4) in ovire
True
Pomoč: konstruktor razreda Ovire
bo poklical super().__init__
, kot vsi zgledno napisani konstruktorji. Kot argument mu podaj primerno sestavljen slovar.
Ocena 9 in 10
Za oceno 9 bo potrebno sprogramirati še nekaj, prav tako seveda za oceno 10. Navodila bodo še objavljena.
Testi
- 6. januar 2025, 17:53