Minobot
Naloga je variacija na temo naloge Minolovec. Ukvarja se le s premiki. (Tisto, kar je bilo v nalogi za oceno 7.)
Testi
Testi: testi-minobot.zip
Python bo ob poganjanju testov morda sitnaril z nekimi "warningi". Naj vas ne vznemirjajo. Povezani so s tem, da vas nisem učil čisto pravilnega načina odpiranja datotek.
O robotih
Podana je funkcija premik(ukaz, x, y, smer)
, ki kot argument prejme ukaz
, trenutne koordinate robota (x
in y
) in smer, v katero je obrnjen. Funkcija vrne trojko (terko), v kateri sta novi koordinati in nova smer.
Ukaz je lahko niz "R"
, niz "L"
, ki pomenita, da se robot obrne za 90 stopinj levo ali desno (glede na trenutno smer) ali pa število korakov.
Smer je eden izmed znakov N, E, S ali W, ki predstavljajo smeri neba v angleščini.
Za še točnejši opis je funkcija kar tule. Če gornji opis ne zadošča, bo branje te funkcije (ki jo morate znati prebrati), gotovo dovolj.
def premik(ukaz, x, y, smer):
smeri = "NESW"
premiki = [(0, -1), (1, 0), (0, 1), (-1, 0)]
ismer = smeri.index(smer)
if ukaz == "R":
smer = smeri[(ismer + 1) % 4]
elif ukaz == "L":
smer = smeri[(ismer - 1) % 4]
else:
dx, dy = premiki[ismer]
x += dx * ukaz
y += dy * ukaz
return x, y, smer
Če funkcijo pokličemo s premik(10, 5, 3, "E")
, vrne (15, 3, "E")
(robot gre za 10 korakov proti vzhodu, torej se x
poveča za 10).
Če jo pokličemo s premik("L", 5, 3, "E")
, vrne (5, 3, 'N')
(robot se obrne na levo, torej iz vzhoda proti severu).
Če jo pokličemo s premik("R", 5, 3, "E")
, vrne (5, 3, 'S')
(robot se obrne na desno, torej iz vzhoda proti jugu).
Za več informacij o robotih v Firefox vpišite "URL" about:robots
. (Deluje le v Firefoxu.)
Obvezna naloga
1.Napiši funkcijo izvedi(ime_datoteke)
, ki kot argument dobi ime datoteke z ukazi, ki naj jih robot izvede. Datoteka je oblike:
DESNO
NAPREJ 12
DESNO
NAPREJ 2
LEVO
NAPREJ 3
LEVO
LEVO
Funkcija mora vrniti seznam zapodenih stanj, torej trojk z vrednostmi x, y in smeri, skozi katere gre robot, ko izvaja ta program. Robot je v začetku na koordinatah (0, 0) in obrnjen proti severu.
Gornji ukazi so shranjeni v datoteki primer.txt. Če pokličemo funkcijo z izvedi("primer.txt")
, vrne
[(0, 0, 'N'), (0, 0, 'E'), (12, 0, 'E'),
(12, 0, 'S'), (12, 2, 'S'), (12, 2, 'E'),
(15, 2, 'E'), (15, 2, 'N'), (15, 2, 'W')]
Funkcija lahko uporablja podano funkcijo premik
(oziroma je to celo priporočeno). Samo za prevajanje ukazov v angleščino in številke boste morali poskrbeti.
Napiši funkcijo
opisi_stanje(x, y, smer)
, ki vrne niz z opisom stanja. Stanje je opisano s koordinatama, med katerima je dvopičje; koordinata x je poravnana desno, y pa levo. Obe sta izpisani na tri mesta. Sledi presledek in znak, ki pove smer. Znaki za smeri so ^, >, v in < (za N, E, S in W).Klic
opisi_stanje(0, 12, "N")
vrne niz" 0:12 ^"
. (Pazi na presledke).Napiši funkcijo
prevedi(ime_vhoda, ime_izhoda)
. Funkcija mora prebrati vhodno datoteko (najbrž tako, da pokliče funkcijoizvedi
?) in v izhodno datoteko izpisati zaporedje stanj v obliki, kot jo vrača funkcijaopisi_stanje
.Če pokličemo
prevedi("primer.txt", "stanja.txt")
, mora ustvariti datoteko stanja.txt z naslednjo vsebino:0:0 ^ 0:0 > 12:0 > 12:0 v 12:2 v 12:2 > 15:2 > 15:2 ^ 15:2 <
Rešitev
Bistvo funkcije je tole: v zanki moramo klicati x, y, smer = premik(ukaz, x, y, smer)
. Funkcija premik
namreč sprejme trenutne koordinate in smer ter vrne nove koordinate in smer - ki jih shranimo v spremenljivke z istimi imeni. Če pokličemo le premik(ukaz, x, y, smer)
, funkcija ne bo spreminjala vrednosti x
, y
in smer
, saj tega ne more. (Kot smo se učili na nekih predavanjih, kjer smo risali puščice.)
Poleg tega je potrebno stanja robota še zapisovati v seznam (stanja.append((x, y, smer))
), pa smeri je potrebno prevajati iz slovenščine v angleščino...
Če zložimo vse skupaj, dobimo
def izvedi(ime_datoteke):
x, y, smer = 0, 0, "N"
stanja = [(x, y, smer)]
for vrstica in open(ime_datoteke):
vrstica = vrstica.strip()
if vrstica.startswith("NAPREJ "):
ukaz = int(vrstica.split()[-1])
elif vrstica == "LEVO":
ukaz = "L"
else:
ukaz = "R"
x, y, smer = premik(ukaz, x, y, smer)
stanja.append((x, y, smer))
return stanja
Ne spreglejte, kako smo šli čez vrstice datoteke: for vrstica in open(ime_datoteke)
. Nič read().split("\n")
ali kaj podobno zapletenega.
Ostale funkcije so preprostejše.
Funkcija opisi_stanje
zahteva le, da znamo oblikovati izpis: najprej prvo število na tri mesta, poravnano na desno ({:>3}
), nato dvopičje (:
), nato drugo število na tri mesta poravnano na levo ({:<3}
), pa presledek in potem še en znak.
Poleg tega je potrebno - da vas malo zafrkavam - spremeniti smer iz N, E, S in W v ^, >, v in <. Recimo z indeksi.
def opisi_stanje(x, y, smer):
crke = "NESW"
znaki = "^>v<"
return "{:>3}:{:<3} {}".format(x, y, znaki[crke.index(smer)])
Zadnja funkcija, prevedi
uporabi funkcijo izvedi
, nato pa gre prek seznama, ki ga le-ta vrne in za vsako stanje v datoteko zapiše, kar pravi funkcija opisi_stanje
in nato doda znak za prehod v novo vrstico, \n
.
def prevedi(vhod, izhod):
stanja = izvedi(vhod)
ven = open(izhod, "wt")
for x, y, smer in stanja:
ven.write(opisi_stanje(x, y, smer) + "\n")
Dodatna naloga
Napiši funkcijo opisi_stanje_2(x, y, smer)
, ki je podobna funkciji opisi_stanje
, le da je smer na začetku in da to okrog koordinat oklepaji, takole ^ (0:12)
. Koordinata x
naj, skupaj z oklepajem, zasede štiri mesta.
Znajdite se. :)
Rešitev
Težava je v tem, da hočemo izpisati oklepaj in število tako, da skupaj zasedeta štiri mesta. En način je tale
def opisi_stanje_2(x, y, smer):
crke = "NESW"
znaki = "^>v<"
return "{} {:>4}:{})".format(znaki[crke.index(smer)], "({}".format(x), y)