Pasziánsz rendezés

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 véges sorozat ún. pasziánsz rendezését kell megvalósítani. Ez a pasziánsz nevű kártyajátékról kapta a nevét, mivel annak menetéhez nagyon hasonlóan végezzük a sorozat rendezését.

A rendezendő sorozatot úgy tekintjük, mint egy véletlenszerűen megkevert kártyapakli egymás után következő lapjait. Ezeket a lapokat (vagyis rendre a sorozat elemeit) ezután halmokba osztjuk szét a következő szabályok szerint:

Magát a rendezés eredményét ezután pedig úgy kapjuk, ha az iménti szakaszban létrehozott halmokat rendezetten összefésüljük.

Műveletek halmokkal (1 pont)

A rendezés során alkalmazott halmokat a Pile (paraméteres) szinonimával ábrázoljuk, amely tulajdonképpen nem lesz más, mint adott típusú elemek listája:

type Pile a = [a]

Adjuk meg ezen definíció szerint az üres, vagyis kártyát nem tartalmazó halomnak megfelelő értéket!

emptyPile :: Pile a

Készítsünk egy olyan bináris operátort, amely egy elemet rátesz egy halom tetejére!

infixl 5 <<
(<<) :: Pile a -> a -> Pile a

Test>
[1] :: Pile Integer
Test>
[1, 2] :: Pile Integer
Test>
"tset" :: Pile Char

A kezdeti állapot előállítása (1 pont)

Definiáljuk azt a függvény, amely elvégzi az algoritmus első lépését, vagyis a rendezendő sorozat első eleméből képez egy halmot!

firstDeal :: [a] -> ([Pile a], [a])

Test>
([], []) :: ([Pile ()], [()])
Test>
([[1]], [6, 3, 7, 1, 9, 9, 5]) :: ([Pile Integer], [Integer])
Test>
(["l"], "ambda") :: ([Pile Char], [Char])

Egy elem elhelyezése a halmok tetejére (3 pont)

Készítsünk egy olyan függvényt, amely adott rendezés szerint megkeresi azt a halmot, amelyre a soronkövetkező elemet kell elhelyezni, majd ráteszi azt!

Ne feledjük, hogy két elem (az első másodikhoz való) viszonyát ebben az esetben egy Ordering értékkel írjuk le, amely a következő lehet: LT – kisebb, mint; EQ – egyenlő; GT – nagyobb, mint.

place :: (a -> a -> Ordering) -> [Pile a] -> a -> [Pile a]

Test>
[[("card", 1)]] :: [Pile ([Char], Integer)]
Test>
[[("card", 1)], [("stick", 3)]] :: [Pile ([Char], Integer)]
Test>
[[("card", 1)], [("ball", 2), ("stick", 3)]] :: [Pile ([Char], Integer)]
Test>
[[5]] :: [Pile Integer]
Test>
[[4, 5]] :: [Pile Integer]
Test>
[[4, 5], [8]] :: [Pile Integer]
Test>
[[2, 4, 5], [8]] :: [Pile Integer]
Test>
[[2, 4, 5], [8], [10]] :: [Pile Integer]
Test>
[[2, 4, 5], [8], [9, 10]] :: [Pile Integer]
Test>
[[2, 4, 5], [3, 8], [9, 10]] :: [Pile Integer]

A halmok összefésülése (3 pont)

Adjuk meg azt a függvényt, amely adott rendezés szerint az algoritmus korábbi fázisában létrehozott halmokat összefésüli egy rendezett sorozattá! A halmok esetében feltételezhetjük, hogy azok már ugyanazon rendezés szerint rendezetten tartalmazzák az elemeket.

Megjegyzés: A megoldásban nem használható semmilyen rendezés!

mergePiles :: (a -> a -> Ordering) -> [Pile a] -> [a]

Test>
[19, 10, 8, 7, 6, 4, 4, 2, 2, 0, -2, -4] :: [Integer]
Test>
"abbceefgiiillmnnnnnooorrsstttuu" :: [Char]

Paraméterezhető pasziánsz rendezés (3 pont)

Írjuk meg a pasziánsz rendezés rendezési relációval paraméterezhető változatát! Ez egy olyan függvény lesz, amely az adott típusbeli két érték viszonyát egy Ordering típusú értékkel leíró függvény segítségével (ld. fentebb) egy olyan típusú értékeket tartalmazó listából meghatározza annak egy rendezett permutációját!

Megjegyzés: A megoldásban nem használható semmilyen rendezés!

patienceSortBy :: (a -> a -> Ordering) -> [a] -> [a]

Test>
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1] :: [Integer]
Test>
[('c', 0), ('e', 1), ('d', 4), ('b', 13), ('g', 25), ('f', 30), ('a', 32)] :: [(Char, Integer)]

Általános pasziánsz rendezés (1 pont)

Az egyszerűbb használhatóság érdekében adjuk meg a pasziánsz rendezés azon változatát, amely eleve feltételezi a sorozat elemeinek rendezhetőségét és azok alapértelmezett rendezési relációjával számítja ki annak egy rendezett permutációját!

Megjegyzés: A megoldásban legfeljebb csak a pasziánsz rendezés használható!

patienceSort :: Ord a => [a] -> [a]

Test>
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] :: [Integer]
Test>
"abfoor" :: [Char]

Pontozás (elmélet + gyakorlat)