2011-04-27 51 views
5

我在F#中创建了一个棋盘(类型)游戏,并且在“功能”方式中遇到了一些麻烦。穿越F#2D阵列

我有一个数组,看起来,例如,像:

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]] 

我想基于上述,创建一个新的数组,其中:

  1. 如果该项目是> 0,然后将新的阵列中应该是多少1
  2. 如果该项目是= 0,则:
    1. 如果向左或向右或高于或低于一个项目是> 1,则在新的ARRA y中的数目应为2
    2. 否则,如果到的右侧或上方或下方左边的项为= 1,则新的数组的数量应为3
    3. 否则,数应为4

这应该创建一个新的阵列,它看起来像:

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]] 

我看不到在实现这一目标的F#什么简单的办法。在C#中,我只是创建了一个for循环来做到这一点,但我认为在F#中使用map函数 - mapi看起来很有前途,但它似乎只能访问当前块在考虑和其指数,而不是整个阵列...

我的问题似乎是游戏的规则是依赖于周边地区,而标准的遍历方法似乎并没有给予周围区域 - 实现我在做什么的最佳方式是什么?

回答

4

我不认为我在这个解决方案中拉扯任何偷偷摸摸的特技。我使用Array2D.init来构建一个新的数组。 init所需的函数确定每个位置的数组值。

此外,我把收集邻居在一个单独的功能。在邻居函数中,我使用列表理解并仅产生有效的邻居,避免了角落和边缘的麻烦。

这是我想出了(警告:当二维数组是1x1的或空它会失败,我要把它留给读者来防止这种情况):

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 
     ) 

测试在F#互动:

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 

结果:

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]] 
+0

这看起来完全像我所需要的,而且看起来更像F#,而不像我创建的那样......虽然我的解决方案非常相似,但我创建了一个全是零的新数组,然后有一个嵌套for循环遍历原始数组。我也没有使用这个列表理解的东西,所以我可能并没有那么接近这个想法...... – 2011-04-27 09:52:23

2

我的一些想法:

阵列旨在通过索引访问。如果您使用数组来存储数据,那么通过索引访问它是最方便的方法。

你想要的是一个元素知道它的邻居在哪里的数据结构。这个数据结构不是一个简单的数组。您可以通过增加一个阵列设计这样的数据结构:

type NArray(A: int [,]) = 
    member x.Item with get (i,j) = (A.[i,j], i, j, A) 

,你也可以明确的四个邻国添加到一个元素:

type NArray(A: int [,]) = 
    let get i j di dj = 
     let newI = i + di 
     let newJ = j + dj 
     if newI < 0 || newI > A.GetLength(0) then None 
     elif newJ < 0 || newJ > A.GetLength(1) then None 
     else Some (A.[newI, newJ]) 

    member x.Item with get (i,j) = (A.[i,j], get i j 0 1, get i j 0 -1, get i j 1 0, get i j -1, 0) 

当你想要一个序列或同样的问题出现清单知道它的邻居。他们被设计不知道。如果列表中的元素知道它的前一个节点,那么它不再是单个链接列表。

当你选择一个数据结构时,你会继承它的优点和它的短小。对于数组,您可以快速建立索引,而其元素本身不具有位置的概念。其他数据结构,如线程二叉树或双链表,它们的元素知道它们在哪里。但成本是更多的存储使用。