Skúška 1.2.2024 - Manic Miner


V osemdesiatych rokoch minulého storočia bola veľmi populárna počítačová hra Manic Miner, v ktorej sa baník Willy pohybuje v jaskynnom bludisku (štvorcovej sieti) pomocou klávesových šípok, zbiera zlaté mince, pričom v jaskyni môžu byť chodby alebo celé úseky, ktoré ho automaticky presúvajú ďalej (niečo ako bežiace pásy). Cieľom je odsledovať, kam sa Willy po zadanej postupnosti šípok dostane, koľko pritom prejde krokov a koľko pritom zozbiera zlatých mincí.

Textový súbor popisuje hraciu plochu (jaskyňu) ako štvorcovú sieť (všetky riadky sú rovnako dlhé). Prvé riadky obsahujú samotný popis jaskyne , pričom znaky v súbore majú tento význam:

  • '.' voľné políčko

  • 'X' stena

  • '>', 'v', '<', '^' políčka s automatickým presúvaním: vpravo, dole, vľavo, hore

Ďalej nasleduje riadok s pozíciou baníka Willyho ako dvojica celých čísel: poradové číslo riadka a stĺpca (číslujeme od 0). Tento sa bude v priebehu hry zobrazovať znakom '+'. Na začiatku hry Willy stojí na voľnom políčku (znak '.'). Za týmto riadkom až do konca súboru nasledujú dvojice celých čísel, ktoré označujú pozície zlatých mincí. Tieto sa budú počas hry zobrazovať znakom 'o'. Mince sa na začiatku hry môžu nachádzať na ľubovoľných políčkach (okrem štartovej pozície Willyho), t.j. aj na presúvacích políčkach aj na políčkach so stenou (tie sa zrejme nebudú dať zozbierať).

Tvojou úlohou je prečítať textový súbor s popisom jaskyne a odsimulovať zadanú postupnosť stláčaných šípok ('L' vľavo, 'R' vpravo, 'U' hore, 'D' dole). Samotný pohyb hráča sa bude riadiť podľa týchto pravidiel:

  • šípka na voľné políčko (prípadne s mincou) presunie hráča (a zdvihne mincu)

  • šípka smerom k stene, resp. za okraj plochy, sa ignoruje (Willy stojí na mieste)

  • šípka na políčko s presúvaním (jedno z '>', 'v', '<', '^') spôsobí automatický presun na ďalšie políčko daným smerom, ak je týmto smerom opäť políčko s presúvaním, znovu sa to opakuje; ak je týmto smerom stena alebo okraj plochy, hráč zastane na tomto políčku; ak sa na niektorých z týchto políčok nachádzali mince, tie sa počas pohybu zdvihnú.

Riešenie zapíš do triedy ManicMiner s týmito metódami:

class ManicMiner:
    def __init__(self, meno_suboru):
        ...

    def __str__(self):
        return ''

    def sipky(self, postupnost):
        return 0, 0

    def pocet_minci(self):
        return 0

kde

  • konštruktor __init__(meno_suboru) prečíta hraciu plochu aj s pozíciami hráča a zlatých mincí

  • metóda __str__() vráti znakový reťazec, ktorý reprezentuje momentálny stav plochy aj s pozíciou hráča (znak '+'); s pozíciami všetkých mincí (znak 'o')

  • metóda sipky(postupnost) kde parameter postupnost je znakový reťazec s postupnosťou stláčaných šípok (znaky 'L', 'R', 'U', 'D' a znakov číslic) – hráč sa bude v ploche pohybovať podľa týchto zadaných príkazov; ak sa daným smerom nemôže pohnúť (okraj plochy, stena), tento konkrétny príkaz sa ignoruje, ak prechádza cez políčko s presúvaním, tak zrealizuje automatický pohyb; ak je v postupnosti šípok (aj viacciferné) číslo, označuje to, že nasledovná šípka sa vykoná príslušný počet krát (napríklad, '4R' označuje 'RRRR'); metóda vracia dvojicu čísel: (počet prejdených krokov, počet zdvihnutých mincí); každé volanie tejto metódy vráti len tie počty krokov a mincí, ktoré sa prešli a pozbierali počas tohto volania

  • metóda pocet_minci() vráti momentálny počet mincí, ktoré ešte ostali v hracej ploche.

Napríklad, pre súbor1.txt:

XXXXXXX
XXX.XXX
X.....X
XXX.XXX
XXXXXXX
2 3
2 5
1 3
3 3
2 1

takýto test:

if __name__ == '__main__':
    mm = ManicMiner('subor1.txt')
    print(mm)
    print(mm.sipky('UDRR'))
    print(mm.sipky('LLDULL'))
    print(mm.sipky('LLUUDD'))
    print(mm)

vypíše:

XXXXXXX
XXXoXXX
Xo.+.oX
XXXoXXX
XXXXXXX
(4, 2)
(6, 2)
(0, 0)
XXXXXXX
XXX.XXX
X+....X
XXX.XXX
XXXXXXX

Alebo pre súbor2.txt:

....>>>>v
........v
.....<<<v
0 0
0 5

takýto test:

if __name__ == '__main__':
    mm = ManicMiner('subor2.txt')
    print(mm)
    print('pocet minci =', mm.pocet_minci())
    print(mm.sipky('10R'))
    print(mm)
    print(mm.sipky('1LR'))
    print(mm)
    print('pocet minci =', mm.pocet_minci())

vypíše:

+...>o>>v
........v
.....<<<v
pocet minci = 1
(10, 1)
....>>>>v
........v
.....<<<+
(6, 0)
....>>>>v
........v
....+<<<v
pocet minci = 0

Z úlohového servera L.I.S.T. si stiahni kostru programu skuska.py. Pozri si testovacie dáta v súboroch 'subor1.txt', 'subor2.txt', …, ktoré bude používať aj testovač.

Aby si mohol spúšťať skúškové testy, program ulož do súboru skuska.py. Riešenie (bez dátových súborov) odovzdaj na úlohový server https://list.fmph.uniba.sk/. Tvoj odovzdaný program musí začínať tromi riadkami komentárov:

# 4. skuska: Manic Miner
# autor: Janko Hraško
# datum: 1.2.2024