Dominójáték

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

A feladatban egy dominójátékot fogunk megvalósítani, melyben dominó sorozatokat kell alkotni. Ezen sorozatokat egy megadott dominó lapkákból fogjuk képezni.

Ezeket a dominóláncokat az alábbi egyszerűsített szabályok mentén fogjuk megadni:

A dominólapkákat egy rendezett pár fogja reprezentálni, amelyek a későbbekben tetszőlegesen forgathatóak lesznek.

type Domino = (Int, Int)

A dominósorozatokat lapkák sorozataként adjuk meg.

type DominoSequence = [Domino]

(A type kulcsszó segítségével a Domino típus az (Int, Int) típus egy másik neve lesz, illetve a DominoSequence típus a Domino típusból alkotott listákat/sorozatokat fogja jelenteni, hasonlóan a String és [Char] viszonyához. A programban ez semmilyen további megszorítást nem indukál, csupán a beszédesebb függvénytípusok kialakításában segít.)

Dominólapkák előállítása (1 pont)

Adjuk meg azt a függvényt, amely tetszőlegesen megadott n értékre előállítja a dominólapkákat! A függvény definiálása során ügyeljünk arra, hogy az ismétléseket elkerüljük. A lapkák tetszőlegesen forgathatóak, azért az (1,0) ne szerepeljen, mert ez a (0,1) elforgatása.

dominoes :: Int -> [Domino]

Test>
[(0, 0), (0, 1), (0, 2), (1, 1), (1, 2), (2, 2)] :: [Domino]
Test>
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)] :: [Domino]
Test>
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (3, 3), (3, 4), (3, 5), (3, 6), (4, 4), (4, 5), (4, 6), (5, 5), (5, 6), (6, 6)] :: [Domino]

Lapka forgatása (1 pont)

Adjuk meg azt a függvényt, amely egy dominólapkát megfordít!

flipDomino :: Domino -> Domino

Test>
(1, 0) :: Domino
Test>
(1, 3) :: Domino

Lapkák illeszthetősége (1 pont)

Definiáljuk azt a függvényt, amely megadja, hogy egy lapka illeszthető-e egy másikhoz!

matches :: Domino -> Domino -> Bool

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

Lapkák keresése (2 pont)

Adjuk meg azt a függvényt, amely a megadott halmazból kiválogatja azokat a lapkákat, amelyeknek valamelyik oldala megegyezik a keresett számmal!

getDominoesWithSide :: Int -> [Domino] -> [Domino]

Test>
[] :: [Domino]
Test>
[(0, 3), (1, 3), (2, 3), (3, 3)] :: [Domino]
Test>
[(0, 5), (1, 5), (2, 5), (3, 5), (4, 5), (5, 5), (5, 6)] :: [Domino]

Sorozat ellenőrzése (2 pont)

Döntsük el, hogy a sorozatban megadott lapkák megfelelően vannak-e megadva!

isValidDominoSequence :: [Domino] -> Bool

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

Sorozat konvertálása (1 pont)

Ellenőrizzük, hogy a paraméterül kapott dominóhalmaz megfelel-e a dominó sorozat feltételeinek!

Megjegyzés: Hiba esetén használjuk az error függvényt!

fromDominoes :: [Domino] -> DominoSequence

Test>
[] :: DominoSequence
Test>
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 1)] :: DominoSequence
Test>
⊥₁ :: DominoSequence
⊥₁: Invalid domino sequence
CallStack (from HasCallStack):
  error, called at ./Dominoes.lhs:143:34 in main:Dominoes

Sorozat végződése (1 pont)

Adjuk meg azt a függvényt, amely egy dominósorozatból megadja, hogy milyen számmal rendelkező lapkákkal lehetséges azt folytatni!

dominoSequenceEndsWith :: DominoSequence {-Nem üres, véges sorozat-} -> Int

Test>
1 :: Int
Test>
1 :: Int
Test>
4 :: Int

Dominósorozat bővítése (2 pont)

Adjuk meg azt a függvényt, amely segítségével bővíthetjük egy újabb lapkával a sorozatot!

Megjegyzés: Ha illegális lépést eredményezne a bővítés, akkor használjuk az error függvényt!

(<+>) :: DominoSequence -> Domino -> DominoSequence

Test>
[(1, 2), (2, 4)] :: DominoSequence
Test>
[(1, 2), (2, 5), (5, 1), (1, 4)] :: DominoSequence
Test>
[(1, 2), (2, 5), (5, 1), (1, 4)] :: DominoSequence
Test>
[(1, 2), (2, 5), (5, 1), (1, 3), (3, 2)] :: DominoSequence
Test>
⊥₁ :: DominoSequence
⊥₁: Domino cannot be appended
CallStack (from HasCallStack):
  error, called at ./Dominoes.lhs:176:44 in main:Dominoes

Sorozat lehetséges bővítései, ismétléssel (3 pont)

Adjuk meg azt a függvényt, amely a megadott sorozatot az összes lehetséges módon kiegészíti egy lapkával a rendelkezésre álló dominók felhasználásával!

fork :: DominoSequence -> [Domino] -> [DominoSequence]

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

Felhasznált lapkák eltávolítása (2 pont)

Távolítsuk el a halmazból azokat a lapkákat, amelyeket már felhasználtunk a sorozatban!

filterDominoesBy :: [Domino] -> DominoSequence -> [Domino]

Test>
[(0, 0), (0, 1), (0, 2), (0, 3), (1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)] :: [Domino]
Test>
[(0, 0), (0, 2), (0, 3), (1, 1), (1, 2), (2, 2), (3, 3)] :: [Domino]
Test>
[] :: [Domino]
Test>
[(0, 0), (0, 2), (0, 3), (0, 4), (0, 5), (1, 1), (1, 2), (1, 4), (1, 5), (2, 2), (2, 4), (2, 5), (3, 3), (3, 4), (3, 5), (4, 4), (4, 5), (5, 5)] :: [Domino]

Sorozat lehetséges bővítései, ismétlés nélkül (1 pont)

Adjuk meg azt a függvényt, amely a megadott sorozatot az összes lehetséges módon kiegészíti egy lapkával és közben ügyel arra, hogy ugyanazt a lapkát ne használja fel kétszer a sorozatban!

fork' :: DominoSequence -> [Domino] -> [DominoSequence]

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

Sorozatok generálása (3 pont)

Adjuk meg azt a függvényt, amely egy sorozat halmazból előállítja az összes lehetséges sorozatot a fork' függvény iterálásával, melyek a kiinduló sorozatokból keletkezhetnek! Egészen addig ismételjük az alkalmazást, amíg üres sorozatot nem kapunk!

generate :: [DominoSequence] -> [Domino] -> [DominoSequence]

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

Pontozás