1

I'm trying to make a function that will take a list of lists of Ints as an input, and adds +1 every time it runs into a number bigger or equal to 10. I added -20 on each side so xc can start at 0. Example what should happen after the function runs into first '10':

     [[-20,-20, 0, 0, 0, 0, 0, 0, 0,-20,-20],
      [-20,-20, 0,10, 1, 0, 0, 0, 0,-20,-20],
      [-20,-20, 1, 1, 1, 0,10, 0, 0,-20,-20],
      [-20,-20, 0, 0, 0,10, 0, 0, 0,-20,-20],
      [-20,-20, 0, 0, 0, 0, 0, 0,10,-20,-20],
      [-20,-20,10,10,10, 0, 0, 0, 0,-20,-20],
      [-20,-20,10, 0,10, 0, 0, 0, 0,-20,-20],
      [-20,-20,10,10,10, 0, 0, 0, 0,-20,-20]]

SampleInput = [[-20,-20, 0, 0, 0, 0, 0, 0, 0,-20,-20],
               [-20,-20, 0,10, 0, 0, 0, 0, 0,-20,-20],
               [-20,-20, 0, 0, 0, 0,10, 0, 0,-20,-20],
               [-20,-20, 0, 0, 0,10, 0, 0, 0,-20,-20],
               [-20,-20, 0, 0, 0, 0, 0, 0,10,-20,-20],
               [-20,-20,10,10,10, 0, 0, 0, 0,-20,-20],
               [-20,-20,10, 0,10, 0, 0, 0, 0,-20,-20],
               [-20,-20,10,10,10, 0, 0, 0, 0,-20,-20]]

adder::[[Int]] -> [[Int]]
adder ((xa:xb:xc:xd:xe):(ya:yb:yc:yd:ye)) 
    | xc >= 10  = adder ((xb:xc:(xd+1):xe):((yb+1):(yc+1):(yd+1):ye))
    | otherwise = adder ((xb:xc:xd:xe):(yb:yc:yd:ye)) 

I also dont know how to apply xa : adder... which we could do fairly easily if it was a single list. Any ideas how to fix this code? Also, you can replace -20 with anything up to 10 if needed, its just for orientation, since I plan to delete these -20s after the function is applied to the list.

I will want to run function second time on a reversed list, you can see why if you imagine minesweeper where 10s are mines

Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • 2
    I think you make things too hard. Try first to sole the problem for a simple list of `Int`s. Try to work with small patterns. – Willem Van Onsem Nov 12 '19 at 21:42
  • I kinda managed to do it for a single list. However, I need to also add +1 to `Int`s in the next list. – Jakub Kudlej Nov 12 '19 at 21:59
  • take a look at `zipWith`. – Willem Van Onsem Nov 12 '19 at 22:28
  • This can actually work. In a sense, you are creating a gigantic pattern and move it along the minefield. – Ignat Insarov Nov 12 '19 at 22:33
  • I cannot figure out how I should utilize `zipWith`. Could you describe what you have in mind? – Jakub Kudlej Nov 12 '19 at 22:53
  • I honestly tried to write this up, but it gets very messy. The investment of effort to make it right this way is not worth it. – Ignat Insarov Nov 12 '19 at 23:28
  • got an idea, how about spliting the function to two adders where each will work with one list? And conditions in first will affect the second. – Jakub Kudlej Nov 13 '19 at 06:47
  • Can you explain your problem better? `'10':[[...` is not even haskell sintax. Give us a simple example. What whould be the output of `adder [[0, 0, 10, 0, 0]]`? – lsmor Nov 13 '19 at 10:12
  • @lsmor the OP wants to (+1) every cell surrounding every 10 in the input matrix, as in the game minesweeper. – Will Ness Nov 13 '19 at 10:17
  • @WillNess oh!, isn't this kind of the same question as in https://stackoverflow.com/questions/58793029/minesweeper-board-labels-beginner-level Is the same PO but changing the board settup – lsmor Nov 13 '19 at 10:30

2 Answers2

0

I think it's rather easy, as long as the data structure stays as [[Int]]. See the below example:

addIf10 :: Int -> Int
addIf10 x = if x >= 10 then x + 1 else x

-- The first map "unpacks" the list to form an [Int]
-- Second map runs the addIf10 function on the [Int]
adder :: [[Int]] -> [[Int]]
adder = map (map addIf10)
DevNebulae
  • 4,566
  • 3
  • 16
  • 27
0

I see how you arrived at this idea. In a sense, you are creating a gigantic pattern and move it along the minefield. It can work. But it is not an easy way.

adder :: [[Int]] -> [[Int]]
adder [ ] = [ ]
adder [x] = [x]
adder t@[  [_, _],   [_, _]    ] = t
adder   (u@[_, _]: v@[_, _]: us) = u: v: adder us
adder t = afterPass !! 0: adder (afterPass !! 1: us)
  where
    t' = applyHalfStencil t

    (  (x: xs)
     : (y: ys)
     : us
     ) = t'

    xys = [xs, ys]

    afterPass = [x: adder xys !! 0, y: adder xys !! 1]

applyHalfStencil
      s@( (xa: xb: xc: xs)
        : (ya: yb: yc: ys)
        : us
        )
    | xb > 9 =
        ( (xa    : xb    : xc + 1: xs)
        : (ya + 1: yb + 1: yc + 1: ys)
        : us
        )
    | otherwise = s

Of course, you have to also pad your field with -20s above and below. By the way, one layer of -20 is enough. Sample:

sampleInput :: [[Int]]
sampleInput = [ [-20 , -20 , -20 , -20 , -20 , -20]
              , [-20 , 10  , 0   , 0   , 0   , -20]
              , [-20 , 0   , 10  , 10  , 10  , -20]
              , [-20 , 0   , 10  , 0   , 10  , -20]
              , [-20 , 0   , 10  , 10  , 10  , -20]
              , [-20 , -20 , -20 , -20 , -20 , -20] ]

While we are at it, nothing stops us from applying the whole stencil at once, not just the lower right half of it.

adder :: [[Int]] -> [[Int]]
adder [ ] = [ ]
adder [x] = [x]
adder [x, y] = [x, y]
adder t@[  [_, _], _, _    ] = t
adder   (u@[_, _]: v: w: us) = u: v: w: adder us
adder t = afterPass !! 0: adder (afterPass !! 1: afterPass !! 2: us)
  where
    t' = applyStencil t

    (  (x: xs)
     : (y: ys)
     : (z: zs)
     : us
     ) = t'

    xyzs = [xs, ys, zs]

    afterPass = [x: adder xyzs !! 0, y: adder xyzs !! 1, z: adder xyzs !! 2]

applyStencil
      s@( (xa: xb: xc: xs)
        : (ya: yb: yc: ys)
        : (za: zb: zc: zs)
        : us
        )
    | yb > 9 =
        ( (xa + 1: xb + 1: xc + 1: xs)
        : (ya + 1: yb    : yc + 1: ys)
        : (za + 1: zb + 1: zc + 1: zs)
        : us
        )
    | otherwise = s

So, here we are, another solution. It is probably more efficient. It is also good that you put creative force into the problem.


To the future reader, for context: this question and answer continue the line of inquiry started in our previous cooperation with Jakub.

Ignat Insarov
  • 4,660
  • 18
  • 37