Home > Software engineering >  haskell - detect diagonally adjacent elements
haskell - detect diagonally adjacent elements

Time:04-24

The objective of the function is to take a board in the form of a list of lists of Squares and returns True if no Square contains a white where there is a green square diagonally adjacent to it in the following row.

The function signature is:

diagchecker :: [[Square]] -> Bool

Square is defined as:

data Square = White | Green | Empty deriving Eq

For example, diagchecker [[White,Empty],[Empty,Green]] should return False.

diagchecker [[Green,Empty],[Empty,White]] should return True.

diagchecker [[White,Green],[White,White],[Green,Empty]] should return False.

---------Update------------

OK I'm basically one step away from getting this right. Here is my code:

data Square = White | Green | Empty deriving Eq

diagchecker :: [[Square]] -> Bool

anyDiags :: (a -> a -> Bool) -> [[a]] -> Bool
anyDiags p = fst . foldr f (False, [])
  where
    f xs (a, ys) = ( a || or (zipWith p xs (drop 1 ys)) 
                       || or (zipWith p (drop 1 xs) ys)
                   , xs)

greenAfterWhite x y = (x == White && y == Green)
    
diagchecker = anyDiags greenAfterWhite

This code actually works, and now the only problem I'm facing is that I want diagchecker to return True when there is no green after white, and return False when there is green after white. Under current situation it is doing the job detecting whether there is green after white, but the result Boolean it returns is exactly the opposite of what I want. Can anyone please help me with this?

-----Update No.2-----

For changing the output I've tried changing greenAfterWhite like this:

greenAfterWhite x y 
    | (x == white && y == green) = False
    | otherwise = True

or this:

greenAfterWhite x y = not (x == White && y == Green)

Both of these changes all result in the diagchecker returns TRUE for every single input [[Square]].

CodePudding user response:

Since you only check the two diagonal squares below, I'll express this as a mapping on tails. You're welcome to reformulate it in terms of foldr:

import Data.List (tails)

diagchecker = noGreenUnderWhiteDiagonally

noGreenUnderWhiteDiagonally rows = 
  null [ ()
         | (a:b:_) <- tails rows,
           greenUnderWhite a (drop 1 b) 
           || 
           greenUnderWhite (drop 1 a) b]

greenUnderWhite row1 row2 = 
  or $ zipWith (...) ... ...

You will need to complete the definition to check the presence of green square underneath in case the square above is white.

or will detect whether any True element is present in its argument list.

The negation is already built into the code, with null detecting whether its argument list is empty. The elements of that list are not important, so we use the "bland" value, ().

The mapping on tails achieves pairwise comparison of consecutive rows in your matrix.

  • Related