Examining Items #2

Goals

  1. spájanie zoznamov
  2. ďalšie výhody využitia príkazu for-else

Content

  1. Za domácu úlohu ste mali rozšíriť príkaz preskumaj o možnosť opísať nie len predmet, ktorý sa nachádza v inventári, ale aj v miestnosti. Prejdeme si možné riešenia spolu.

    Najjednoduchšie riešenie spočíva v tom, že skopírujem fragment realizujúci opis predmetu v batohu a zmením len zoznam predmetov, ktorý je v tomto prípade inventárom na zoznam predmetov v aktuálnej miestnosti:

    for item in inventory:
       if item["name"] == cmd[1]:
          print(item["description"])
          break
    else:
       print("Taký predmet tu nikde nevidím.")
    
    for item in world[location]["items"]:
       if item["name"] == cmd[1]:
          print(item["description"])
          break
    else:
       print("Taký predmet tu nikde nevidím.")
    

    Ak však tento fragment spustíme, problém, s ktorým tu budeme zápasiť je viacnásobný výpis textu:

    Taký predmet tu nikde nevidím.
    

    Text sa vypíše vtedy, ak sa predmet:

    • nachádza v batohu, ale nenachádza sa v miestnosti,
    • nachádza v miestnosti, ale nenachádza sa v batohu, alebo
    • nenachádza ani v batohu ani v miestnosti (v tomto prípade sa vypíše 2x).

    Za tento problém môže to, že oba cykly sa spustia vždy. A teda v prípade, že sa predmet nenájde v batohu, uvedená správa sa vypíše. A podobne, ak sa predmet nenájde v miestnosti, opäť sa vypíše.

    Aby sme tomu predišli, vytvoríme si pomocnú premennú found_in_inventory, ktorá bude fungovať ako príznak toho, či sme predmet v inventári našli alebo nie. Nastavíme ju na počiatočnú hodnotu False a na hodnotu True ju nastavíme vtedy, keď predmet nájdeme v inventári. Následne druhý cyklus spustíme len vtedy, ak sme predmet v inventári nenašli (a teda hodnota premennej found_in_inventory je False):

    found_in_inventory = False
    for item in inventory:
       if item["name"] == cmd[1]:
          print(item["description"])
          found_in_inventory = True
          break
    else:
       print("Taký predmet tu nikde nevidím.")
    
    if found_in_inventory == False:
       for item in world[location]["items"]:
          if item["name"] == cmd[1]:
             print(item["description"])
             break
       else:
          print("Taký predmet tu nikde nevidím.")
    

    Ak však spustíme aktuálnu úpravu, všetko bude fungovať len v prípade, ak predmet nájdeme v inventári (nevypíše sa žiadna ďalšia správa). Ak však predmet v inventári nenájdeme, sme na tom rovnako. Problémom je v tomto prípade časť else v prvom cykle, ktorá sa spustí zakaždým, keď predmet nenájdeme v inventári a teda správu o neúspechu zobrazí. Riešením bude odstránenie tejto časti. Upravený kód bude vyzerať nasledovne:

    found_in_inventory = False
    for item in inventory:
       if item["name"] == cmd[1]:
          print(item["description"])
          found_in_inventory = True
          break
    
    if found_in_inventory == False:
       for item in world[location]["items"]:
          if item["name"] == cmd[1]:
             print(item["description"])
             break
       else:
          print("Taký predmet tu nikde nevidím.")
    

    Tentokrát už kód bude fungovať ako má. Takéto riešenie je celkom časté pre jazyky založené na jazyku C (ako Java, C# a podobne). S využitím vlastností, ktoré ponúka jazyk Python však tento kód môžeme ešte ďalej upravovať a teda aj zjednodušovať. Využiť na to môžeme práve cyklus for-else a časť else, do ktorej presuniemie celé prehľadávanie v zozname predmetov v miestnosti. Nepotrebujeme teda žiadnu premennú navyše.

    for item in inventory:
       if item["name"] == cmd[1]:
          print(item["description"])
          break
    else:
       for item in world[location]["items"]:
          if item["name"] == cmd[1]:
             print(item["description"])
             break
       else:
          print("Taký predmet tu nikde nevidím.")
    

    Okrem toho môžeme využiť ďalšiu vlastnosť, ktoru je spájanie zoznamo dokopy. To si môžeme ilustrovať na nasledovnom fragmente:

    l1 = ['jano', 'fero', 'jozo']
    l2 = [1, 2, 3, 4]
    l1 + l2
    ['jano', 'fero', 'jozo', 1, 2, 3, 4]
    

    Vďaka tejto vlastnosti môžeme našu aktuálnu implementáciu upraviť naozaj elegantne a vo výsledku nebudeme mať počet riadkov nijak väčší ako ten, ktorý sme už mali na začiatku:

    for item in inventory + world[location]["items"]:
       if item["name"] == cmd[1]:
          print(item["description"])
          break
    else:
       print("Taký predmet tu nikde nevidím.")
    
  2. Upravte implementáciu tak, že fragment kódu, ktorý definuje správanie príkazu preskumaj osamostatníte do samostatnej funkcie s názvom examine_item().

    Najprv identifikujme parametre, ktoré táto funkcia potrebuje:

    • room - miestnosť, v ktorej chceme preskúmavať príkazy (vždy aktuálna)
    • inventory - hráčov inventár
    • line - príkazový riadok, z ktorého vystrihneme názov predmetu, ktorý chce hráč preskúmať alebo nič, ak hráč zadal len samotný príkaz preskumaj

    Následne vytvoríme samostatnú funkciu, prekopírujeme do nej príslušný kód a jemne ho refaktorujeme:

    def examine_item(room, inventory, line):
       cmd = line.split(maxsplit=1)
       if len(cmd) == 1:
          print("Ta ja neznám čo chceš skúmať.")
       else:
          for item in inventory + room["items"]:
             if item['name'] == cmd[1]:
                print(item['description'])
                break
          else:
             print("Taký predmet tu nikde nevidím.")
    

    A túto funkciu zavoláme z hlavnej slučky, keď rozpoznáme, že sa jedná o príkaz preskumaj:

    elif line.startswith("preskumaj"):
       examine_item(world[location], inventory, line)
    

Homework

Počas sviatkov sa zaregistrujte na portáli www.codewars.com a vyriešte niekoľko kata v jazyku Python.

results matching ""

    No results matching ""