Szókereső

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 feladat összefoglaló leírása

Ebben a feladatban egy szókereső programot kell megvalósítani, ahol megadott szavakról kell eldönteni, hogy megtalálhatóak egy adott táblán. A táblák négyzetesek (azaz azonos sora és oszlopa van), de mérete nem rögzített. A megoldás során a lehető legáltalánosabb megoldásra kell törekedni. Minden tábla csupa nagybetűből áll!

A táblákat itt most a következő típussal fogjuk ábrázolni:

type Table = [[Char]]

valamint a továbbiakban az alábbi, ilyen típusú konstansokat fogjuk alkalmazni a tesztek során:

table :: Table
table = [['T','L','O']
        ,['Á','T','J']
        ,['T','A','D']
        ]
table2 :: Table
table2 = [['O','S','B','Z']
         ,['L','Z','Á','Á']
         ,['D','L','L','M']
         ,['A','Y','O','G']
         ]

Egy betű előfordulásai a táblán (2 pont)

Készítsünk egy olyan függvényt, amely megkeresi, hogy a táblán milyen pozíciókon található meg egy adott betű! Az eredményt pozíciók egy listájaként adja vissza. A pozíciókat a következő típussal definiáljuk:

type Position = (Int, Int)

így tehát lényegében egész számok párjaként egy kétdimenziós koordinátát adunk vissza. A táblában ezeket a koordinátákat a bal felső saroktól, nullától kezdődően számozzuk.

Megjegyzések.

letterPosition :: Table -> Char -> [Position]

Test>
[] :: [Position]
Test>
[(2, 1)] :: [Position]
Test>
[(0, 0), (1, 1), (2, 0)] :: [Position]
Test>
[(1, 2), (1, 3)] :: [Position]

Egy betű a táblán van-e? (1 pont)

Írjunk egy függvényt, amely eldönti, hogy egy betű a táblán megtalálható-e!

isLetterOnTable :: Table -> Char -> Bool

Test>
False :: Bool
Test>
True :: Bool
Test>
True :: Bool
Test>
True :: Bool

Egy szó betűinek előfordulásai a táblán (1 pont)

Adjunk meg egy függvényt, amely összegyűjti egy szó betűinek lehetséges előfordulásait a táblán!

wordPosition :: Table -> String -> [[Position]]

Test>
[[(0, 1)], [(0, 2)], [(0, 1)]] :: [[Position]]
Test>
[[], [(0, 2)], [], [(2, 1)], [(0, 0), (1, 1), (2, 0)]] :: [[Position]]
Test>
[[], [], [], []] :: [[Position]]
Test>
[[(0, 1)], [(0, 3), (1, 1)], [(1, 2), (1, 3)], [(2, 3)], [(1, 0), (2, 1), (2, 2)], [(1, 2), (1, 3)], [(0, 3), (1, 1)]] :: [[Position]]
Test>
[[(0, 1)], [(0, 3), (1, 1)], [(3, 0)], [(3, 3)], [(0, 0), (3, 2)], [(1, 0), (2, 1), (2, 2)]] :: [[Position]]

Egy szó minden betűje megtalálható a táblán? (1 pont)

Készítsünk egy függvényt, amellyel eldönthető, hogy egy adott szó összes betűje megtalálható a táblán!

isWordOnTable :: Table -> String -> Bool

Test>
True :: Bool
Test>
False :: Bool
Test>
False :: Bool
Test>
True :: Bool
Test>
True :: Bool

Irányok kiszámítása (1 pont)

Annak eldöntéséhez, hogy a táblán levő betűkből kirakható egy szó, meg kell néznünk, hogy a benne egymás után szereplő betűk a táblán egymáshoz képest miként helyezkednek el.

Ehhez definiáljuk az alábbi típust:

type Direction = Int

Az egy ábrázolható irányok hasonlóak a numerikus billentyűzeten található irányokhoz. Így 1 a balra átlósan le, 2 a le, 3 a jobb átlósan le, 4 a bal, és így tovább. Helybe nem maradhatunk, így oda a -1, vagyis érvénytelen érték kerül.

Mindezeket az alábbi konstans foglalja össze:

directions :: [[Direction]]
directions = [[7, 8,9]
             ,[4,-1,6]
             ,[1, 2,3]
             ]

Az irányokat mindig az éppen aktuális helyhez képest értelmezzük. Például, a "tat" szót akarjuk kirakni és a (2,0) (bal alsó sarok) pozícióból indítjuk a szót. Ekkor először a (2,0) pozícióhoz képest jobbra, majd a (2,1) pozícióhoz képest fel, vagyis a 6 majd a 8 irányokba kell menni.

Így a függvény első paramétere az aktuális hely, a második pedig az a hely ahova lépni szeretnénk. Ha olyan lépést hajtanánk végre, amely nem szomszédos mezőre vinne vagy maradna egyhelyben, akkor adjunk vissza a -1 értéket!

direction :: Position -> Position -> Direction

Test>
6 :: Direction
Test>
8 :: Direction
Test>
2 :: Direction
Test>
-1 :: Direction
Test>
-1 :: Direction
Test>
8 :: Direction
Test>
8 :: Direction

Pozíciók átalakítása útvonallá (2 pont)

Készítsünk egy függvényt, amely a betűkhöz tartozó kétdimenziós koordináták sorozatát irányok sorozatává alakítja!

Ehhez létrehozzuk a következő típust:

type Route = [Direction]

A függvénynek viszont csak abban az esetben kell ürestől különböző listát visszaadnia, ha az egymásra következő koordináták a direction függvény szerint szabályosan következnek egymásra! Ha ez bármelyik pontban nem teljesülne a sorozatban, akkor az eredmény legyen üres.

toRoute :: [Position] -> Route

Test>
[] :: Route
Test>
[] :: Route
Test>
[6, 6] :: Route
Test>
[6, 6, 2, 2, 4, 4, 8] :: Route
Test>
[] :: Route

Eltér a lista mindegyik eleme egymástól? (1 pont)

Definiáljunk egy függvényt, amely akkor ad igazat, ha a paraméterül kapott lista minden egyes eleme különböző! Üres lista esetén ez automatikusan teljesül.

isAllDifferent :: (Eq a) => [a] -> Bool

Test>
True :: Bool
Test>
False :: Bool
Test>
False :: Bool
Test>
True :: Bool

Megjegyzés. Ez később a possibleRoutes függvénynél felhasználható.

Listák listáinak bővítése egy elemmel (1 pont)

Készítsünk egy olyan függvényt, amely egy adott elemet listák listájában minden lista végére teszi!

addToAllLists :: [[a]] -> a -> [[a]]

Test>
[] :: [[Integer]]
Test>
["foox", "barx", "bazx"] :: [[Char]]

Megjegyzés. Ez később a combinations függvény megadásához felhasználható.

Elemek kombinációinak előállítása (3 pont)

Írjunk egy függvényt, amely egy listában megadott értékek listájából meghatározza azokat a listákat, amelyeket úgy nyerünk, hogy minden listából mindig kiválasztunk egy-egy értéket!

Egy példán keresztül így lehet bemutatni az elvárt működést. Adottak az alábbi értékek:

1   1   1
2   2   2
3   3   3

amelyeket a [[1,2,3],[1,2,3],[1,2,3]] listával ábrázoltunk. Ekkor a lehetséges kombinációk (egy része) a következők:

[1][1][1]  [1] 1 [1]  [1] 1 [1]  [1][1] 1   [1] 1  1    [1] 1  1
 2  2  2    2 [2] 2    2  2  2    2  2 [2]   2 [2][2]    2  2 [2]
 3  3  3    3  3  3    3 [3] 3    3  3  3    3  3  3     3 [3] 2

 1 [1][1]   1  1 [1]   1  1 [1]   1 [1] 1    1  1  1     1  1  1
[2] 2  2   [2][2] 2   [2] 2  2   [2] 2 [2]  [2][2][2]   [2] 2 [2]
 3  3  3    3  3  3    3 [3] 3    3  3  3    3  3  3     3 [3] 3

 1 [1][1]   1  1 [1]   1  1 [1]   1 [1] 1    1  1  1     1  1  1
 2  2  2    2 [2] 2    2  2  2    2  2 [2]   2 [2][2]    2  2 [2]
[3] 3  3   [3] 3  3   [3][3] 3   [3] 3  3   [3] 3  3    [3][3] 3

és így tovább.

combinations :: [[a]] -> [[a]]

Test>
[[]] :: [[()]]
Test>
[[1]] :: [[Integer]]
Test>
[[1, 2, 3]] :: [[Integer]]
Test>
[[1, 3, 5, 7], [2, 3, 5, 7], [1, 4, 5, 7], [2, 4, 5, 7], [1, 3, 6, 7], [2, 3, 6, 7], [1, 4, 6, 7], [2, 4, 6, 7], [1, 3, 5, 8], [2, 3, 5, 8], [1, 4, 5, 8], [2, 4, 5, 8], [1, 3, 6, 8], [2, 3, 6, 8], [1, 4, 6, 8], [2, 4, 6, 8]] :: [[Integer]]
Test>
[[1, 1, 1], [2, 1, 1], [3, 1, 1], [1, 2, 1], [2, 2, 1], [3, 2, 1], [1, 3, 1], [2, 3, 1], [3, 3, 1], [1, 1, 2], [2, 1, 2], [3, 1, 2], [1, 2, 2], [2, 2, 2], [3, 2, 2], [1, 3, 2], [2, 3, 2], [3, 3, 2], [1, 1, 3], [2, 1, 3], [3, 1, 3], [1, 2, 3], [2, 2, 3], [3, 2, 3], [1, 3, 3], [2, 3, 3], [3, 3, 3]] :: [[Integer]]
Test>
["dbnp", "ubnp", "cbnp", "kbnp", "dunp", "uunp", "cunp", "kunp", "dmnp", "umnp", "cmnp", "kmnp", "dpnp", "upnp", "cpnp", "kpnp", "dbup", "ubup", "cbup", "kbup", "duup", "uuup", "cuup", "kuup", "dmup", "umup", "cmup", "kmup", "dpup", "upup", "cpup", "kpup" ++ [……], "dbl" ++ […, ……], "ub" ++ […, ……], "c" ++ […, ……], …, ……] :: [[Char]]

A pozíciók sorozatából összeállítható útvonalak (2 pont)

Definiáljunk egy olyan függvényt, amellyel a tábla kétdimenziós (sorozatként megadott) koordinátái között tudjuk megkeresni a lehetséges utakat! Az utak szerkesztése során ügyeljünk arra, hogy ugyanazon a pozíción kétszer nem haladhatunk át!

possibleRoutes :: [[Position]] -> [Route]

Test>
[] :: [Route]
Test>
[[8], [6], [2]] :: [Route]
Test>
[[1, 7], [1, 1]] :: [Route]
Test>
[[6, 8], [2, 4]] :: [Route]
Test>
[] :: [Route]
Test>
[[4, 2, 2, 4]] :: [Route]
Test>
[] :: [Route]
Test>
[[2, 6, 1, 7], [2, 6, 2, 4], [2, 6, 1, 6]] :: [Route]

Rajta van-e a táblán a szó? (2 pont)

Készítsünk egy függvényt, amely eldönti egy tábla és egy szó viszonylatában, hogy az adott szó szerepel a táblán és ha igen, akkor szerkeszthető-e hozzá a possibleRoutes függvény szabályai szerint útvonal!

has :: Table -> String -> Bool

Test>
True :: Bool
Test>
False :: Bool
Test>
True :: Bool
Test>
True :: Bool
Test>
False :: Bool
Test>
True :: Bool
Test>
False :: Bool
Test>
True :: Bool

A szavak pontozása (1 pont)

Adjunk meg egy függvényt, amely kiszámítja az adott szóért adható pontot! Csak olyan szavakért kaphatunk pontot, amely szerepel a táblán és tartozik hozzá szabályos útvonal. Ekkor az alábbi képlettel határozható meg az értéke:

WordFindere262eaee7e8b8db2cb4b2e1d0bbc30af.png

ahol w a w szó hossza.

wordScore :: Table -> String -> Int

Test>
2 :: Int
Test>
0 :: Int
Test>
5 :: Int
Test>
5 :: Int
Test>
0 :: Int
Test>
5 :: Int
Test>
5 :: Int

Pontozás