Home > Blockchain >  Error with checking for neighbors in 2d array
Error with checking for neighbors in 2d array

Time:03-21

I am attempting to implement conways game in haskell for class and have code that looks like this for checking for neighbors of a cell (x,y) in a square board of size (w,h):

Neighbors :: ((Int,Int), [[Bool]]) -> (Int,Int) -> Int
Neighbors arr@((w,h), cells) (x,y) = 
let 
    j = w -1
    k = h - 1 
    checkcell (x,y) = if (cells !! y) !! x then 1 else 0 in 
case (x,y) of
-- Check right, bottom, and bottom right
(0,0) -> checkcell (x,y 1)   checkcell (x 1,y)   checkcell (x 1,y 1)
-- Check bottom, left, right, bottom left, bottom right
(_,0) -> checkcell (x,y 1)   checkcell (x-1,y)   checkcell (x 1,y)    checkcell (x 1,y 1)    checkcell (x-1,y 1) 
--check bottom, top, right, top right, bottom right
(0,_) -> checkcell (x,y 1)    checkcell (x,y-1)    checkcell (x 1,y)    checkcell (x 1,y 1)    checkcell (x 1,y-1) 
-- check top, left, right,top left, top right
(_, k) -> checkcell (x,y-1)    checkcell (x-1,y)    checkcell (x 1,y)    checkcell (x-1,y-1)    checkcell (x 1,y-1) 
-- check bottom, top, left, top left, bottom left
(j, _) -> checkcell (x,y 1)    checkcell (x,y-1)    checkcell (x-1,y)    checkcell (x-1,y 1)    checkcell (x-1,y-1) 
--check top, left, top left
(j,k) -> checkcell (x,y-1)    checkcell (x-1,y)    checkcell (x-1,y-1) 
--check bottom, left, bottom left
(j,0) -> checkcell (x,y 1)    checkcell (x-1,y)    checkcell (x-1,y 1) 
-- check top, top right, right
(0,k) -> checkcell (x,y-1)    checkcell (x 1,y-1)    checkcell (x 1,y) 
--check all surrounding 
(_,_) -> checkcell (x,y 1)    checkcell (x,y-1)    checkcell (x 1,y)    checkcell (x-1,y)    checkcell (x 1,y 1)   checkcell (x 1,y-1)    checkcell (x-1,y 1)    checkcell (x-1,y-1) 

I are using j and k to fit for the bounds of the array. I am checking for all edge cases, and corners however the code is failing for array sizes and rows at (_, max_row), (max_column, _), (max_column, max_row) and giving incorrect values. This is the output that ghci is giving me:

> world = ((3,3), [[False, False, False], [False, False, False], [False, True,True]])
> liveNeighbors world (2,2)
*** Exception: Prelude.!!: index too large
> liveNeighbors world (0,2)
*** Exception: Prelude.!!: index too large
> liveNeighbors world (0,1)
1
> liveNeighbors world (1,1)
0

The value for (1,1) should give 2 since the bottom and bottom right are true, however it is only giving a value of one. Any idea why this is happening? I'm not looking for a code solution, if someone could point me in the right direction conceptually on what is going wrong that would be greatly appreciated. This is for a project confining to list processing so no other data structures other than lists or tuples are allowed.

CodePudding user response:

There are 2 problems in this code:

  1. order of patterns: in your example you get error message when test your code for (2,2) position. It is because pattern (_, k) goes earlier than (j, k), so you check "top, left, right,top left, top right", not "top, left, top left" as you expected

  2. variables in patterns: pattern (_, k) match successfully with other values of (x, y) in your code and patterns below it are overlapped. You just assign k to y, not compare them

So, you can write code like this (I use MultiWayIf extension for more similarity with original, but it is just syntax sugar):

{-# LANGUAGE MultiWayIf #-}

neighbors :: ((Int,Int), [[Bool]]) -> (Int,Int) -> Int
neighbors arr@((w,h), cells) (x,y) = 
    let 
        j = w -1
        k = h - 1 
        checkcell (x,y) = if (cells !! y) !! x then 1 else 0 in 
    if
        -- Check right, bottom, and bottom right
        | (x, y) == (0,0) -> checkcell (x,y 1)   checkcell (x 1,y)   checkcell (x 1,y 1)
        --check top, left, top left
        | (x, y) == (j,k) -> checkcell (x,y-1)    checkcell (x-1,y)    checkcell (x-1,y-1) 
        --check bottom, left, bottom left
        | (x, y) == (j,0) -> checkcell (x,y 1)    checkcell (x-1,y)    checkcell (x-1,y 1) 
        -- check top, top right, right
        | (x, y) == (0,k) -> checkcell (x,y-1)    checkcell (x 1,y-1)    checkcell (x 1,y) 
        -- Check bottom, left, right, bottom left, bottom right
        | y == 0 -> checkcell (x,y 1)   checkcell (x-1,y)   checkcell (x 1,y)    checkcell (x 1,y 1)    checkcell (x-1,y 1) 
        --check bottom, top, right, top right, bottom right
        | x == 0 -> checkcell (x,y 1)    checkcell (x,y-1)    checkcell (x 1,y)    checkcell (x 1,y 1)    checkcell (x 1,y-1) 
        -- check top, left, right,top left, top right
        | y == k -> checkcell (x,y-1)    checkcell (x-1,y)    checkcell (x 1,y)    checkcell (x-1,y-1)    checkcell (x 1,y-1) 
        -- check bottom, top, left, top left, bottom left
        | x == j -> checkcell (x,y 1)    checkcell (x,y-1)    checkcell (x-1,y)    checkcell (x-1,y 1)    checkcell (x-1,y-1) 
        --check all surrounding 
        | otherwise -> checkcell (x,y 1)    checkcell (x,y-1)    checkcell (x 1,y)    checkcell (x-1,y)    checkcell (x 1,y 1)   checkcell (x 1,y-1)    checkcell (x-1,y 1)    checkcell (x-1,y-1)
  • Related