'Error with checking for neighbors in 2d array
I am attempting to implement Conway's 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):
liveNeighbors :: ((Int,Int), [[Bool]]) -> (Int,Int) -> Int
liveNeighbors 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 am 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 1. 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.
Solution 1:[1]
There are 2 problems in this code:
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 expectedvariables in patterns: pattern
(_, k)match successfully with other values of(x, y)in your code and patterns below it are overlapped. You just assignktoy, 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)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | SergeyKuz1001 |
