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.

  1. 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).

  2. Napiši funkcijo prevedi(ime_vhoda, ime_izhoda). Funkcija mora prebrati vhodno datoteko (najbrž tako, da pokliče funkcijo izvedi?) in v izhodno datoteko izpisati zaporedje stanj v obliki, kot jo vrača funkcija opisi_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)
Zadnja sprememba: četrtek, 25. marec 2021, 18.25