Add initial HW code for HW 5.
This commit is contained in:
167
KarelState.hs
Normal file
167
KarelState.hs
Normal file
@@ -0,0 +1,167 @@
|
||||
-- | This module defines the state of a running Karel program.
|
||||
module KarelState where
|
||||
|
||||
import Prelude hiding (Either(..))
|
||||
import KarelSyntax
|
||||
|
||||
|
||||
--
|
||||
-- * Positions and directions
|
||||
--
|
||||
|
||||
-- | A cartesian coordinate, representing a position in the world.
|
||||
type Pos = (Int,Int)
|
||||
|
||||
-- | Get the position next to the given position, offset by one square
|
||||
-- in the indicated *cardinal* direction.
|
||||
neighbor :: Card -> Pos -> Pos
|
||||
neighbor North (x,y) = (x,y+1)
|
||||
neighbor South (x,y) = (x,y-1)
|
||||
neighbor East (x,y) = (x+1,y)
|
||||
neighbor West (x,y) = (x-1,y)
|
||||
|
||||
-- | Get a cardinal direction relative to the current one.
|
||||
cardTurn :: Dir -> Card -> Card
|
||||
cardTurn Front c = c
|
||||
cardTurn Back North = South
|
||||
cardTurn Back South = North
|
||||
cardTurn Back East = West
|
||||
cardTurn Back West = East
|
||||
cardTurn Left North = West
|
||||
cardTurn Left South = East
|
||||
cardTurn Left East = North
|
||||
cardTurn Left West = South
|
||||
cardTurn Right North = East
|
||||
cardTurn Right South = West
|
||||
cardTurn Right East = South
|
||||
cardTurn Right West = North
|
||||
|
||||
|
||||
--
|
||||
-- * World state
|
||||
--
|
||||
|
||||
-- | The state of the world is represented by a function that returns
|
||||
-- for each position:
|
||||
-- * Nothing, if the position is a wall
|
||||
-- * Just k, if the position is clear and has k beepers
|
||||
-- You can assume k is always >= 0.
|
||||
type World = Pos -> Maybe Int
|
||||
|
||||
-- | Is the given position clear?
|
||||
isClear :: Pos -> World -> Bool
|
||||
isClear p w = w p /= Nothing
|
||||
|
||||
-- | Is there a beeper at the given position?
|
||||
hasBeeper :: Pos -> World -> Bool
|
||||
hasBeeper p w = maybe False (>0) (w p)
|
||||
|
||||
-- | Increment the number of beepers at the given position.
|
||||
incBeeper :: Pos -> World -> World
|
||||
incBeeper p w = \q -> if p == q
|
||||
then case w q of
|
||||
Nothing -> Just 1
|
||||
Just i -> Just (i+1)
|
||||
else w q
|
||||
|
||||
-- | Decrement the number of beepers at the given position. Note that this
|
||||
-- function can yield a world with negative beepers, so you should make
|
||||
-- sure to only decrement the beepers at a position after first checking
|
||||
-- to make sure there is at least one beeper there (using `hasBeeper`).
|
||||
decBeeper :: Pos -> World -> World
|
||||
decBeeper p w = \q -> if p == q then fmap (subtract 1) (w q) else w q
|
||||
|
||||
|
||||
--
|
||||
-- * Robot state
|
||||
--
|
||||
|
||||
-- | The state of the robot is represented by a triple containing:
|
||||
-- * the current position
|
||||
-- * the current facing (cardinal direction)
|
||||
-- * the number of beepers in the beeper bag
|
||||
type Robot = (Pos,Card,Int)
|
||||
|
||||
|
||||
-- ** Robot position
|
||||
|
||||
-- | The robot's position.
|
||||
getPos :: Robot -> Pos
|
||||
getPos (p,_,_) = p
|
||||
|
||||
-- | Get a position relative to the robot's current facing and position.
|
||||
relativePos :: Dir -> Robot -> Pos
|
||||
relativePos d (p,c,_) = neighbor (cardTurn d c) p
|
||||
|
||||
-- | Set the robot's position.
|
||||
setPos :: Pos -> Robot -> Robot
|
||||
setPos p (_,c,b) = (p,c,b)
|
||||
|
||||
-- | Update the robot's position using an update function.
|
||||
updatePos :: (Pos -> Pos) -> Robot -> Robot
|
||||
updatePos f (p,c,b) = (f p,c,b)
|
||||
|
||||
|
||||
-- ** Robot facing
|
||||
|
||||
-- | The robot's facing (cardinal direction).
|
||||
getFacing :: Robot -> Card
|
||||
getFacing (_,c,_) = c
|
||||
|
||||
-- | Set the robot's facing.
|
||||
setFacing :: Card -> Robot -> Robot
|
||||
setFacing c (p,_,b) = (p,c,b)
|
||||
|
||||
-- | Update the robot's facing using an update function.
|
||||
updateFacing :: (Card -> Card) -> Robot -> Robot
|
||||
updateFacing f (p,c,b) = (p,f c,b)
|
||||
|
||||
|
||||
-- ** Beeper bag
|
||||
|
||||
-- | The number of beepers in the beeper bag.
|
||||
getBag :: Robot -> Int
|
||||
getBag (_,_,b) = b
|
||||
|
||||
-- | Is the beeper bag empty?
|
||||
isEmpty :: Robot -> Bool
|
||||
isEmpty (_,_,b) = b <= 0
|
||||
|
||||
-- | Increment the number of beepers in the bag.
|
||||
incBag :: Robot -> Robot
|
||||
incBag (p,c,b) = (p,c,b+1)
|
||||
|
||||
-- | Decrement the number of beepers in the bag.
|
||||
decBag :: Robot -> Robot
|
||||
decBag (p,c,b) = (p,c,b-1)
|
||||
|
||||
|
||||
--
|
||||
-- * Statement results
|
||||
--
|
||||
|
||||
-- | The result of executing a statement.
|
||||
--
|
||||
-- * OK: The statement executed successfully, so return the updated state
|
||||
-- of the world and the robot. OK to execute the next statement.
|
||||
--
|
||||
-- * Done: Produced only by the Shutdown statement. This returns the final
|
||||
-- state of the robot. No further statements should be executed.
|
||||
--
|
||||
-- * Error: An error occurred. Includes a string for reporting error messages.
|
||||
-- No further statements should be executed.
|
||||
--
|
||||
data Result = OK World Robot
|
||||
| Done Robot
|
||||
| Error String
|
||||
|
||||
instance Show Result where
|
||||
show (OK _ r) = "OK: " ++ show r
|
||||
show (Done r) = "Done: " ++ show r
|
||||
show (Error s) = "Error: " ++ s
|
||||
|
||||
-- | Applies a function to the result if its an OK, otherwise returns
|
||||
-- the result unchanged.
|
||||
onOK :: (World -> Robot -> Result) -> Result -> Result
|
||||
onOK f (OK w r) = f w r
|
||||
onOK _ result = result
|
||||
Reference in New Issue
Block a user