pioupiou1211
pioupiou1211

Reputation: 373

Create all the '' small'' matrix from a bigger one - Haskell

I have a rectangular matrix with cases containing B or N. An example of matrix:

g0 = [[B,B,B,B,B,B,N],
      [B,B,N,B,N,B,B],
      [N,B,N,N,N,N,N],
      [B,B,B,N,N,B,N],
      [N,N,N,B,B,B,B],
      [B,B,B,N,N,B,N]]

I have a type rectangle like [Int,Int,Int,Int] and a function that gets a smaller rectangular matrix from my matrix with this type. Here's the function but that's not the most important part:

getRectangle :: Rectangle -> Grille -> Grille -- cette fonction récupère la grille qui correspond au rectangle donné
getRectangle (i,j,l,c) g = transpose (getLigne (j,c,(nbLigne (transpose g0))) (transpose (getLigne (i,l,(nbLigne g0)) g0)))
--transpose get create a matrix with (n,m) = (lines,columns) in a matrix (m,n) and nbLigne return the number of lines (or columns when used with transpose) of a matrix.

getLigne :: (Int,Int,Int) -> Grille -> Grille 
getLigne (i,l,0) g = []                     
getLigne (1,l,1) g = [head g]                
getLigne (i,l,indice) [] = []
getLigne (i,l,indice) g         
    | indice == (i+l) =  getLigne (i,l,(indice-1)) (init g) ++ [last g]
    | indice == i = [last g]
    | i < indice && indice < (i+l) = getLigne (i,l,(indice-1)) (init g) ++ [last g]
    | otherwise = getLigne (i,l,(indice-1)) (init g)

Here's an example:

*Main> affiche (getRectangle (1,2,2,3) g0)
[B,B,B,B]
[B,N,B,N]
[B,N,N,N]

So, I have a tuple with (i,j,l,c). Knowing that 1<=i<i+l<=n and 1<=j<j+c<=m with n the number of lines of the matrix and m the number of columns. To be clear, with a tuple (i,j,l,c), my function create a rectangle, from my matrix, formed with these cases: (i,j), (i+l,j), (i,j+c) and (i+l,j+c).

Now that I can create a single rectangle, I need to create all the possibles rectangles in any matrix. I don't have any clue on how I can do this since I feel like there is so many rectangles in a single matrix and cover all the cases seems very hard and long to me.

Maybe that I wasn't clear on some points, feel free to ask.

Upvotes: 0

Views: 114

Answers (1)

baxbaxwalanuksiwe
baxbaxwalanuksiwe

Reputation: 1494

Salut :),

For combinations, I often work with the list monad. Note that using the do notation like this is equivalent to working with list comprehensions

From a position you can deduce all the rectangles that can originate from a given point:

allRectsOriginatingFrom :: Point -> Grille -> [Rectangle]
allRectsOriginatingFrom (x, y) g
    -- Si le point est dans ta grille...
    | (x >= 1 && x <= width g) && (y >= 1 && y <= height g) = do
        w <- [0 .. width g - x]
        h <- [0 .. height g - y]
        return (x, y, w, h)
    -- Sinon y'a pas de rectangle possible
    | otherwise = [] 

From there, your just have to map the function over all the possible positions on your grid:

allPointsOf :: Grille -> [Point]
allPointsOf g = do
    x <- [1 .. width g]
    y <- [1 .. height g]
    return (x, y)

allRectsOf :: Grille -> [Rectangle]
allRectsOf g = do
    pos <- allPointsOf g
    allRectsOriginatingFrom pos g

And finally, mapping it with your getLigne function will get you every rectangle in your grid.

PS: Try to create datatypes instead of type aliases, it's better in my opinion (e.g. create a datatype like data Rectangle = Rectangle Int Int Int Int instead of type Rectangle = (Int, Int, Int, Int)).

Upvotes: 1

Related Questions