Használható segédanyagok: Haskell könyvtárainak dokumentációja, (lokális!) Hoogle, a tárgy honlapja és a BE-AD rendszerbe feltöltött beadandók. Ha bármilyen kérdés, észrevétel felmerül, azt a felügyelőknek kell jelezni, nem a diáktársaknak!
A feladatok egymásra épülnek ezért érdemes ezeket a megadásuk sorrendjében megoldani, de legalább megérteni az aktuális feladatot megelőző feladatokat! A függvények definíciójában lehet, sőt javasolt is alkalmazni a korábban definiált függvényeket (függetlenül attól, hogy sikerült-e azokat megadni).
Tekintve, hogy a tesztesetek, bár odafigyelés mellett íródnak, nem fedik le minden esetben a függvény teljes működését, határozottan javasolt még külön próbálgatni a megoldásokat beadás előtt, vagy megkérdezni a felügyelőket!
Részpontszámokat csak az elégséges szint elérése után lehet kapni!
A feladatban egy autonóm marsjáró útvonalkereső algoritmusát fogjuk elkészíteni.
A Mars feltérképezett területét egy négyzetrácsnak (Map
) képzeljük el, sorokra és oszlopokra felbontva. Egy-egy koordinátát (Coordinate
) sor-oszlop párral ábrázolunk, ahol a sorszámozás nullától indul. A (0,0)
koordináta a bal felső sarkot jelöli, az oszlopszámok jobbra nőnek, a sorszámok lefelé.
A Mars felszínét szektorokra (Sector
) osztjuk. A felszín egy szektorát egy rendezett pár alkotja, mely megadja a szektor pozícióját és hogy járható-e (Passable
) vagy sem (True
, ha járható, egyébként False
).
A feltérképezett terület oldalai azonos hosszúságúak. A feltérképezett területet az oldalhosszával és a szektorok listájával adjuk meg.
Hozzunk létre egy n × n méretű üres térképet, melyen nincs egyetlen egy akadály sem, minden szektor járható!
Ha a méret nem pozitív, adjunk hibaüzenetet az error
függvénnyel (lásd példák)! A paramétert a show
függvénnyel lehet szöveggé alakítani.
Cseréljünk ki egy megadott kulcshoz tartozó értéket egy kulcs-érték párokból álló listában! Mindig a kulcs első előfordulásához rendelt értéket cseréljük, ha a kulcs többször is előfordulna a listában.
Adjuk meg azt a műveletet, mellyel az egyes szektorokat járhatatlannak minősíthetjük a radar által begyűjtött információk alapján!
Segítség: a térkép frissítéséhez használhatjuk az előbbi replaceElem
függvényt.
Vezessük be az alábbi három teszt térképet!
Soroljuk fel egy koordináta négy szomszédját északról kezdve, óramutató járásával ellentétes irányban!
Megjegyzés: itt még nem foglalkozunk a koordináták helyességével, azaz szerepelhetnek negatív sorok vagy oszlopok.
Döntsük el, hogy egy adott koordináta feltérképezett-e vagy sem, azaz a térképen van-e!
Döntsük el, hogy a térkép egy adott koordinátáján áthaladhatunk-e, azaz nincs ott akadály! Feltehetjük, hogy a vizsgált koordináta megtalálható a térképen.
Döntsük el, hogy egy pozíció legálisnak minősül-e! Ezt akkor állíthatjuk, ha léphet-e oda a marsjáró, azaz a pozíció rajta van a térképen és nincs ott akadály.
Gyűjtsük össze egy listába azokat a koordinátákat, ahová a marsjáró az adott pozícióról léphet! Használjuk a korábban definiált műveleteket!
A továbbiakban azzal foglalkozunk, hogy útvonalat keressünk egy adott koordinátából egy másikba. Az útvonalakra bevezetjük a Path
típust, mely jelöli, hogy a marsjáró mely szektorokon menne végig.
Az útvonalakban a koordinátákat fordított sorrendben tároljuk. Tehát a kiindulási pont a lista utolsó eleme, és ha végig szeretnénk haladni az útvonalon, akkor a listát a végéről előre haladva kell bejárni.
Az ábrákon egy ‘X’ jelöli azt a koordinátát ahova eljutottunk az útvonalat követve.
Vezessük be azt a műveletet, amely tervezett koordinátára landoltatja a marsjárót! Ha a koordináta nem járható, akkor adjunk hibaüzenetet az error
függvénnyel (lásd példák)!
Egészítsünk ki egy útvonalat egy új lépéssel! Próbáljuk ki az összes lehetséges irányt (neighbourFreeSectors
)! Ne lépjünk újra olyan koordinátára, ahol korábban már jártunk, azaz szerepel az útvonalban!
Ha az útvonal nem folytatható egyik irányban sem, akkor adjunk vissza üres listát!
Döntsük el, hogy az útvonal követésével elérnénk-e a célunkat, azaz az útvonal első pozíciója megegyezik-e a céllal!
Keressük meg a térképen az összes lehetséges útvonalat, mely elvezet a célba! A breadthFirst
első paramétere a térkép, mely jelöli a járható szektorokat. A második paramétere a cél, ahova legvégül szeretnénk eljutni. A harmadik paramétere útvonalak listája, melyek a landolási koordinátából indulnak. Az egyes útvonalak legelső koordinátája az a koordináta, ahol éppen áll a marsjáró. Az eredmény azok az útvonalak lesznek, melyekben az első koordináta a céllal egyezik meg.
A breadthFirst
működési elve a következő:
Ha az útvonalak listája üres, akkor elakadtunk, nincs útvonal a célba. Adjunk vissza egy üres listát!
Ha az útvonalak listája nem üres, akkor két lehetőség áll előttünk, attól függően, hogy elértük-e a célunkat:
Ha az első útvonalon már elértünk a célba (reached
), akkor tegyük be ezt az útvonalat a végeredmény listába, és keressünk további célba vezető útvonalakat a maradék útvonalak közül a breadthFirst
-tel.
Különben az első útvonalat ki kell egészíteni egy lépéssel (step
). Ha több irányban indulhatunk el, akkor mindegyik irányt kipróbáljuk. Fűzzük be a legelső útvonal összes lehetséges folytatását az útvonalak listájának végére, és keressünk célba vezető útvonalakat a breadthFirst
-tel!
Keressük meg az egyik legrövidebb utat a célhoz egy adott kiindulási pontból! A shortestPath
második paramétere a cél, a harmadik paramétere a landolási hely.
Megjegyzés: használjuk ki, hogy a szélességi bejárásnál az első útvonal az egyik legrövidebb lesz!