Autorské riešenie
Kým sa pustíme do programovania, pozrime sa poriadne na to, čo o riešenom probléme vieme. Pestujeme riasy, ktoré sú v boxoch. Boxy sú usporiadané do obdĺžnikovej oblasti. Nejakú časť boxov ráno zalejeme:
Voda z boxov sa odparuje:
Na začiatku poznáme stav vody v boxoch a plán zalievania. Úlohou je zistiť, aký bude stav po poslednom zaliatí a následnom odparení vody. Poznáme štruktúru dát, ktoré popisujú stav vody v boxoch aj štruktúru dát, ktoré popisujú plán zalievania. Celú simuláciu zmien stavu by sme mohli rozdeliť na nasledovné kroky: postupne vyberaj inštrukcie na zalievanie
Pre realizáciu jednotlivých častí si môžeme vytvoriť samostatné funkcie. Výsledný program môže vyzerať nasledovne: #riasy1.py def zalej_riadok(riadok, stav): pocet_stlpcov = len(stav[0]) for stlpec in range(pocet_stlpcov): if stav[riadok][stlpec] > 0: stav[riadok][stlpec] = min(stav[riadok][stlpec] + 1, 5) def zalej_stlpec(stlpec, stav): pocet_riadkov = len(stav) for riadok in range(pocet_riadkov): if stav[riadok][stlpec] > 0: stav[riadok][stlpec] = min(stav[riadok][stlpec] + 1, 5) def zalej_oblast(start_riadok, start_stlpec, pocet_riadkov, pocet_stlpcov, stav): for riadok in range(start_riadok, start_riadok + pocet_riadkov): for stlpec in range(start_stlpec, start_stlpec + pocet_stlpcov): if stav[riadok][stlpec] > 0: stav[riadok][stlpec] = min(stav[riadok][stlpec] + 1, 5) def odpar_vodu(stav): pocet_riadkov = len(stav) pocet_stlpcov = len(stav[0]) for riadok in range(pocet_riadkov): for stlpec in range(pocet_stlpcov): stav[riadok][stlpec] = max(stav[riadok][stlpec] - 1, 0) def simuluj_pestovanie(stav, plan): for zaznam in plan: if zaznam: if zaznam[0] == 'riadok': zalej_riadok(zaznam[1], stav) elif zaznam[0] == 'stlpec': zalej_stlpec(zaznam[1], stav) else: zalej_oblast(zaznam[0], zaznam[1], zaznam[2], zaznam[3], stav) odpar_vodu(stav) Všimnime si niektoré časti riešenia:
Máme síce funkčné riešenie, ale možno stojí za to zamyslieť sa, či ho vieme nejako vylepšiť. Ak sa pozrieme na funkcie pre zalievanie, tak zistíme, že robia to isté, i keď každá na inej časti farmy. Riadok môžeme chápať ako obdĺžnikovú oblasť, ktorá má len jeden riadok. Podobne aj na stĺpec sa môžeme pozrieť ako na obdĺžnikovú oblasť len s jedným stĺpcom. Mala by nám teda stačiť len jedna funkcia: zalej_oblast. Pozrime sa na riešenie, v ktorom riadky aj stĺpce chápeme ako oblasti: #riasy2.py def zalej_oblast(start_riadok, start_stlpec, pocet_riadkov, pocet_stlpcov, stav): for riadok in range(start_riadok, start_riadok + pocet_riadkov): for stlpec in range(start_stlpec, start_stlpec + pocet_stlpcov): if stav[riadok][stlpec] > 0: stav[riadok][stlpec] = min(stav[riadok][stlpec] + 1, 5) def odpar_vodu(stav): pocet_riadkov = len(stav) pocet_stlpcov = len(stav[0]) for riadok in range(pocet_riadkov): for stlpec in range(pocet_stlpcov): stav[riadok][stlpec] = max(stav[riadok][stlpec] - 1, 0) def simuluj_pestovanie(stav, plan): pocet_riadkov = len(stav) pocet_stlpcov = len(stav[0]) for zaznam in plan: if zaznam: if zaznam[0] == 'riadok': zalej_oblast(zaznam[1], 0, 1, pocet_stlpcov, stav) elif zaznam[0] == 'stlpec': zalej_oblast(0, zaznam[1], pocet_riadkov, 1, stav) else: zalej_oblast(zaznam[0], zaznam[1], zaznam[2], zaznam[3], stav) odpar_vodu(stav) Funkcie zalej_riadok a zalej_stlpec už nepotrebujeme. Nahradili sme ich funkciou zalej_oblast, ktorá je univerzálnejšia. Vo funkcii simuluj_pestovanie však riadky a stĺpce musíme vyjadriť ako oblasti. Riadok vyjadríme ako oblasť s jedným riadkom a všetkými stĺpcami a stĺpec ako oblasť s jedným stĺpcom a všetkými riadkami. Pokračujme v našej snahe o vylepšenie programu ďalej. Ak sa pozrieme na funkcie zalej_oblast a odpar_vodu tak vidíme, že robia podobné veci. Jedna vo vybranej oblasti pridáva vodu (+1) a druhá odoberá vodu (-1). Vytvorme jednu univerzálnu funkciu, ktorá podľa hodnoty parametra vodu pridá alebo uberie. #riasy3.py def zmen_oblast(start_riadok, start_stlpec, pocet_riadkov, pocet_stlpcov, zmena, stav): for riadok in range(start_riadok, start_riadok + pocet_riadkov): for stlpec in range(start_stlpec, start_stlpec + pocet_stlpcov): if stav[riadok][stlpec] > 0: if zmena == 1: stav[riadok][stlpec] = min(stav[riadok][stlpec] + 1, 5) else: stav[riadok][stlpec] = max(stav[riadok][stlpec] - 1, 0) def simuluj_pestovanie(stav, plan): pocet_riadkov = len(stav) pocet_stlpcov = len(stav[0]) for zaznam in plan: if zaznam: if zaznam[0] == 'riadok': zmen_oblast(zaznam[1], 0, 1, pocet_stlpcov, 1, stav) elif zaznam[0] == 'stlpec': zmen_oblast(0, zaznam[1], pocet_riadkov, 1, 1, stav) else: zmen_oblast(zaznam[0], zaznam[1], zaznam[2], zaznam[3], 1, stav) zmen_oblast(0, 0, pocet_riadkov, pocet_stlpcov, -1, stav) Ukázali sme si tri riešenia toho istého problému. Dekompozíciu, ktorú sme spravili na začiatku, sme však do zodpovedajúcich funkcií v jednotlivých riešeniach premietli rôzne. Rôzne, i keď v niečom podobné činnosti, sme najskôr implementovali ako samostatné funkcie. Neskôr sme ich zlúčili do univerzálnejších funkcií, ktorých správanie sme ovplyvnili hodnotami parametrov. Vaše zaujímavé riešenia a najčastejšie chyby S touto úlohou ste si poradili celkom dobre. Aj keď ide o komplexný problém, ktorý sa dá pomerne dobre rozdeliť na niekoľko menších problémov a ich riešenie implementovať do samostatných funkcií, väčšina z vás tak neurobila. Celé riešenie bolo často ímplementované v jednej rozsiahlej funkcii. Takýto prístup zneprehľadňuje samotné riešenie a nepomáha v prípada hľadania chyby alebo testovania kódu. Niekoľko týmov si neuvedomilo dôsledky nulového stavu vody v boxoch. Ak takýto stav nastane, box sa už nezalieva a ani vod sa z neho neodparuje. |
||||||||||
© Univerzita Pavla Jozefa Šafárika v Košiciach, Prírodovedecká fakulta, Ústav informatiky palmaj (zavinac) upjs.sk |