user3596063
user3596063

Reputation: 21

How to extract the value from a certain position in a matrix in Haskell?

I have to implement a gameboard for 2048. I declared it:

type Board = [[Int]]

In order to add a new random value in a random cell I must check the value in that cell, but I don't know how to get the value. I've seen different examples using a monad, but I don't know how to use Monad and I was wondering if there is another way to do this.

Can anyone help me with an example?

Thanks!

Upvotes: 2

Views: 1050

Answers (1)

leftaroundabout
leftaroundabout

Reputation: 120711

Well, as for checking the value in a particular cell – that's just list-indexing, you can simply use !!. Since the list is nested you need two lookups, first the row then the column/cell.

type CellId = (Int,Int)

cellAt :: Board -> CellId -> Int
cellAt rows (idy, idx) = rows !! idy !! idx

I bit less obvious is updating. To do that in a functional style you need a function like

updataCellAt :: CellId -> Int -> Board -> Board

that takes a board as an argument, and returns a modified board.

Modifying a list is easy only at one spot: the head.

replaceHead :: a -> [a] -> [a]
replaceHead _ [] = []
replaceHead x (_:xs) = x:xs

To modify an arbitrary spot, the best thing is to first split up the list in everything before that spot, and everything form there on (so the second list has the spot as its head).

replaceAt :: Int -> a -> [a] -> [a]
replaceAt i x xs = let (prev, remain) = splitAt i xs
                   in prev ++ replaceHead x remain

Now, this is not very flexible: you're simply throwing away the replaced element, but in general you might want to only apply a transformation to it.

modifyHead :: (a->a) -> [a] -> [a]
modifyHead _ [] = []
modifyHead mdf (x:xs) = mdf x : xs

modifyAt :: Int -> (a->a) -> [a] -> [a]
modifyAt i mdf xs = let (prev, remain) = splitAt i xs
                    in prev ++ modifyHead mdf remain

This one can now easily be used to modify a nested list, like your board:

modifyCellAt :: CellId -> (a->a) -> [[a]] -> [[a]]
modifyCellAt (iy, ix) mdf = modifyAt iy (\row -> modifyAt ix mdf row)
               -- or short: modifyAt iy $ modifyAt ix mdf

Upvotes: 2

Related Questions