楼主: AlexQin

《 笨方法學 Ruby 》(Learn Ruby The Hard Way)

[复制链接]
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
41#
 楼主| 发表于 2013-11-20 09:22 | 只看该作者
習題 32: 迴圈和陣列

現在你應該有能力寫更有趣的程式出來了。如果你能夠一直跟得上,你應該已意識到你能將之前學到的將 if 語句 和 「布林表示式」這些東西結合起來,讓程式做出一些聰明的事了。

然而,我們的城市還需要能很快地完成重複的事情。這節習題中我們將使用 for-loop (for 迴圈) 來建立和印出各式的陣列。在做習題的過程中,你將會逐漸搞懂它們是怎麼回事。現在我不會告訴你,你需要自己找到答案。

在你開始使用 for 迴圈之前,你需要在某個位置存放迴圈的結果。最後的方法是使用陣列 array。一個陣列,就是一個按照順序存放東西的容器。陣列並不複雜,你只是要學習一點新的語法。首先我們來看看如何建立一個陣列:

  1. hairs = ['brown', 'blond', 'red']
  2. eyes = ['brown', 'blue', 'green']
  3. weights = [1, 2, 3, 4]
复制代码

你要做的是以 [ 左中括號開頭「打開」陣列,然後寫下你要放入陣列的東西、用逗號 , 隔開,就跟函式的參數一樣,最後你需要用 ] 右中括號結束陣列的定義。然後 Ruby 接收這個陣列以及裡面所有的內容,將其賦予給一個變數。

Warning: 對於不會寫程式的人來說這是一個困難點。習慣性思維告訴你的大腦大地是平的。記得上一個練習中的巢狀 if 語句吧,你可能覺得要理解它有些難度,因為生活中一般人不會去想這樣的問題,但這樣的問題在程式中幾乎到處都是。你會看到一個函式呼叫用另外一個包含 if 語句的函式,其中又有巢狀陣列的陣列。如果你看到這樣的東西一時無法弄懂,就用紙筆記下來,手動分割下去,直到弄懂為止。

現在我們將使用迴圈建立一些陣列,然後將它們印出來:

  1. the_count = [1, 2, 3, 4, 5]
  2. fruits = ['apples', 'oranges', 'pears', 'apricots']
  3. change = [1, 'pennies', 2, 'dimes', 3, 'quarters']

  4. # this first kind of for-loop goes through an array
  5. for number in the_count
  6.   puts "This is count #{number}"
  7. end

  8. # same as above, but using a block instead
  9. fruits.each do |fruit|
  10.   puts "A fruit of type: #{fruit}"
  11. end

  12. # also we can go through mixed arrays too
  13. for i in change
  14.   puts "I got #{i}"
  15. end

  16. # we can also build arrays, first start with an empty one
  17. elements = []

  18. # then use a range object to do 0 to 5 counts
  19. for i in (0..5)
  20.   puts "Adding #{i} to the list."
  21.   # push is a function that arrays understand
  22.   elements.push(i)
  23. end

  24. # now we can puts them out too
  25. for i in elements
  26.   puts "Element was: #{i}"
  27. end
复制代码

你應該看到的結果

  1. $ ruby ex32.rb
  2. This is count 1
  3. This is count 2
  4. This is count 3
  5. This is count 4
  6. This is count 5
  7. A fruit of type: apples
  8. A fruit of type: oranges
  9. A fruit of type: pears
  10. A fruit of type: apricots
  11. I got 1
  12. I got 'pennies'
  13. I got 2
  14. I got 'dimes'
  15. I got 3
  16. I got 'quarters'
  17. Adding 0 to the list.
  18. Adding 1 to the list.
  19. Adding 2 to the list.
  20. Adding 3 to the list.
  21. Adding 4 to the list.
  22. Adding 5 to the list.
  23. Element was: 0
  24. Element was: 1
  25. Element was: 2
  26. Element was: 3
  27. Element was: 4
  28. Element was: 5
  29. $
复制代码

加分習題

  • 注意一下 range (0..5)。查一下 Range class (類別) 並弄懂它。
  • 在第 24 行,你可以直接將 elements 賦值為 (0..5),而不需使用 for 迴圈嗎?
  • 在 Ruby 文件中可以找到關於陣列的內容,仔細閱讀一下,除了 push 以外,陣列還支援那些操作?

使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
42#
 楼主| 发表于 2013-11-20 09:25 | 只看该作者

習題 33: While 迴圈

接下來是一個更在你意料之外的概念:while-loop(while迴圈)。while 迴圈會一直執行它下面的程式碼區段,直到它對應的布林表示式為 false 才會停下來。

等等,你還能跟的上這些術語吧?如果我們寫了這樣一個語句:if items > 5 或者是 for fruit in fruits,那就是在開始一個程式碼區段 (code block),新的程式碼區段是需要被縮排的,最後再以 end 語句結尾。只有將程式碼用這樣的方式格式化,Ruby 才能知道你的目的。如果你不太明白這一點,就回去看看 「if 語句」、「函式」和「for 迴圈」章節,直到你明白為止。

接下來的店席將訓練你的大腦去閱讀這些結構化的與集,這和我們將布林表示式燒錄到你的大腦中的過程有點類似。

回到 while 迴圈,它所作的和 if 語句類似,也是去檢查一個布林表示式的真假,不一樣的是它下面的程式碼區段不是只被執行一次,而是執行完後再趟回到 while 所在的位置,如此重複進行,直到 while 表示式為 false 為止。

while 迴圈有一個問題:那就是有時它會永不結束。如果你的目的是循環到宇宙毀滅為止,那這樣也挺好的,不過其他的情況下你的迴總需要有一個結束點。

為了避免這樣的問題,你需要遵循下面的規定:

  • 盡量少用 while 迴圈,大部分時候 for 迴圈是更好的選擇。
  • 重複檢查你的 while 語句,確定你測試的布林表示式最終會變成 false。
  • 如果不確定,就在 while 迴圈的結尾印出你要測試的值。看看它的變化。

在這節練習中,你將通過上面的三樣事情學會 while 迴圈:

  1. i = 0
  2. numbers = []

  3. while i < 6
  4.   puts "At the top i is #{i}"
  5.   numbers.push(i)

  6.   i = i + 1
  7.   puts "Numbers now: #{numbers}"
  8.   puts "At the bottom i is #{i}"
  9. end

  10. puts "The numbers: "

  11. for num in numbers
  12.   puts num
  13. end
复制代码

你應該看到的結果

  1. $ ruby ex33.rb
  2. At the top i is 0
  3. Numbers now:  [0]
  4. At the bottom i is 1
  5. At the top i is 1
  6. Numbers now:  [0, 1]
  7. At the bottom i is 2
  8. At the top i is 2
  9. Numbers now:  [0, 1, 2]
  10. At the bottom i is 3
  11. At the top i is 3
  12. Numbers now:  [0, 1, 2, 3]
  13. At the bottom i is 4
  14. At the top i is 4
  15. Numbers now:  [0, 1, 2, 3, 4]
  16. At the bottom i is 5
  17. At the top i is 5
  18. Numbers now:  [0, 1, 2, 3, 4, 5]
  19. At the bottom i is 6
  20. The numbers:
  21. 0
  22. 1
  23. 2
  24. 3
  25. 4
  26. 5
复制代码

加分習題

  • 將這個 while 迴圈改成一個函式,將測試條件 (i < 6)中的 6 換成一個變數。
  • 使用這個函式重寫你的腳本,並使用不同的數字進行測試。
  • 為函式添加另一個參數,這個參數用來定義第 8 行的 +1,這樣你就可以讓它任意加值了。
  • 再使用該函式重寫一遍這個腳本。看看效果如何。
  • 接下來使用 for 迴圈和 range 把這個腳本再寫一遍。你還需要中間的加值操作嗎?如果你不去掉它,會有什麼樣的結果?


有可能你會碰到程序跑著停不下來了,這時你只要按著 CTRL 再敲 c (CTRL-c),這樣程式就會中斷下來了。

使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
43#
 楼主| 发表于 2013-11-20 10:51 | 只看该作者
習題 34: 存取陣列裡的元素

陣列非常有用,但只有你存取裡面的內容時,它才能發揮出作用來。你已經學會了案順序讀出陣列中的內容,但如果你要得到第 5 個元素該怎麼辦呢?你需要知道如何存取陣列中的元素。存取第一個元素的方法是這樣的:

  1. animals = ['bear', 'tiger', 'penguin', 'zebra']
  2. bear = animals[0]
复制代码

你定義一個 animals 的陣列,然後你用 0 來存取第一個元素!?這是怎麼回事啊?因為數學裡面就是這樣,所以 Ruby 的陣列也是從 0 開始的。雖然看起來很奇怪,這樣定義其實有它的好處。

最好的解釋方式勢將你平常使用數字的方式和程式設計師使用數字的方式做比較。

假設你在觀看上面陣列中的四種動物:(['bear', 'tiger', 'penguin', 'zebra']) 的賽跑。而它們比賽的名次正好跟陣列中的順樹一樣。這是一場很刺激的比賽,因為這些動物沒打算吃掉對方,而且比賽還真的舉辦起來了。結果你的朋友來晚了,他想知道誰贏了比賽,他會問你「嘿,誰是第 0 名?」嗎?不會的,他會問「嘿,誰是第 1 名?」

這是因為動物的次序是很重要的。沒有第一個就沒有第二個,沒有第二個話也不會有第三個。第零個是不存在的,因為零的意思是什麼都沒有。「什麼都沒有」怎麼贏比賽嘛?完全不和邏輯。這樣的數字我們稱之為「序數(ordinal number)」

而程式設計師不能用這種方式思考問題,因為他們可以從陣列中的任何一個位置取出一個元素來。對程式設計師來說,上述的陣列更像是一疊卡片。如果他們想要 tiger,就抓它出來,如果想要 zeebra,也一樣抓出來。要隨機地抓陣列裡的內容,陣列的每一個元素都應該要有一個地址(address),或者一個「索引(index)」,而最好的方式就是使用以 0 開頭的索引。相信我說的這一點吧,這種方式獲取元素會更容易。而這一類的數字被稱為「基數(cardinal number)」,它意味著你可以任意抓取元素,所以我們需要一個 0 號元素。

那麼,這些知識對你的陣列操作有什麼幫助呢?很簡單,每次你對自己說:「我要第 3 隻動物」時,你需要將「序數」轉換成「基數」,只要將前者減 1 就可以了。第 3 隻動物的索引是 2,也就是 penguin。由於你一輩子都在跟序數打交道,所以你需要這種方式來獲得基數,只要減 1 就都搞定了。

記住:ordinal == 有序,以 1 開始;cardinal == 隨機存取,以 0 開始。

讓我們練習一下。定義一個動物列表,然後跟著做後面的習題,你需要寫出所指位置的動物名稱。如果我用的是「first」、「second」等說法。那說明我用的是敘述,所以你需要減去 1。如果我給你的是基數 ( 0, 1, 2 ),你只要直接使用即可。

  1. animals = ['bear', 'python', 'peacock', 'kangaroo', 'whale', 'platypus']
复制代码

The animal at 1. The 3rd animal. The 1st animal. The animal at 3. The 5th animal. The animal at 2. The 6th animal. The animal at 4.

對於上述某一條,以這樣的格式寫出一個完整的句子:「The 1st animal is at 0 and is a bear.」然後倒過來念「 “The animal at 0 is the 1st animal and is a bear.」

使用 IRB 去檢查你的答案。

Hint: Ruby 還有一些便利的 method 是屬於在陣列中存取特定元素的用法。:animals.first 和 animals.last。

加分習題

  • 上網搜尋一下關於 序數 (ordinal number) 和基數 (cardinal number) 的知識並閱讀一下。
  • 以你對於這些數字類型的了解,解釋一下為什麼今年是 2010 年。呢是:你不能隨便挑選年份。
  • 再寫一些陣列,用一樣的方式做出索引,確認自己可以在兩種數字之間互相翻譯。
  • 使用 IRB 檢查自己的答案。


Warning: 會有程式設計師告訴你,叫你去閱讀一個叫「Dijkstra」的人寫的關於數字的主題。我建議你還是不讀為妙,除非你喜歡聽一個在寫程式這一行剛興起時就停止了從事寫程式工作的人對你大吼大叫。

使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
44#
 楼主| 发表于 2013-11-20 10:58 | 只看该作者
習題 35: 分支 (Branches) 和函式 (Functions)

你已經學會了 if 語句、函式、還有陣列。現在你要練習扭轉一下思維了。把下面的代碼寫下來,看你是否能弄懂它實現的是什麼功能。

  1. def prompt()
  2.   print "> "
  3. end

  4. def gold_room()
  5.   puts "This room is full of gold.  How much do you take?"

  6.   prompt; next_move = gets.chomp
  7.   if next_move.include? "0" or next_move.include? "1"
  8.     how_much = next_move.to_i()
  9.   else
  10.     dead("Man, learn to type a number.")
  11.   end

  12.   if how_much < 50
  13.     puts "Nice, you're not greedy, you win!"
  14.     Process.exit(0)
  15.   else
  16.     dead("You greedy bastard!")
  17.   end
  18. end


  19. def bear_room()
  20.   puts "There is a bear here."
  21.   puts "The bear has a bunch of honey."
  22.   puts "The fat bear is in front of another door."
  23.   puts "How are you going to move the bear?"
  24.   bear_moved = false

  25.   while true
  26.     prompt; next_move = gets.chomp

  27.     if next_move == "take honey"
  28.       dead("The bear looks at you then slaps your face off.")
  29.     elsif next_move == "taunt bear" and not bear_moved
  30.       puts "The bear has moved from the door. You can go through it now."
  31.       bear_moved = true
  32.     elsif next_move == "taunt bear" and bear_moved
  33.       dead("The bear gets pissed off and chews your leg off.")
  34.     elsif next_move == "open door" and bear_moved
  35.       gold_room()
  36.     else
  37.       puts "I got no idea what that means."
  38.     end
  39.   end
  40. end

  41. def cthulu_room()
  42.   puts "Here you see the great evil Cthulu."
  43.   puts "He, it, whatever stares at you and you go insane."
  44.   puts "Do you flee for your life or eat your head?"

  45.   prompt; next_move = gets.chomp

  46.   if next_move.include? "flee"
  47.     start()
  48.   elsif next_move.include? "head"
  49.     dead("Well that was tasty!")
  50.   else
  51.     cthulu_room()
  52.   end
  53. end

  54. def dead(why)
  55.   puts "#{why}  Good job!"
  56.   Process.exit(0)
  57. end

  58. def start()
  59.   puts "You are in a dark room."
  60.   puts "There is a door to your right and left."
  61.   puts "Which one do you take?"

  62.   prompt; next_move = gets.chomp

  63.   if next_move == "left"
  64.     bear_room()
  65.   elsif next_move == "right"
  66.     cthulu_room()
  67.   else
  68.     dead("You stumble around the room until you starve.")
  69.   end
  70. end

  71. start()
复制代码

你應該看到的結果

你可以結果:

  1. $ ruby ex35.rb
  2. You are in a dark room.
  3. There is a door to your right and left.
  4. Which one do you take?
  5. > left
  6. There is a bear here.
  7. The bear has a bunch of honey.
  8. The fat bear is in front of another door.
  9. How are you going to move the bear?
  10. > taunt bear
  11. The bear has moved from the door. You can go through it now.
  12. > open door
  13. This room is full of gold.  How much do you take?
  14. > asf
  15. Man, learn to type a number. Good job!
  16. $
复制代码

加分習題

  • 把這個遊戲的地圖畫出來,把自己的路線也畫出來。
  • 改正你所有的錯誤,包括拼寫錯誤。
  • 為你不懂的函式寫註解。記得 RDoc 中的註釋嗎?
  • 為遊戲添加更多元素。通過怎樣的方式可以簡化並且擴充遊戲的功能呢?
  • 這個 gold_room 遊戲使用了奇怪的方式讓你鍵入一個數字。這種方式會導致什麼樣的bug?你可以用比檢查 0、1更好的方式判斷輸入是否是數字嗎? to_i() 這個函式可以給你一些頭緒。

使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
45#
 楼主| 发表于 2013-11-21 10:02 | 只看该作者
習題 36: 設計和測試

現在你已經學會了「if 語句」,我將給你一些使用 for 迴圈和 while 迴圈的規則,一面你日後碰到麻煩。我還會教你一些測試的小技巧,以便你能發現自己程式的問題。最後,你將需要設計一個和上節類似的小遊戲,不過內容略有更改。

If 語句的規則

1.每一個「if語句」必伴隨須一個 else。 2. 如果這個 else 因為沒有意義,而永遠都沒被執行到,那你必須在 else 語句後面使用一個叫 die 的函式,讓它印出錯誤並死給你看,這和上一節的習題類似,這樣你可以找到很多的錯誤。 3. 千萬不要使用超過兩層的 if 語句,最好盡量保持只有 1 層。那你就需要把第二個 if 移到另一個函式裡面。 4. 將if語句當做段落來對待,其中的每一個 if、elsif、else組合就跟 一個段落的句子組合一樣。在這種組合的最前面和最後面留一個空行以作區分。 5. 你的布林測試應該很簡單,如果它們很複雜的話,你需要將它們的運算式先放到一個變數裡,並且為變數取一個好名字。

如果你遵循上面的規則,你就會寫出比大部分程式設計師都好的程式碼來。回到上一個練習中,看看我有沒有遵循這些規則,如果沒有的話,就將其改正過來。

Warning: 在日常寫程式中不要成為這些規則的奴隸。在訓練中,你需要通過這些規則的應用來鞏固你學到的知識,而在實際寫程式中這些規則有時其實很蠢。如果你覺得哪個規則很蠢,就別使用它。

Rules For Loops

只有在迴圈循環永不停止時使用 while 迴圈,這意味著你可能永遠都用不到。這條只有 Ruby 中成立,其他的語言另當別論。
其他類型的迴圈都使用 for 迴圈,尤其是在迴圈的對象數量固定或者有限的情況下。

除錯(Debug) 的小技巧

不要使用「debugger」。Debugger 所作的相當於對病人的全身掃描。你並不會得到某方面的有用資訊,而且你會發現它輸出的資訊太多,而且大部分沒有用,或者只會讓你更困惑。
最好的除錯技巧是使用 puts 或 p 在各個你想要檢查的關鍵環節將關鍵變數印出來,從而檢查哪裡是否有錯。
讓程式一部分一部分地運行起來。不要等一個很長的腳本寫完後才去運行它。寫一點,運行一點,再修改一點。


家庭作業

寫一個和上節練習類似的遊戲。同類的任何題材的遊戲都可以,花一個星期讓它盡可能有趣一些。作為加分習題,你可以盡量多使用陣列、函式、以及模組(記得習題 13 嗎?),而且盡量多弄一些新的 Ruby 程式讓你的遊戲跑起來。

過有一點需要注意,你應該把遊戲的設計先寫出來。在你開始寫程式碼之前,你應該設計出遊戲的地圖,創建出玩家會碰到的房間、怪物、以及陷阱等環節。

一旦搞定了地圖,你就可以寫寫程式碼了。如果你發現地圖有問題,就調整一下地圖,讓寫程式碼和地圖互相符合。

最後一個建議:每一個程式設計師在開始一個新的大項目時,都會被非理性的恐懼影響到。為了避免這種恐懼,他們會拖延時間,到最後一事無成。我有時會這樣,每個人都會有這樣的經歷,避免這種情況的最好的方法是把自己要做的事情列出來,一次完成一樣。

開始做吧。先做一個小一點的版本,擴充它讓它變大,把自己要完成的事情一一列出來,然後逐個完成就可以了。


使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
46#
 楼主| 发表于 2013-11-21 10:04 | 只看该作者
習題 37: 複習各種符號

現在該複習你學過的符號和 Ruby 關鍵字了,而且你在本節還會學到一些新的東西。我在這裡所作的是將所有的 Ruby 符號和關鍵字列出來,這些都是值得掌握的重點。

在這節課中,你需要複習每一個關鍵字,從記憶中想起它的作用並且寫下來,接著上網搜索它真正的功能。有些內容可能是無法搜索的,所以這對你可能有些難度,不過你還是需要堅持嘗試。

如果你發現記憶中的內容有誤,就在索引卡片上寫下正確的定義,試著將自己的記憶糾正過來。如果你就是不知道它的定義,就把它也直接寫下來,以後再做研究。

最後,將每一種符號和關鍵字用在程式裡,你可以用一個小程式來做,也可以盡量多寫一些程式來鞏固記憶。這裡的關鍵點是明白各個符號的作用,確認自己沒搞錯,如果搞錯了就糾正過來,然後將其用在程序裡,並且通過這樣的方式鞏固自己的記憶。

Keywords(關鍵字)

  • alias
  • and
  • BEGIN
  • begin
  • break
  • case
  • class
  • def
  • defined?
  • do
  • else
  • elsif
  • END
  • end
  • ensure
  • false
  • for
  • if
  • in
  • module
  • next
  • nil
  • not
  • or
  • redo
  • rescue
  • retry
  • return
  • self
  • super
  • then
  • true
  • undef
  • unless
  • until
  • when
  • while
  • yield

資料類型

針對每一種資料類型,都舉出一些例子來,例如針對 string,你可以舉出一些字。針對number,你可以舉出一些數字。

  • true
  • false
  • nil
  • constants
  • strings
  • numbers
  • ranges
  • arrays
  • hashes


字串格式(String Formats)

一樣的,在字符串中使用它們,確認它們的功能。

  • \\
  • \'
  • \"
  • \a
  • \b
  • \f
  • \n
  • \r
  • \t
  • \v


Operators

有些操作符號你可能還不熟悉,不過還是一一看過去,研究一下它們的功能,如果你研究不出來也沒關係,記錄下來日後解決。

  • ::
  • []
  • **
  • -(unary)
  • +(unary)
  • !
  • ~
  • *
  • /
  • %
  • +
  • -
  • <<
  • >>
  • &
  • |
  • >
  • >=
  • <
  • <=
  • <=>
  • ==
  • ===
  • !=
  • =~
  • !~
  • &&
  • ||
  • ..
  • ...


花一個星期學習這些東西,如果你能提前完成就更好了。我們的目的是覆蓋到所有的符號類型,確認你已經牢牢記住它們。另外很重要的一點是這樣你可以找出自己還不知道哪些東西,為自己日後學習找到一些方向。

使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
47#
 楼主| 发表于 2013-11-21 10:05 | 只看该作者
習題 38: 閱讀程式碼

現在去找一些 Ruby 程式碼閱讀一下。你需要自己找程式碼,然後從中學習一些東西。你學到的東西已經足夠讓你看懂一些程式碼了,但你可能還無法理解這些程式碼的功能。這節課我要教給你的是:如何運用你學到的東西理解別人的程式碼。

首先把你想要理解的程式碼印到紙上。沒錯,你需要印出來,因為和螢幕輸出相比,你的眼睛和大腦更習慣於接受紙質列印的內容。一次最多列印幾頁就可以了。

然後通讀你列印出來的代碼並做好標記,標記的內容包括以下幾個方面:

  • 函數以及函數的功能。
  • 每個變數的初始賦值。
  • 每個在程式的各個部分中多次出現的變數。它們以後可能會給你帶來麻煩。
  • 任何不包含else的 if 語句。它們是正確的嗎?
  • 任何可能沒有結束點的while循環。
  • 最後一條,代碼中任何你看不懂的部分都記下來。


接下來你需要通過註解的方式向自己解釋程式碼的含義。解釋各個函式的使用方法,各個變數的用途,以及任何其它方面的內容,只要能幫助你理解程式碼即可。

最後,在程式碼中比較難的各個部分,逐行或者逐個函式跟踪變數值。你可以再打印一份出來,在空白處寫出你要「追踪」的每個變數的值。

一旦你基本理解了程式碼的功能,回到電腦面前,在程式碼上重讀一次,看看能不能找到新的問題點。然後繼續找新的程式碼,用上述的方法去閱讀理解,直到你不再需要紙質列印為止。

加分習題

  • 研究一下什麼是「流程圖(flow chart)」,並學著畫一下。
  • 如果你在讀程式碼的時候找出了錯誤,試著把它們改對,並把修改內容發給作者。
  • 不使用紙質打印時,你可以使用註解符號#在程序中加入筆記。有時這些筆記會對後來的讀程式碼的人有很大的幫助。

使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
48#
 楼主| 发表于 2013-11-21 10:07 | 只看该作者
習題 39: 陣列的操作

你已經學過了陣列。在你學習“while 迴圈的時候,你對陣列進行過「pushed」動作,而且將陣列的內容印了出來。另外你應該還在加分習題裡研究過 Ruby 文件,看了陣列支援的其他操作。這已經是一段時間以前了,所以如果你不記得了的話,就回到本書的前面再複習一遍吧。

找到了嗎?還記得嗎?很好。那時候你對一個陣列執行了 push 函式。不過,你也許還沒有真正明白發生的事情,所以我們再來看看我們可以對陣列進行什麼樣的操作。

當你看到像 mystuff.append('hello')這樣的程式時,你事實上已經在 Ruby 內部激發了一個連鎖反應。以下是它的運作原理:

  • Ruby 看到你用到了 mystuff,於是就去找到這個變數。也許它需要倒著檢查看你有沒有在哪裡用 = 建立過這個變數,或者檢查它是不是一個函式參數,或者看它是不是一個全局變數。不管哪種方式,它得先找到 mystuff 這個變數才行。
  • 一旦它找到了 mystuff,就輪到處理句點 . (period)這個操作符號,而且開始查看 mystuff 內部的一些變數了。由於 mystuff 是一個陣列,Ruby 知道 mystuff 支援一些函式。
  • 接下來輪到了處理 push。Ruby會將 「push」和 mystuff 支援的所有函式的名稱一一對比,如果確實其中有一個叫 push 的函式,那麼Ruby就會去使用這個函式。
  • 接下來Ruby看到了括號(parenthesis)並且意識到, 「噢,原來這應該是一個函式」,到了這裡,它就正常會呼叫這個函式了,不過這裡的函式還要多一個參數才行。


一下子要消化這麼多可能有點難度,不過我們將做幾個練習,讓你頭腦中有一個深刻的印象。下面的練習將字符串和列表混在一起,看看你能不能在裡邊找出點樂子來:

  1. ten_things = "Apples Oranges Crows Telephone Light Sugar"

  2. puts "Wait there's not 10 things in that list, let's fix that."

  3. stuff = ten_things.split(' ')
  4. more_stuff = %w(Day Night Song Frisbee Corn Banana Girl Boy)

  5. while stuff.length != 10
  6.   next_one = more_stuff.pop()
  7.   puts "Adding: #{next_one}"
  8.   stuff.push(next_one)
  9.   puts "There's #{stuff.length} items now."
  10. end

  11. puts "There we go: #{stuff}"

  12. puts "Let's do some things with stuff."

  13. puts stuff[1]
  14. puts stuff[-1] # whoa! fancy
  15. puts stuff.pop()
  16. puts stuff.join(' ') # what? cool!
  17. puts stuff.values_at(3,5).join('#') # super stellar!
复制代码

你應該看到的結果

  1. $ ruby ex39.rb
  2. Wait there's not 10 things in that list, let's fix that.
  3. Adding: Boy
  4. There's 7 items now.
  5. Adding: Girl
  6. There's 8 items now.
  7. Adding: Banana
  8. There's 9 items now.
  9. Adding: Corn
  10. There's 10 items now.
  11. There we go: ["Apples", "Oranges", "Crows", "Telephone", "Light", "Sugar", "Boy", "Girl", "Banana", "Corn"]
  12. Let's do some things with stuff.
  13. Oranges
  14. Corn
  15. Corn
  16. Apples Oranges Crows Telephone Light Sugar Boy Girl Banana
  17. Telephone#Sugar
  18. $
复制代码

加分習題

  • 上網閱讀一些關於「物件導向程式(Object Oriented Programming)」的資料。暈了吧?嗯,我以前也是。別擔心。你將從這本書學到足夠用的關於物件導向程式的基礎知識,而以後你還可以慢慢學到更多。
  • something.methods 和 something的 class 有什麼關係?
  • 如果你不知道我講的是些什麼東西,別擔心。程式設計師為了顯得自己聰明,於是就發明了Opject Oriented Programming,簡稱為OOP,然後他們就開始濫用這個東西了。如果你覺得這東西太難,你可以開始學一下「函式式程式(functional programming)」。

使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
49#
 楼主| 发表于 2013-11-21 10:09 | 只看该作者
習題 40: Hash, 可愛的 Hash

接下來我要教你另外一種讓你傷腦筋的容器型資料結構,因為一旦你學會這種資料結構,你將擁有超酷的能力。這是最有用的容器:Hash。

Ruby 將這種資料類型叫做「Hash」,有的語言裡它的名稱是「dictionaries」。這兩種名字我都會用到,不過這並不重要,重要的是它們和陣列的區別。你看,針對陣列你可以做這樣的事情:

  1. ruby-1.9.2-p180 :015 > things = ['a','b','c','d']
  2. => ["a", "b", "c", "d"]
  3. ruby-1.9.2-p180 :016 > print things[1]
  4. b => nil
  5. ruby-1.9.2-p180 :017 > things[1] = 'z'
  6. => "z"
  7. ruby-1.9.2-p180 :018 > print things[1]
  8. z => nil
  9. ruby-1.9.2-p180 :019 > print things
  10. ["a", "z", "c", "d"] => nil
  11. ruby-1.9.2-p180 :020 >
复制代码

你可以使用數字作為陣列的「索引」,也就是你可以通過數字找到陣列中的元素。而 Hash 所作的,是讓你可以通過任何東西找到元素,不只是數字。是的,Hash 可以將一個物件和另外一個東西關聯,不管它們的類型是什麼,我們來看看:

  1. ruby-1.9.2-p180 :001 > stuff = {:name => "Rob", :age => 30, :height => 5*12+10}
  2. => {:name=>"Rob", :age=>30, :height=>70}
  3. ruby-1.9.2-p180 :002 > puts stuff[:name]
  4. Rob
  5. => nil
  6. ruby-1.9.2-p180 :003 > puts stuff[:age]
  7. 30
  8. => nil
  9. ruby-1.9.2-p180 :004 > puts stuff[:height]
  10. 70
  11. => nil
  12. ruby-1.9.2-p180 :005 > stuff[:city] = "New York"
  13. => "New York"
  14. ruby-1.9.2-p180 :006 > puts stuff[:city]
  15. New York
  16. => nil
  17. ruby-1.9.2-p180 :007 >
复制代码

你將看到除了通過數字以外,我們在 Ruby 還可以用字串來從 Hash 中獲取 stuff,我們還可以用字串來往 Hash 中添加元素。當然它支持的不只有字串,我們還可以做這樣的事情:

  1. ruby-1.9.2-p180 :004 > stuff[1] = "Wow"
  2. => "Wow"
  3. ruby-1.9.2-p180 :005 > stuff[2] = "Neato"
  4. => "Neato"
  5. ruby-1.9.2-p180 :006 > puts stuff[1]
  6. Wow
  7. => nil
  8. ruby-1.9.2-p180 :007 > puts stuff[2]
  9. Neato
  10. => nil
  11. ruby-1.9.2-p180 :008 > puts stuff
  12. {:name=>"Rob", :age=>30, :height=>70, :city=>"New York", 1=>"Wow", 2=>"Neato"}
  13. => nil
  14. ruby-1.9.2-p180 :009 >
复制代码

在這裡我使用了數字。其實我可以使用任何東西,不過這麼說並不准確,不過你先這麼理解就行了。

當然了,一個只能放東西進去的 Hash是沒啥意思的,所以我們還要有刪除物件的方法,也就是使用 delete 這個關鍵字:

  1. ruby-1.9.2-p180 :009 > stuff.delete(:city)
  2. => "New York"
  3. ruby-1.9.2-p180 :010 > stuff.delete(1)
  4. => "Wow"
  5. ruby-1.9.2-p180 :011 > stuff.delete(2)
  6. => "Neato"
  7. ruby-1.9.2-p180 :012 > stuff
  8. => {:name=>"Rob", :age=>30, :height=>70}
  9. ruby-1.9.2-p180 :013 >
复制代码

接下來我們要做一個練習,你必須「非常」仔細,我要求你將這個練習寫下來,然後試著弄懂它做了些什麼。這個練習很有趣,做完以後你可能會有豁然開朗的感覺。

  1. cities = {'CA' => 'San Francisco',
  2.   'MI' => 'Detroit',
  3.   'FL' => 'Jacksonville'}

  4. cities['NY'] = 'New York'
  5. cities['OR'] = 'Portland'

  6. def find_city(map, state)
  7.   if map.include? state
  8.     return map[state]
  9.   else
  10.     return "Not found."
  11.   end
  12. end

  13. # ok pay attention!
  14. cities[:find] = method(:find_city)

  15. while true
  16.   print "State? (ENTER to quit) "
  17.   state = gets.chomp

  18.   break if state.empty?

  19.   # this line is the most important ever! study!
  20.   puts cities[:find].call(cities, state)
  21. end
复制代码

你應該看到的結果

  1. $ ruby ex40.rb
  2. State? (ENTER to quit) > CA
  3. San Francisco
  4. State? (ENTER to quit) > FL
  5. Jacksonville
  6. State? (ENTER to quit) > O
  7. Not found.
  8. State? (ENTER to quit) > OR
  9. Portland
  10. State? (ENTER to quit) > VT
  11. Not found.
  12. State? (ENTER to quit) >
复制代码

加分習題

  • 在 Ruby 文件中找到 Hash 相關的內容,學著對 Hash 做更多的操作。
  • 找出一些 Hash 無法做到的事情。例如比較重要的一個就是 Hash 的內容是無序的,你可以檢查一下看看是否真是這樣。
  • 試著把 for 迴圈執行到 Hash 上面,然後試著在 for 迴圈中使用 Hash 的 each 函式,看看會有什麼樣的結果。

使用道具 举报

回复
论坛徽章:
1056
紫蜘蛛
日期:2015-09-22 15:53:22紫蜘蛛
日期:2015-10-15 13:48:52紫蜘蛛
日期:2015-10-15 14:45:48紫蜘蛛
日期:2015-10-15 14:47:47紫蜘蛛
日期:2015-10-15 14:48:45九尾狐狸
日期:2015-09-22 15:53:22九尾狐狸
日期:2015-10-15 13:50:37九尾狐狸
日期:2015-10-15 14:45:48九尾狐狸
日期:2015-10-15 14:47:47九尾狐狸
日期:2015-10-15 14:48:45
50#
 楼主| 发表于 2013-11-22 09:10 | 只看该作者
習題 41: 來自 Percal 25 號行星的哥頓人(Gothons)

你在上一節中發現 Hash 的秘密功能了嗎?你可以解釋給自己嗎?讓我來給你解釋一下,順便和你自己的理解對比看有什麼不同。這裡是我們要討論的程式碼:

  1. cities[:find] = method(:find_city)
  2. puts cities[:find].call(cities, state)
复制代码

你要記住一個函式也可以作為一個變數,為了要將一個程式碼區段儲存在一個變數裡,我們創造了一個東西叫「proc」,proc 是 procedure 縮寫。在這段程式碼中,首先我們呼叫了 Ruby 內建的函式 method,它會回傳一個 proc 版的 find_city 函式。然後我們將之除存在一個 Hash 裡:key 是 :find,value 是 cities。。這和我們將州和市關聯起來的程式碼做的事情一樣,只不過在這個情況裡是個 proc。

好了,所以一旦我們知道 find_city 是在Hash中 :find 的位置,這就意味著我們可以去呼叫它。第二行程式碼可以分解成如下步驟:

  • Ruby 讀到了 cities,然後知道了它是一個 「Hash」。
  • 然後看到了[:find],於是 Ruby 就從索引找到了 cities Hash 中對應的位置,並且獲取了該位置的內容。
  • [:find] 這個位置的內容是我們的函式 find_city,所以Ruby就知道了這裡表示一個函式,於是當它碰到.call就開始了 proc呼叫。
  • cities、state 這兩個參數將被傳遞到函式 find_city 中,然後這個函式就被運行了。
  • find_city 接著從 cities 中尋找 states,並且回傳它找到的內容,如果什麼都沒找到,就返回一個信息說它什麼都沒找到。
  • Ruby 接受 find_city 傳回的資訊,最後將該資訊賦值給一開始的 city_found 這個變數。

我再教你一個小技巧。如果你倒著閱讀的話,程式碼可能會變得更容易理解。讓我們來試一下,一樣是那行:

  • state 和 city 是…
  • 最為參數傳遞給…
  • 一個 proc 位於…
  • :find 然後尋找,目的地為…
  • cities 這個 Hash…
  • 最後印到螢幕上


還有一種方法讀它,這回是「由裡向外」。

  • 找到表示式的中心位置,此次為[:find]。
  • 逆時針追溯,首先看到的是一個叫 cities的 Hash,這樣就知道了 cities 中的 :find 元素。
  • 上一步得到一個函式。繼續逆時針尋找,看到的是參數。
  • 參數傳遞給函式後,函式會傳回一個值。然後再逆時針尋找。
  • 最後,我們到了city_found =的賦值位置,並且得到了最終結果。


數十年的程式經驗下來,我在讀程式碼的過程中已經用不到上面的三種方法了。我只要瞄一眼就能知道它的意思。甚至給我一整頁的程式碼,我也可以一眼瞄出裡邊的 bug 和錯誤。這樣的技能是花了超乎常人的時間和精力才鍛煉得來的。在磨練的過程中,我學會了下面三種讀程式碼的方法:

  • 從前向後。
  • 從後向前。
  • 逆時針方向。


現在我們來寫這次的練習,寫完後再過一遍,這節習題其實挺有趣的。

程式碼不少,不過還是從頭寫完吧。確認它能運行,然後玩一下看看。

  1. def prompt()
  2.   print "> "
  3. end

  4. def death()
  5.   quips = ["You died.  You kinda suck at this.",
  6.     "Nice job, you died ...jackass.",
  7.     "Such a luser.",
  8.     "I have a small puppy that's better at this."]
  9.   puts quips[rand(quips.length())]
  10.   Process.exit(1)
  11. end

  12. def central_corridor()
  13.   puts "The Gothons of Planet Percal #25 have invaded your ship and destroyed"
  14.   puts "your entire crew.  You are the last surviving member and your last"
  15.   puts "mission is to get the neutron destruct bomb from the Weapons Armory,"
  16.   puts "put it in the bridge, and blow the ship up after getting into an "
  17.   puts "escape pod."
  18.   puts "\n"
  19.   puts "You're running down the central corridor to the Weapons Armory when"
  20.   puts "a Gothon jumps out, red scaly skin, dark grimy teeth, and evil clown costume"
  21.   puts "flowing around his hate filled body.  He's blocking the door to the"
  22.   puts "Armory and about to pull a weapon to blast you."

  23.   prompt()
  24.   action = gets.chomp()

  25.   if action == "shoot!"
  26.     puts "Quick on the draw you yank out your blaster and fire it at the Gothon."
  27.     puts "His clown costume is flowing and moving around his body, which throws"
  28.     puts "off your aim.  Your laser hits his costume but misses him entirely.  This"
  29.     puts "completely ruins his brand new costume his mother bought him, which"
  30.     puts "makes him fly into an insane rage and blast you repeatedly in the face until"
  31.     puts "you are dead.  Then he eats you."
  32.     return :death

  33.   elsif action == "dodge!"
  34.     puts "Like a world class boxer you dodge, weave, slip and slide right"
  35.     puts "as the Gothon's blaster cranks a laser past your head."
  36.     puts "In the middle of your artful dodge your foot slips and you"
  37.     puts "bang your head on the metal wall and pass out."
  38.     puts "You wake up shortly after only to die as the Gothon stomps on"
  39.     puts "your head and eats you."
  40.     return :death

  41.   elsif action == "tell a joke"
  42.     puts "Lucky for you they made you learn Gothon insults in the academy."
  43.     puts "You tell the one Gothon joke you know:"
  44.     puts "Lbhe zbgure vf fb sng, jura fur fvgf nebhaq gur ubhfr, fur fvgf nebhaq gur ubhfr."
  45.     puts "The Gothon stops, tries not to laugh, then busts out laughing and can't move."
  46.     puts "While he's laughing you run up and shoot him square in the head"
  47.     puts "putting him down, then jump through the Weapon Armory door."
  48.     return :laser_weapon_armory

  49.   else
  50.     puts "DOES NOT COMPUTE!"
  51.     return :central_corridor
  52.   end
  53. end

  54. def laser_weapon_armory()
  55.   puts "You do a dive roll into the Weapon Armory, crouch and scan the room"
  56.   puts "for more Gothons that might be hiding.  It's dead quiet, too quiet."
  57.   puts "You stand up and run to the far side of the room and find the"
  58.   puts "neutron bomb in its container.  There's a keypad lock on the box"
  59.   puts "and you need the code to get the bomb out.  If you get the code"
  60.   puts "wrong 10 times then the lock closes forever and you can't"
  61.   puts "get the bomb.  The code is 3 digits."
  62.   code = "%s%s%s" % [rand(9)+1, rand(9)+1, rand(9)+1]
  63.   print "[keypad]> "
  64.   guess = gets.chomp()
  65.   guesses = 0

  66.   while guess != code and guesses < 10
  67.     puts "BZZZZEDDD!"
  68.     guesses += 1
  69.     print "[keypad]> "
  70.     guess = gets.chomp()
  71.   end

  72.   if guess == code
  73.     puts "The container clicks open and the seal breaks, letting gas out."
  74.     puts "You grab the neutron bomb and run as fast as you can to the"
  75.     puts "bridge where you must place it in the right spot."
  76.     return :the_bridge
  77.   else
  78.     puts "The lock buzzes one last time and then you hear a sickening"
  79.     puts "melting sound as the mechanism is fused together."
  80.     puts "You decide to sit there, and finally the Gothons blow up the"
  81.     puts "ship from their ship and you die."
  82.     return :death
  83.   end
  84. end

  85. def the_bridge()
  86.   puts "You burst onto the Bridge with the netron destruct bomb"
  87.   puts "under your arm and surprise 5 Gothons who are trying to"
  88.   puts "take control of the ship.  Each of them has an even uglier"
  89.   puts "clown costume than the last.  They haven't pulled their"
  90.   puts "weapons out yet, as they see the active bomb under your"
  91.   puts "arm and don't want to set it off."

  92.   prompt()
  93.   action = gets.chomp()

  94.   if action == "throw the bomb"
  95.     puts "In a panic you throw the bomb at the group of Gothons"
  96.     puts "and make a leap for the door.  Right as you drop it a"
  97.     puts "Gothon shoots you right in the back killing you."
  98.     puts "As you die you see another Gothon frantically try to disarm"
  99.     puts "the bomb. You die knowing they will probably blow up when"
  100.     puts "it goes off."
  101.     return :death

  102.   elsif action == "slowly place the bomb"
  103.     puts "You point your blaster at the bomb under your arm"
  104.     puts "and the Gothons put their hands up and start to sweat."
  105.     puts "You inch backward to the door, open it, and then carefully"
  106.     puts "place the bomb on the floor, pointing your blaster at it."
  107.     puts "You then jump back through the door, punch the close button"
  108.     puts "and blast the lock so the Gothons can't get out."
  109.     puts "Now that the bomb is placed you run to the escape pod to"
  110.     puts "get off this tin can."
  111.     return :escape_pod
  112.   else
  113.     puts "DOES NOT COMPUTE!"
  114.     return :the_bridge
  115.   end
  116. end

  117. def escape_pod()
  118.   puts "You rush through the ship desperately trying to make it to"
  119.   puts "the escape pod before the whole ship explodes.  It seems like"
  120.   puts "hardly any Gothons are on the ship, so your run is clear of"
  121.   puts "interference.  You get to the chamber with the escape pods, and"
  122.   puts "now need to pick one to take.  Some of them could be damaged"
  123.   puts "but you don't have time to look.  There's 5 pods, which one"
  124.   puts "do you take?"

  125.   good_pod = rand(5)+1
  126.   print "[pod #]>"
  127.   guess = gets.chomp()

  128.   if guess.to_i != good_pod
  129.     puts "You jump into pod %s and hit the eject button." % guess
  130.     puts "The pod escapes out into the void of space, then"
  131.     puts "implodes as the hull ruptures, crushing your body"
  132.     puts "into jam jelly."
  133.     return :death
  134.   else
  135.     puts "You jump into pod %s and hit the eject button." % guess
  136.     puts "The pod easily slides out into space heading to"
  137.     puts "the planet below.  As it flies to the planet, you look"
  138.     puts "back and see your ship implode then explode like a"
  139.     puts "bright star, taking out the Gothon ship at the same"
  140.     puts "time.  You won!"
  141.     Process.exit(0)
  142.   end
  143. end

  144. ROOMS = {
  145.   :death => method(:death),
  146.   :central_corridor => method(:central_corridor),
  147.   :laser_weapon_armory => method(:laser_weapon_armory),
  148.   :the_bridge => method(:the_bridge),
  149.   :escape_pod => method(:escape_pod)
  150. }

  151. def runner(map, start)
  152.   next_one = start

  153.   while true
  154.     room = map[next_one]
  155.     puts "\n--------"
  156.     next_one = room.call()
  157.   end
  158. end

  159. runner(ROOMS, :central_corridor)
复制代码

你應該看到的結果

  1. $ ruby ex41.rb

  2. --------
  3. The Gothons of Planet Percal #25 have invaded your ship and destroyed
  4. your entire crew.  You are the last surviving member and your last
  5. mission is to get the neutron destruct bomb from the Weapons Armory,
  6. put it in the bridge, and blow the ship up after getting into an
  7. escape pod.


  8. You're running down the central corridor to the Weapons Armory when
  9. a Gothon jumps out, red scaly skin, dark grimy teeth, and evil clown costume
  10. flowing around his hate filled body.  He's blocking the door to the
  11. Armory and about to pull a weapon to blast you.
  12. > dodge!
  13. Like a world class boxer you dodge, weave, slip and slide right
  14. as the Gothon's blaster cranks a laser past your head.
  15. In the middle of your artful dodge your foot slips and you
  16. bang your head on the metal wall and pass out.
  17. You wake up shortly after only to die as the Gothon stomps on
  18. your head and eats you.

  19. --------
  20. Such a luser.

  21. $ ruby ex41.rb

  22. --------
  23. The Gothons of Planet Percal #25 have invaded your ship and destroyed
  24. your entire crew.  You are the last surviving member and your last
  25. mission is to get the neutron destruct bomb from the Weapons Armory,
  26. put it in the bridge, and blow the ship up after getting into an
  27. escape pod.


  28. You're running down the central corridor to the Weapons Armory when
  29. a Gothon jumps out, red scaly skin, dark grimy teeth, and evil clown costume
  30. flowing around his hate filled body.  He's blocking the door to the
  31. Armory and about to pull a weapon to blast you.
  32. > tell a joke
  33. Lucky for you they made you learn Gothon insults in the academy.
  34. You tell the one Gothon joke you know:
  35. Lbhe zbgure vf fb sng, jura fur fvgf nebhaq gur ubhfr, fur fvgf nebhaq gur ubhfr.
  36. The Gothon stops, tries not to laugh, then busts out laughing and can't move.
  37. While he's laughing you run up and shoot him square in the head
  38. putting him down, then jump through the Weapon Armory door.

  39. --------
  40. You do a dive roll into the Weapon Armory, crouch and scan the room
  41. for more Gothons that might be hiding.  It's dead quiet, too quiet.
  42. You stand up and run to the far side of the room and find the
  43. neutron bomb in its container.  There's a keypad lock on the box
  44. and you need the code to get the bomb out.  If you get the code
  45. wrong 10 times then the lock closes forever and you can't
  46. get the bomb.  The code is 3 digits.
  47. [keypad]> 123
  48. BZZZZEDDD!
  49. [keypad]> 234
  50. BZZZZEDDD!
  51. [keypad]> 345
  52. BZZZZEDDD!
  53. [keypad]> 456
  54. BZZZZEDDD!
  55. [keypad]> 567
  56. BZZZZEDDD!
  57. [keypad]> 678
  58. BZZZZEDDD!
  59. [keypad]> 789
  60. BZZZZEDDD!
  61. [keypad]> 384
  62. BZZZZEDDD!
  63. [keypad]> 764
  64. BZZZZEDDD!
  65. [keypad]> 354
  66. BZZZZEDDD!
  67. [keypad]> 263
  68. The lock buzzes one last time and then you hear a sickening
  69. melting sound as the mechanism is fused together.
  70. You decide to sit there, and finally the Gothons blow up the
  71. ship from their ship and you die.

  72. --------
  73. You died.  You kinda suck at this.
复制代码

加分習題

  • 解釋一下返回至下一個房間的運作原理。 2.建立更多的房間,讓遊戲規模變大。
  • 除了讓每個函式印出自己以外,試試學習一下「文件註解(doc comments)」。
  • 看看你能不能將房間描述寫成文件註解,然後修改運行它的程式碼,讓它把文檔註解打印出來。
  • 一旦你用了文件註解作為房間描述,你還需要讓這個函式打出用戶提示嗎?試著讓運行函數的代碼打出用戶提示來,然後將用戶輸入傳遞到各個函式。你的函式應該只是一些 if 語句組合,將結果印出來,並且返回下一個房間。
  • 這其實是一個小版本的「有限狀態機(finite state machine)」,找資料閱讀了解一下,雖然你可能看不懂,但還是找來看看吧

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表