这本书马上就要结束了。本章的练习对你是一个真正的挑战。当你完成以后,你就可以算是一个能力不错的 Ruby 初学者了。为了进一步学习,你还需要多读一些书,多写一些程序,不过你已经具备进一步学习的技能了。接下来的学习就只是时间、动力、以及资源的问题了。
在本章练习中,我们不会去创建一个完整的游戏,取而代之的是我们会为《练习42》中的游戏建立一个“引擎(engine)”,让这个游戏能够在浏览 器中运行起来。这会涉及到将《练习42》中的游戏「重构(refactor)」,将《练习47》中的架构混合进来,添加自动测试代码,最后建立一个可以 运行游戏的web 引擎。
这是一节很「庞大」的练习。我预测你要花一周到一个月才能完成它。最好的方法是一点一点来,每晚上完成一点,在进行下一步之前确认上一步有正确完成。
重构《练习42》的游戏
你已经在两个练习中修改了 gothonweb 项目,这节练习中你会再修改一次。这种修改的技术叫做「重构(refactoring)」,或者用我喜欢的讲法来说,叫「修修补补(fixing stuff)」。重构是一个程序术语,它指的是清理旧代码或者为旧代码添加新功能的过程。你其实已经做过这样的事情了,只不过不知道这个术语而已。这 是写软体过程的第二个自然属性。
你在本节中要做的,是将《练习47》中的可以测试的房间地图,以及《练习42》中的游戏这两样东西归并到一起,创建一个新的游戏架构。游戏的内容不会发生变化,只不过我们会通过“重构”让它有一个更好的架构而已。
第一步是将 ex47.rb 的内容复制到 gothonweb/lib/map.rb 中,然后将ex47_tests.rb
的内容复制到gothonweb/test/test_map.rb
中,然后再次运行测试,确认他们还能正常运作。
Note: 从现在开始我不会再向你展示运行测试的输出了,我就假设你回去运行这些测试,而且知道怎样的输出是正确的。
将《练习47》的代码拷贝完毕后,你就该开始重构它,让它包含《练习42》中的地图。我一开始会把基本架构为你准备好,然后你需要去完成map.rb和map_tests.rb 里边的内容。
首先要做的是使用 Room 类来构建基本的地图架构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
class Room attr_accessor :name, :description, :paths def initialize<span class="o">(</span>name, description<span class="o">)</span> @name <span class="o">=</span> name @description <span class="o">=</span> description @paths <span class="o">=</span> <span class="o">{}</span> end def go<span class="o">(</span>direction<span class="o">)</span> @paths<span class="o">[</span>direction<span class="o">]</span> end def add_paths<span class="o">(</span>paths<span class="o">)</span> @paths.update<span class="o">(</span>paths<span class="o">)</span> end end <span class="nv">central_corridor</span> <span class="o">=</span> Room.new<span class="o">(</span><span class="s2">"Central Corridor"</span>, %q<span class="o">{</span> The Gothons of Planet Percal <span class="c">#25 have invaded your ship and destroyed</span> your entire crew. You are the last surviving member and your last mission is to get the neutron destruct bomb from the Weapons Armory, put it in the bridge, and blow the ship up after getting into an escape pod. You<span class="s1">'re running down the central corridor to the Weapons Armory when</span> <span class="s1">a Gothon jumps out, red scaly skin, dark grimy teeth, and evil clown costume</span> <span class="s1">flowing around his hate filled body. He'</span>s blocking the door to the Armory and about to pull a weapon to blast you. <span class="o">})</span> <span class="nv">laser_weapon_armory</span> <span class="o">=</span> Room.new<span class="o">(</span><span class="s2">"Laser Weapon Armory"</span>, %q<span class="o">{</span> Lucky <span class="k">for</span> you they made you learn Gothon insults in the academy. You tell the one Gothon joke you know: Lbhe zbgure vf fb sng, jura fur fvgf nebhaq gur ubhfr, fur fvgf nebhaq gur ubhfr. The Gothon stops, tries not to laugh, <span class="k">then</span> busts out laughing and can<span class="s1">'t move.</span> <span class="s1">While he'</span>s laughing you run up and shoot him square in the head putting him down, <span class="k">then</span> jump through the Weapon Armory door. You <span class="k">do</span> a dive roll into the Weapon Armory, crouch and scan the room <span class="k">for</span> more Gothons that might be hiding. It<span class="s1">'s dead quiet, too quiet.</span> <span class="s1">You stand up and run to the far side of the room and find the</span> <span class="s1">neutron bomb in its container. There'</span>s a keypad lock on the box and you need the code to get the bomb out. If you get the code wrong <span class="m">10</span> <span class="nb">times </span><span class="k">then</span> the lock closes forever and you can<span class="s1">'t</span> <span class="s1">get the bomb. The code is 3 digits.</span> <span class="s1">})</span> <span class="s1">the_bridge = Room.new("The Bridge",</span> <span class="s1">%q{</span> <span class="s1">The container clicks open and the seal breaks, letting gas out.</span> <span class="s1">You grab the neutron bomb and run as fast as you can to the</span> <span class="s1">bridge where you must place it in the right spot.</span> <span class="s1">You burst onto the Bridge with the netron destruct bomb</span> <span class="s1">under your arm and surprise 5 Gothons who are trying to</span> <span class="s1">take control of the ship. Each of them has an even uglier</span> <span class="s1">clown costume than the last. They haven'</span>t pulled their weapons out yet, as they see the active bomb under your arm and don<span class="s1">'t want to set it off.</span> <span class="s1">})</span> <span class="s1">escape_pod = Room.new("Escape Pod",</span> <span class="s1">%q{</span> <span class="s1">You point your blaster at the bomb under your arm</span> <span class="s1">and the Gothons put their hands up and start to sweat.</span> <span class="s1">You inch backward to the door, open it, and then carefully</span> <span class="s1">place the bomb on the floor, pointing your blaster at it.</span> <span class="s1">You then jump back through the door, punch the close button</span> <span class="s1">and blast the lock so the Gothons can'</span>t get out. Now that the bomb is placed you run to the escape pod to get off this tin can. You rush through the ship desperately trying to make it to the escape pod before the whole ship explodes. It seems like hardly any Gothons are on the ship, so your run is clear of interference. You get to the chamber with the escape pods, and now need to pick one to take. Some of them could be damaged but you don<span class="s1">'t have time to look. There'</span>s <span class="m">5</span> pods, which one <span class="k">do</span> you take? <span class="o">})</span> <span class="nv">the_end_winner</span> <span class="o">=</span> Room.new<span class="o">(</span><span class="s2">"The End"</span>, %q<span class="o">{</span> You jump into pod <span class="m">2</span> and hit the eject button. The pod easily slides out into space heading to the planet below. As it flies to the planet, you look back and see your ship implode <span class="k">then</span> explode like a bright star, taking out the Gothon ship at the same time. You won! <span class="o">})</span> <span class="nv">the_end_loser</span> <span class="o">=</span> Room.new<span class="o">(</span><span class="s2">"The End"</span>, %q<span class="o">{</span> You jump into a random pod and hit the eject button. The pod escapes out into the void of space, <span class="k">then</span> implodes as the hull ruptures, crushing your body into jam jelly. <span class="o">})</span> escape_pod.add_paths<span class="o">({</span> <span class="s1">'2'</span> <span class="o">=</span>> the_end_winner, <span class="s1">'*'</span> <span class="o">=</span>> the_end_loser <span class="o">})</span> <span class="nv">generic_death</span> <span class="o">=</span> Room.new<span class="o">(</span><span class="s2">"death"</span>, <span class="s2">"You died."</span><span class="o">)</span> the_bridge.add_paths<span class="o">({</span> <span class="s1">'throw the bomb'</span> <span class="o">=</span>> generic_death, <span class="s1">'slowly place the bomb'</span> <span class="o">=</span>> escape_pod <span class="o">})</span> laser_weapon_armory.add_paths<span class="o">({</span> <span class="s1">'0132'</span> <span class="o">=</span>> the_bridge, <span class="s1">'*'</span> <span class="o">=</span>> generic_death <span class="o">})</span> central_corridor.add_paths<span class="o">({</span> <span class="s1">'shoot!'</span> <span class="o">=</span>> generic_death, <span class="s1">'dodge!'</span><span class="o">=</span>> generic_death, <span class="s1">'tell a joke'</span> <span class="o">=</span>> laser_weapon_armory <span class="o">})</span> <span class="nv">START</span> <span class="o">=</span> central_corridor |

