I'm creating a board(type) game in F#, and am having a bit of trouble traversing the array in a "functional" way.
I have an array that looks, for example, like:
val myArray : int [,] = [[1; 1; 0; 0; 0]
[0; 0; 1; 0; 0]
[2; 0; 0; 0; 3]
[0; 0; 0; 0; 0]
[0; 1; 0; 0; 1]]
I want to create a new array based on the above, where:
This should create a new array which looks like:
val myArray : int [,] = [[1; 1; 3; 4; 4]
[2; 3; 1; 3; 2]
[1; 2; 3; 2; 1]
[2; 3; 4; 4; 2]
[3; 1; 3; 3; 1]]
I can't see any simple way in F# of achieving this. In C# I'd just create a for
loop to do this, but I thought there might be a sneaky way of doing it in F#, using things like the map
functions - mapi
looked promising but it only seems to give access to the current piece under consideration and its indices, not the entire array...
My issue seems to be that the rules of the game are dependent on the surrounding area, whereas the standard traversal methods don't seem to give access to the surrounding area - what's the best way to achieve what I'm doing?
I don't think I pulled any sneaky stunt in this solution. I used Array2D.init to build a new array. The function required by init determines the array value at each position.
Furthermore, I put gathering the neighbors in a separate function. In the neighbors function I used a list comprehension and yielding only valid neighbors, avoiding troubles around corners and edges.
This is what I came up with (warning: it will fail when the 2D-array is 1x1 or empty, I'll leave it to the reader to guard against this case):
let neighbors r c (A:'a[,]) =
[if r > 0 then yield A.[r-1,c]
if r < Array2D.length1 A - 1 then yield A.[r+1,c]
if c > 0 then yield A.[r,c-1]
if c < Array2D.length2 A - 1 then yield A.[r,c+1]]
let newArray A =
Array2D.init (Array2D.length1 A) (Array2D.length2 A)
(fun r c ->
if A.[r,c] > 0 then 1
else
match neighbors r c A |> List.max with
| 1 -> 3
| 0 -> 4
| _ -> 2
)
Test in F# interactive:
let myArray = array2D [[1; 1; 0; 0; 0]
[0; 0; 1; 0; 0]
[2; 0; 0; 0; 3]
[0; 0; 0; 0; 0]
[0; 1; 0; 0; 1]]
let result = newArray myArray
result:
val result : int [,] = [[1; 1; 3; 4; 4]
[2; 3; 1; 3; 2]
[1; 2; 3; 2; 1]
[2; 3; 4; 4; 2]
[3; 1; 3; 3; 1]]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With