Akasztófajá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 a szerencsekerékhez hasonló akasztófajátékot fogjuk megvalósítani. A játék során a játékos kap egy feladványt és az a cél, hogy különböző betűk tippelésével eljusson a megfejtéshez a megadott hibahatáron belül.

A játék szabályai a következők:

A játéknak vége szakad, ha:

A feladványhoz megadunk egy ábécét. A feladvány szövege csak a megadott ábécé elemeiből állhat.

type ABC = [Char]
abc :: ABC
abc = ['A'..'Z']

A játék aktuális állapotát (State) az eredeti feladvány szövege (Riddle), a helyesen tippelt betűk (RightGuesses) és a rosszul tippelt betűk (WrongGuesses) rendezett hármasa adja meg.

Az állapot mindhárom elemének közös invariáns tulajdonsága, hogy csak nagybetűket tartalmazhatnak! Ezt a függvények helyes megadásával fogjuk kikényszeríteni.

type Riddle       = String
type RightGuesses = [Char]
type WrongGuesses = [Char]
type State        = (Riddle, RightGuesses, WrongGuesses)

Megfelelő-e a megadott betű? (1 pont)

A tippelt betűk egyaránt lehetnek kis- és nagybetűk, valamint egyéb karakterek is. Adjuk meg azt a függvény, amely kis- és nagybetűkre való tekintet nélkül megvizsgálja, hogy az megtalálható-e a paraméterül kapott ábécében!

isValidLetter :: Char -> ABC -> Bool

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

A kezdeti állapot (2 pont)

Adjuk meg azt a függvényt, amely megadja a kezdeti állapotot! Amennyiben a feladványban csak az adott ábécében is szereplő elemek és szóköz szerepel, a függvény előállítja a kezdeti állapotot leíró rendezett hármast. A rendezett hármas első eleme a feladvány, amely csupa nagybetűből áll. A második és harmadik eleme pedig az eddig jól és rosszul tippelt betűket adja meg, értelemszerűen ezek kezdetben üres listák. Amennyiben a feladvány nem felel meg az ábécének, akkor az error függvény segítségével jelezzünk hibát!

startState :: ABC -> String -> State

Test>
([], [], []) :: State
Test>
("SOS", [], []) :: State
Test>
("SAVE OUR SOULS", [], []) :: State
Test>
⊥₁ :: State
⊥₁: startState: the riddle contains invalid letters
CallStack (from HasCallStack):
  error, called at ./Hangman.lhs:117:19 in main:Hangman

Betűk tippelése (2 pont)

Definiáljuk a guessLetter függvényt, amely egy tippelt betű alapján módosítja a játék állapotát!

Ekkor a következő eseteket különböztetjük meg:

guessLetter :: ABC -> Char -> State -> State

Test>
("SAVE OUR SOULS", "A", []) :: State
Test>
("SAVE OUR SOULS", "A", []) :: State
Test>
("SAVE OUR SOULS", [], "K") :: State
Test>
("SAVE OUR SOULS", "A", []) :: State
Test>
("SAVE OUR SOULS", [], "K") :: State
Test>
("SAVE OUR SOULS", "VA", []) :: State
Test>
("SAVE OUR SOULS", "VA", "K") :: State
Test>
⊥₁ :: State
⊥₁: guessLetter: invalid guessed letter
CallStack (from HasCallStack):
  error, called at ./Hangman.lhs:152:30 in main:Hangman

A feladvány megjelenítése (2 pont)

Adjuk meg a showRiddle függvényt, amellyel a feladvány jelenlegi állapotát tudjuk megjeleníteni a játékos számára!

A feladványban a helyesen tippelt karakterek jelenjenek meg, a többi betű helyére a '_' karaktert illesszük! Ügyeljünk arra, hogy a feladvány tagoltsága a játékos számára is látható maradjon!

Megjegyzés: A megoldáshoz nem használható fel a showState függvény!

showRiddle :: State -> String

Test>
"____ ___ _____" :: String
Test>
"_A__ ___ ___L_" :: String
Test>
"SA__ ___ S__LS" :: String
Test>
"SA__ O__ SO_LS" :: String
Test>
"SOS" :: String

Az állapot megjelenítése (1 pont)

Definiáljuk a showState függvényt, amely az adott állapotot a játékos számára megmutatható formára alakítja!

showState :: State -> State

Test>
("____ ___ _____", [], []) :: State
Test>
("SA__ ___ S__LS", "SAL", []) :: State
Test>
("SA__ O__ SO_LS", "SALO", []) :: State

Sikerült-e megfejteni a feladványt? (2 pont)

Adjuk meg azt a függvényt, amely a játék egy adott állapotához megadja, hogy a játékosnak sikerült-e megfejtenie a feladványt! A feladványt akkor tekintjük megfejtettnek, ha a tippeket figyelembe véve minden betűje ismert.

Megjegyzés: Ebben az esetben még nem kell foglalkozni a rosszul tippelt betűk számával.

isRiddleComplete :: State -> Bool

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

Vége van-e a játéknak? (1 pont)

Definiáljuk az isGameOver függvényt, amely eldönti, hogy a megadott állapot a játék végét jelenti-e!

A játéknak akkor van vége, ha:

isGameOver :: State -> Bool

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

Eddig fel nem használt betűk megadása (1 pont)

Adjuk meg azt a függvényt, amely megadja, mely betűk nem kerültek még felhasználásra a tippelés során!

getAvailableLetters :: ABC -> State ->  [Char]

Test>
"BCDFGHIJMNPQXY" :: [Char]
Test>
"ABCDEFMNOPQRSTUVWXYZ" :: [Char]
Test>
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" :: [Char]

A játék lejátszása (2 pont)

Definiáljuk a play függvényt, amely egy állapot és egy karakterlista segítségével lejátssza a játékot! A lejátszásnak vége szakad, ha:

A játék eredményének megjelenítéséhez használjuk a showState függvényt!

play :: ABC -> [Char] -> State -> State

Test>
("SAVE OUR SOULS", "LRUOEVAS", "WTZK") :: State
Test>
("SAVE ___ S___S", "EVAS", "TZKIJP") :: State
Test>
("____ OUR _OUL_", "LRUO", "W") :: State
Test>
("SAVE OU_ SOULS", "UOLVASE", "YWZTIK") :: State
Test>
("SAVE ___ S__LS", "LVASE", "WZTIKP") :: State

A játék kiértékelése (1 pont)

Adjuk meg azt a függvényt, amely az előző függvény segítségével lejátssza a játékot, majd szöveges formában kiértékeli annak eredményét! Három eset lehetséges: a játékosnak vagy sikerült megfejtenie a feladványt vagy nem, illetve a játéknak még nincs vége.

Megjegyzések:

evaluatePlay :: ABC -> [Char] -> State -> String

Test>
"The player completed the word. Congratulations! The solutions was: SAVE OUR SOULS" :: String
Test>
"Game Over. Try a new game!" :: String
Test>
"The game is pending! Current state is: (\"S_S\",\"S\",\"KP\")" :: String
Test>
"The game is pending! Current state is: (\"SAVE ___ S___S\",\"EVAS\",\"WTZKP\")" :: String
Test>
"The game is pending! Current state is: (\"SAVE ___ S___S\",\"EVAS\",\"ZKP\")" :: String

Pontozás (elmélet + gyakorlat)