+1 (315) 557-6473 

Text-Based Adventure Game Homework Help Using Haskell

Get in touch with us immediately if you need professional text-based adventure game homework help. Our Haskell homework tutors are highly qualified and experienced. You can trust them with your homework and expect excellent solution. Opt for our text-based adventure game homework help using Haskell and enjoy a myriad of benefits
Text-Based Adventure Game Assignment Help

Base module

In this assessment, you are going to make a text-based adventure game in Haskell
This Base.hs module provides some key data types for the game and some helper functions for outputting information to the user:
• GameState { holds a Player value and the current Room that the player is in;
• Next a { is used to represent the idea that, after some command or action, either we stay the Same or Progress to a new a (this will be used as Next GameState);
• Items and Monsters;
• Player { contains information about the player including their inventory (a list of Item);
• Room { describes a room and what is available in it, including:
{ The room’s name, its description, and whether it is a \winning room" (ends the game) or not;
{ A Maybe Item representing whether an item is required to enter the room;
{ A list of Items (each paired with a String description of where the item is located); { A list of Monsters;
{ An association list (list of pairs) between a Direction and a Room;
{ A function representing actions possible in this room, which takes an Item as input, a GameState as input, and produces a NextGameState.
• Make sure you familiarise yourself with Base.hs and understand each part of it.
Creating a map
The following guides you to create a minimal map. You may create something more elaborate (please not too elaborate!) but the following components are required and will be marked.
Please feel free to chose the names and descriptions of rooms and the positions of objects

(any String piece of data is your creative choice).  
1. As a warmup (and a useful function for later) de ne a function opposite which computes (3 marks)
  a direction’s opposite, e.g., opposite North = South. Include the type signature.  
2. In order to construct a Room an \action" value is needed which describes how a player can (3 marks)
  use an item in a room, possibly changing the game state. This is represented by function  
  of type Item ->GameState -> Next GameState.  
  De ne a simple such function which can be used for a room’s actions  eld, of type:  
  noActions ::  Item ->GameState -> Next GameState  
  to represent a lack of actions in a room. Thus noActions should return a Same value with  
  a message that there is nothing that can be done with the item given (you can use show  
  on an Item).  
3. De ne a winning room (has isWinRoom value as True) which requires a key to enter, has (4 marks)
  no items or monster or further doors, and no actions (use the function you de ned above).  
4. De ne a starting room for your player from which the winRoom can be accessed and which (5 marks)
  has a spoon as one of its items (and no actions). This starting room should lead o  to  
  another room de ned in the next question.  
5. De ne a room leading from the previous containing a wood troll with health 10 who holds a (12 marks)
  Key. Implement an \action" function which on a Spoon input checks if the room (provided  
  by the GameState parameter) has a monster:  


• If no monster, indicate (via Same) that we stay in the same state, giving an appro-priate message.

• If there is a monster, we will attack it with the spoon (which deals 5 damage). If the monster has health less than or equal to 5 before we attack then this action will kill it, so return a next game state where the monster is no longer present (not in the list) and the item it was holding is now put into the room’s items.

If the monster has > 5 health, update the monster’s health in the room to be 5 less. Include appropriate messages.

6. De ne game0 as an initial GameState pointing to your start room and with a player who(3 marks) has an empty inventory.
Parsing commands and simple I/O

The Base module provides the Parsable type class with parse :: String -> Maybe a.

7. Implement a Parsable instance for Item. Item names should be parsed lower case. (3 marks)
8. Implement a Parsable instance for Direction. Directions should be parsed lower case. (3 marks)

9. Implement a Parsable instance for Command which parses the following inputs to commands: (12 marks)

• go dir parsed to a Move (parsing also the direction dir );

• grab item parsed to a PickUp (parsing also the item item );

• use item parsed to a Use value (parsing also the item item );

• end parsed to End.

Hint: remember strings are lists and you can pattern match on a number of characters at the start of a list by nested cons patterns.

10. De ne a function tellResponse that takes a string and outputs it (i.e., writes to standard (3 marks)
  output) with the following form, e.g., where message is the input string here:  
   
  Hint: check tellContextLine from Base for inspiration.  
11. De ne a function readCommand ::  IO (Maybe Command) that outputs the string "> " us (4 marks)
  ing putStr2 and then reads a line of input from the user with getLine and returns the result  
  of parsing the user’s input string via parse.  

Game Engine

12. As part of the game engine, items are deleted from a room when they are picked up. Items (5 marks)

are stored in an association list (list of pairs), therefore de ne a function of the type:

deleteFrom :: Eq a => a -> [(a, b)] -> [(a, b)]

which, from the second parameter, deletes the pair whoserst component is equal to the rst parameter.


13. During the course of the game engine, a room may be recomputed (e.g., items removed,(4 marks) monster wounded or killed). When we move from one room to another, we want the new

room to point back to the previous room we were in. De ne a function of type:

leaveRoom :: Room -> Direction -> Room -> Room

whereleaveRoomfromRoomdirtoRoom returns toRoom but whose doors have been up-dated such that the opposite direction is now associated to fromRoom.

Hint: use opposite and deleteFrom. You will be able to test your function more easily later so you might want to come back to this after writing something that type checks.

14. Implement a function step which takes a command, a game state, and computes what to do (15 marks)

next, i.e., of type:

step :: Command ->GameState -> Next GameState This function should handle each possible command as follows:

(a) Move dir should check if there is a door in that direction and if so, and if the player’s in-ventory has the required item for that door, should return a new game state (Progress) where the current room of game state is that new room (computed using leaveRoom)

Hint: you may want to use the lookup function to lookup the door from the doors association list.

(b) PickUp item should remove an item from the room (deleteFrom) and add it to the player’s inventory if indeed the item is in the room.

Include appropriate messages, considering also the case where the requested item is not in this room.

(c) Use item, if the item is in the player’s inventory, then apply the current room’s actions function to the item to compute the next game state.

Otherwise, stay in the same state with a message that the player doesn’t have the item.

15. Implement the functions: (12 marks)

play :: GameState -> IO ()

playLoop :: GameState -> IO ()

which should have the following behaviour:

• play should simply report the context of the player based on the current game state (using tellContext) and then apply playLoop.

Hint: use sequencing of IO computations via either the do notation or >>=

• playLoop should rst check if the player is in the winning room and if so end the game;

• Otherwise, read an input from the user with readCommand, and:

{ If the command is unknown, tell the user and recurse on playLoop with the current game state;

{ If the command is End, return after outputting an appropriate message.

{ Otherwise, use the step function to determine the next game state. If Same, show the message and recurse with the current game state; if Progress, show the message, tellContext for the new game state, and recurse with this new game state.

16. De ne the main function (to make your code compilable as a stand-alone executable) which (1 marks)
 starts the game with the game0 state (see Chunk 1 q6).
17. Bonus Up to a maximum of 8 bonus marks for adding some other feature, e.g., one of: (8 marks)

• A new item and some action demonstrating it;

• A new monster and action demonstrating it;

• A help menu;

Player health / monster attacks.

Example game play from my minimal model answer


You are in a kitchen. It is cold, dark.

There are doors to the south and east.

On a table there is a spoon.

> go east

< This door requires a key. > use spoon

< You do not have a spoon. > grab spoon

< You picked up the spoon.

You are in a kitchen. It is cold, dark.

There are doors to the south and east.

> go south

< You go through the door to the south.

You are in a garden. It is weedy.

There is a door to the north.

There is a wood troll holding a key.

> use spoon

< You attack the monster but it seems only wounded.

You are in a garden. It is weedy.

There is a door to the north.

There is a wood troll holding a key.

> use spoon

< You attack the monster with the spoon and it succumbs. It drops a key.

You are in a garden. It is weedy.

There is a door to the north.

On the floor there is a key.

> grab key

< You picked up the key.

You are in a garden. It is weedy.

There is a door to the north.

> go noerg Unknown command
> go north

< You go through the door to the north.

You are in a kitchen. It is cold, dark.

There are doors to the south and east.


> go east

< You unlock the door to the east.

You are in a loot room. It is shiny. You get all the loot..

There is a door to the west.

< You won Dominic! Well done.

Haskell Code Solution

module Main where

import Base
import System.IO

-- ## Chunk 1,

-- 1.
opposite :: Direction -> Direction
opposite d = case d of
    North -> South
    South -> North
    East -> West
    West -> East

-- 2.
noActions :: Item ->GameState -> Next GameState
noActionsi _ = Same ("Nothing can be done with the " ++ (show i))

-- 3.
winningRoom = Room {
name = "loot room",
description = "shiny. You get all the loot.",
isWinRoom = True,
requires = Just Key,
items = [],
monsters = [],
doors = [],
actions = noActions
}

-- 4.
startingRoom = Room {
name = "kitchen",
description = "cold, dark",
isWinRoom = False,
requires = Nothing,
items = [(Spoon, "On a table")],
monsters = [],
doors = [(South, trollRoom), (East, winningRoom)],
actions = noActions
}

-- 5.

trollRoom = Room {
name = "garden",
description = "weedy",
isWinRoom = False,
requires = Nothing,
items = [],
monsters = [woodTroll],
doors = [(North, startingRoom)],
actions = gardenAction
}

woodTroll = WoodTroll { health = 10, holding = Key }

gardenAction :: Item ->GameState -> Next GameState
gardenAction Spoon (GS p r) = case monsters r of
    [] ->noActions Spoon (GS p r)
m:ts ->
if (health m) > 5 then
            Progress "You attack the monster but it seems only wounded"
                    (GS p (r { monsters = (m {health = (health m) - 5}) : ts }))
else
            Progress "You attack the monster with the spoon and it succumbs. It drops a key"
                    (GS p (r { monsters = ts, items = (holding m, "On the floor") : (items r) }))
gardenActioni g = noActionsi g

-- 6.
game0 = GS { player = Player {playerName = "player1", inventory = []}, room = startingRoom }

-- ## Chunk 2

-- 7.
instanceParsable Item where
parse "key" = Just Key
parse "spoon" = Just Spoon
parse _ = Nothing

-- 8.
instanceParsable Direction where
parse "north" = Just North
parse "south" = Just South
parse "east" = Just East
parse "west" = Just West
parse _ = Nothing

-- 9.
instanceParsable Command where
parse ('g':'o':' ':ds) = do
dir<- parse ds
return (Move dir)
parse ('g':'r':'a':'b':' ':is) = do
item<- parse is
return (PickUp item)
parse ('u':'s':'e':' ':is) = do
item<- parse is
return (Use item)
parse "end" = Just End
parse _ = Nothing

-- 10.
tellResponse :: String -> IO ()
tellResponsess = putStrLn $ "< " ++ ss ++ "."

-- 11.
readCommand :: IO (Maybe Command)
readCommand = do
putStr "> "
hFlushstdout
line<- getLine
return (parse line)


-- ## Chunk 3

-- 12.
deleteFrom :: Eq a => a -> [(a, b)] -> [(a, b)]
deleteFrom _ [] = []
deleteFrom x ((i, ss):ts) = if x == i then ts else (i, ss):(deleteFrom x ts)

-- 13.
leaveRoom :: Room -> Direction -> Room -> Room
leaveRoomfromRoomdirtoRoom =
toRoom { doors = (opposite dir, fromRoom):(deleteFrom (opposite dir) (doors toRoom)) }

-- 14.
step :: Command ->GameState -> Next GameState
step (Move dir) (GS p r) =
case lookup dir (doors r) of
        Just nr ->
case requires nr of
                Just i ->
ifelemi (inventory p) then
                        Progress ("You unlock the door to the " ++ (show dir))
                                (GS p (leaveRoom r dirnr))
else
                        Same ("This door requires a " ++ (show i))
                Nothing -> Progress ("You go through the door to the " ++ (show dir))
                            (GS p (leaveRoom r dirnr))
        Nothing -> Same $ "There is no door at direction " ++ (show dir)
step (PickUpi) (GS p r) =
case lookup i (items r) of
        Just _ -> Progress ("You picked up the " ++ (show i))
                    (GS (p {inventory = i:(inventory p)}) (r {items = deleteFromi (items r)}))
        Nothing -> Same ("There is no " ++ (show i) ++ " in this room")
step (Use i) (GS p r) =
ifelemi (inventory p) then (actions r) i (GS p r)
else Same $ "You do not have a " ++ (show i)

-- 15.
play :: GameState -> IO ()
play g = do
tellContext g
playLoop g

playLoop :: GameState -> IO ()
playLoop (GS p r) =
if (isWinRoom r) then
tellResponse $ "You won " ++ (playerName p) ++ "! Well done."
else do
cs<- readCommand
casecs of
            Nothing -> do
putStrLn "Unknown command"
playLoop (GS p r)
            Just c -> case c of
                End ->putStrLn "Exiting the game"
cmd -> case step cmd (GS p r) of
                    Same s -> do
tellResponse s
playLoop (GS p r)
                    Progress s nxt -> do
tellResponse s
tellContextnxt
playLoopnxt

-- 16.
main :: IO ()
main = play game0
Related Blogs