2013-05-31 89 views
2

我一直在嘗試使用Chris Pine的「學習編程」一書學習ruby。在閱讀本書之前,我真的很興奮,直到第10章和使用的例子。現在這一章以及它的例子已經完全縮小了我對繼續這本書的興奮。在這個例子中,我完全不知道它如何計算tile,或者爲什麼當方法用continent_size world,x,y的屬性定義時,他使用world [y],[x]?我不知道這個例子中的遞歸是如何工作的。有人能夠對這個例子進一步闡明作者實際上想要做什麼嗎?Chris Pine Ruby ch 10,遞歸

M = 'land' 
o = 'water' 

world = [ 
    [o,o,o,o,o,M,o,o,o,o,o], 
    [o,o,o,o,M,M,o,o,o,o,o], 
    [o,o,o,o,o,M,o,o,M,M,o], 
    [o,o,o,M,o,M,o,o,o,M,o], 
    [o,o,o,o,o,M,M,o,o,o,o], 
    [o,o,o,o,M,M,M,M,o,o,o], 
    [M,M,M,M,M,M,M,M,M,M,M], 
    [o,o,o,M,M,o,M,M,M,o,o], 
    [o,o,o,o,o,o,M,M,o,o,o], 
    [o,M,o,o,o,M,M,o,o,o,o], 
    [o,o,o,o,o,M,o,o,o,o,o]] 

def continent_size world, x ,y 

    if x < 0 or x > 10 or y < 0 or y > 10 
    return 0 
    end 

    if world[y][x] != 'land' 
    return 0 
    end 

    size = 1 
    world [y][x] = 'counted land' 

    size = size + continent_size(world, x-1, y-1) 
    size = size + continent_size(world, x , y-1) 
    size = size + continent_size(world, x+1, y-1) 
    size = size + continent_size(world, x-1, y) 
    size = size + continent_size(world, x+1, y) 
    size = size + continent_size(world, x-1, y+1) 
    size = size + continent_size(world, x , y+1) 
    size = size + continent_size(world, x+1, y+1) 
    size 

end 

puts continent_size(world, 5, 5) 
+0

這個程序和章節只是沒有點擊。我覺得我掌握了遞歸,但看看這段代碼,感到困惑和沮喪。有人可以通過代碼來引導我並解釋發生了什麼嗎? – Ordep81

回答

2

這被稱爲洪水填充。它正在計算連接到初始起點的所有「土地」的大小。請注意,它不包括所有'土地'符號,只是因爲水而無法達到的那些符號。

洪水填充是一種稱爲深度優先搜索的方式,它是一種遍歷圖的方式(這裏是一個離散的'地圖')。它可以概括如下所示:

  1. 訪問的當前位置/圖節點,指望它並將其標記爲已訪問
  2. 檢查所有連接的節點(在這裏,任何事情上,下,左或右),如果他們他們是土地,遞歸訪問他們

他可能會做y,x由於以下原因:二維數組的邏輯格式是先按行,然後按列組織。行可以被認爲是y軸,列是x。

1

當我在書中解決這個問題時,我也注意到當調用世界時,我調用了x &。我查看了Pragmatic Programmer的網站,看看它是否在勘誤表中列出,但事實並非如此。

我認爲這是錯字,並將它們翻轉到x,y。代碼以任何方式工作。

這並不重要,因爲5,5的起始點是任意的,並且代碼將檢查x,y(或y,x)周圍的所有八個圖塊,無論它是否碰到數組的「邊緣」 /世界。

0

從其他答案中回過頭幾步,這裏的遞歸是continent_sizecontinent_size內被調用8次。

所以這個方法在內部被稱爲八次。

但是......這八個內部方法中的每一個都會再撥打continent_size八次。

依此類推,等等。

這是瘋狂的讓你的頭,但當你這樣做,感覺就像你可以看到矩陣。儘管非常簡短。

我偶然發現了這個問題,尋找一些有關任務擴展位的幫助(如果你的「探險家」之一脫離世界的邊緣,如何避免錯誤)。

我結束了救援解決這個:

# If it's off the edge of the world, it's as good as water 
square = world[y][x] rescue 'o' 

if square != 'Land' 
    return 0 
end 

我不知道這是否是做的最好的方式,但它似乎很優雅的我。

+0

雖然你的解決方案在技術上起作用,但如果它是水,你正在取代世界的邊緣,那麼它應該是變量'o',而不是字符''o''。 – amnn

0

我覺得我解決這個問題的方式非常骯髒,並且在這裏尋找更好的答案。我創建了一個新的變量,E =「邊緣」,並且改變了觸摸的地圖的邊緣E.然後,我添加此代碼到continent_size方法的頂部的任意字符:

if world[y][x] == 'edge' 
     return 1 
    end 

它的工作原理。 :/

0

看起來救援方式仍然在世界的頂端是'o's時崩潰。解決此問題的一個簡單方法是編寫一個條件,檢查座標(x,y)是否在邊界之外(即在0或world.length-1之外),如果滿足該條件,則返回0。

0

我還注意到Pine的代碼中x和y的換位。
我認爲可能的原因是他安排了「世界」數組,以便每行有一個子數組。 「世界」(world [0])後的方括號中的第一個數字指的是世界中元素(子數組)的索引。由於這些是垂直堆疊,所以它是你的Y軸。括號內的第二個數字(world [0] [5])指向子數組內的元素。這些水平運行,所以第二個數字是指你的X軸。編寫該方法以獲取參數x,然後參數y允許您以傳統(x,y)格式輸入起始位置,而在該方法中,變量將被轉置以完成任務。我認爲。儘管如此,我完全是新手。

此外,如果任何人有一個乾淨的解決方案,這個練習哪里哪里大陸「毗鄰世界邊緣」的加長版我很想看到它

+0

回答了我自己關於擴展練習的問題。我在方法的頂部添加了一個'if'語句來檢查(x,y)座標是否在「地圖」邊界內。 'if y + 1> world.length || x + 1> world [y] .length return 0 end' – MDJ

0

它也花了一些時間來獲得頭圍繞這個例子。我試圖解決這樣的任務,首先:

if (world[y] > world[y].length || world[x] > world[x].length) || (world[y] < world[y].length || world[x] < world[x].length) 
    return 0 
    end 

但我一直得到「未定義的方法‘的錯誤>’爲數組」

我才明白,該解決方案可以在調節的「x」和「y」,如果它們比一個多陣列(10)或更低(0):

if x > 10 || x < 0 || y > 10 || y < 0 
    return 0 
end 

這裏的問題是,它適用於陣列的這個特定大小...如果世界是大於10 - 該計劃將計算它遇到的每個「土地」爲0.

所以我想這只是一半的解決方案...