2011-04-27 46 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) 

當你想要一個序列或同樣的問題出現清單知道它的鄰居。他們被設計不知道。如果列表中的元素知道它的前一個節點,那麼它不再是單個鏈接列表。

當你選擇一個數據結構時,你會繼承它的優點和它的短小。對於數組,您可以快速建立索引,而其元素本身不具有位置的概念。其他數據結構,如線程二叉樹或雙鏈表,它們的元素知道它們在哪裏。但成本是更多的存儲使用。