27 June 2013

The Polar Game in Haskell, Day 3

More phone interviews, more coding. On my laptop, amidst a gaggle of fighting children, during a thunderstorm, with our basement flooding, with the kind assistance of some friendly commentors, a little more progress. Let's change Pos

data Pos = Pos { posY :: Int, posX :: Int }
    deriving (Show, Eq)

And define a game world:

data World = World { board :: Board, penguinPos :: Pos,
                          penguinDir :: Dir,
                          heartCount :: Int } deriving (Show)

It was painful, took an embarrassingly long time, and this can't possibly be how I want to keep it indefinitely, but I finished slice which treats a list of lists of tiles like a 2-dimensional array and gives us what the penguin sees before him, looking in a given direction:

slice :: Board -> Pos -> Dir -> [Tile]
slice board pos East = ( drop ( posX pos ) $ 
    board !! ( posY pos ) ) ++ [Edge]
slice board pos South = ( drop ( posY pos ) $ 
    ( transpose board ) !! ( posX pos ) ) ++ [Edge]
slice board pos West = ( reverse $ take ( posX pos + 1 ) $ 
    board !! ( posY pos ) ) ++ [Edge]
slice board pos North = ( reverse $ take ( posY pos + 1 ) $ 
    ( transpose board ) !! ( posX pos ) ) ++ [Edge]

Let's just leave that as it is for now and use it, with the intent of replacing it with a real array of some sort later on. I still have to figure out how to merge a modified penguin track with an unmodified board to create the next state of the entire board... that's not going to be pretty, but it's doable.

So, one of the things I really love about Haskell is that once you get these pieces, they really do start come together nicely. Let's go ahead and define the first board. I could make it from the strings or a run-length encoding or something, but for now let's just bite the bullet and build the list the hard way:

get_initial_board :: [[Tile]]
get_initial_board = [[Tree,Empty,Empty,Empty,Empty,Empty,
                      Empty,Empty,Empty,Empty,Empty,Empty,
                      Empty,Empty,Empty,Tree,Empty,Empty,
                      Empty,Empty,Empty,Ice_Block,Empty,Empty],
                     [Tree,Empty,Bomb,Empty,Mountain,Empty,
                      Heart,Ice_Block,Heart,Empty,Empty,Empty,
                      Empty,Empty,Empty,Empty,Empty,Empty,
                      Tree,Empty,Empty,Tree,Empty,Empty],
                     [Tree,Empty,Empty,Empty,Empty,Empty,
                      Empty,Empty,Empty,Empty,Empty,Empty,
                      Empty,Empty,Empty,Empty,Heart,Empty,
                      Empty,Empty,Mountain,House,Empty,Empty],
                     [Tree,Tree,Empty,Empty,Empty,Empty,
                      Tree,Empty,Empty,Empty,Empty,Empty,
                      Empty,Empty,Empty,Empty,Empty,Empty,
                      Empty,Empty,Empty,Empty,Empty,Empty]]

penguin_view :: Board -> Pos -> Dir -> [Tile]
penguin_view board pos dir = drop 1 $ slice board pos dir

So now we can actually start doing stuff with this. Here's what's in front of the penguin when he looks at the board from different points, in different directions:

*Main> penguin_view get_initial_board (Pos 0 0) East
[Empty,Empty,Empty,Empty,Empty,Empty,Empty,Empty,Empty,
Empty,Empty,Empty,Empty,Empty,Tree,Empty,Empty,Empty,Empty,
Empty,Ice_Block,Empty,Empty,Edge]

*Main> penguin_view get_initial_board (Pos 0 0) South
[Tree,Tree,Tree,Edge]

*Main> penguin_view get_initial_board (Pos 0 0) West
[Edge]

*Main> penguin_view get_initial_board (Pos 0 0) North
[Edge]

*Main> penguin_view get_initial_board (Pos 3 21) North
[House,Tree,Ice_Block,Edge]

Fun! Tomorrow, if I can manage it... an updated world.

No comments: