karnowski-ruby-warrior 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/.gitignore +3 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +156 -0
  4. data/Rakefile +36 -0
  5. data/VERSION +1 -0
  6. data/bin/rubywarrior +8 -0
  7. data/features/levels.feature +50 -0
  8. data/features/profiles.feature +46 -0
  9. data/features/step_definitions/common_steps.rb +7 -0
  10. data/features/step_definitions/interaction_steps.rb +53 -0
  11. data/features/support/env.rb +8 -0
  12. data/features/support/mockio.rb +57 -0
  13. data/features/towers.feature +14 -0
  14. data/lib/ruby_warrior.rb +41 -0
  15. data/lib/ruby_warrior/abilities/attack.rb +24 -0
  16. data/lib/ruby_warrior/abilities/base.rb +36 -0
  17. data/lib/ruby_warrior/abilities/bind.rb +19 -0
  18. data/lib/ruby_warrior/abilities/direction_of.rb +13 -0
  19. data/lib/ruby_warrior/abilities/direction_of_stairs.rb +13 -0
  20. data/lib/ruby_warrior/abilities/distance.rb +13 -0
  21. data/lib/ruby_warrior/abilities/explode.rb +16 -0
  22. data/lib/ruby_warrior/abilities/feel.rb +13 -0
  23. data/lib/ruby_warrior/abilities/health.rb +13 -0
  24. data/lib/ruby_warrior/abilities/listen.rb +15 -0
  25. data/lib/ruby_warrior/abilities/look.rb +15 -0
  26. data/lib/ruby_warrior/abilities/pivot.rb +16 -0
  27. data/lib/ruby_warrior/abilities/rescue.rb +23 -0
  28. data/lib/ruby_warrior/abilities/rest.rb +20 -0
  29. data/lib/ruby_warrior/abilities/shoot.rb +23 -0
  30. data/lib/ruby_warrior/abilities/walk.rb +20 -0
  31. data/lib/ruby_warrior/config.rb +11 -0
  32. data/lib/ruby_warrior/core_additions.rb +25 -0
  33. data/lib/ruby_warrior/floor.rb +71 -0
  34. data/lib/ruby_warrior/game.rb +160 -0
  35. data/lib/ruby_warrior/level.rb +93 -0
  36. data/lib/ruby_warrior/level_loader.rb +52 -0
  37. data/lib/ruby_warrior/player_generator.rb +41 -0
  38. data/lib/ruby_warrior/position.rb +80 -0
  39. data/lib/ruby_warrior/profile.rb +86 -0
  40. data/lib/ruby_warrior/space.rb +63 -0
  41. data/lib/ruby_warrior/tower.rb +14 -0
  42. data/lib/ruby_warrior/turn.rb +38 -0
  43. data/lib/ruby_warrior/ui.rb +64 -0
  44. data/lib/ruby_warrior/units/archer.rb +34 -0
  45. data/lib/ruby_warrior/units/base.rb +95 -0
  46. data/lib/ruby_warrior/units/captive.rb +30 -0
  47. data/lib/ruby_warrior/units/sludge.rb +30 -0
  48. data/lib/ruby_warrior/units/thick_sludge.rb +13 -0
  49. data/lib/ruby_warrior/units/warrior.rb +58 -0
  50. data/lib/ruby_warrior/units/wizard.rb +34 -0
  51. data/ruby-warrior.gemspec +191 -0
  52. data/script/console +8 -0
  53. data/spec/fixtures/short-tower/level_001.rb +14 -0
  54. data/spec/fixtures/short-tower/level_002.rb +14 -0
  55. data/spec/fixtures/walking_player.rb +5 -0
  56. data/spec/ruby_warrior/abilities/attack_spec.rb +51 -0
  57. data/spec/ruby_warrior/abilities/base_spec.rb +24 -0
  58. data/spec/ruby_warrior/abilities/bind_spec.rb +19 -0
  59. data/spec/ruby_warrior/abilities/direction_of_spec.rb +13 -0
  60. data/spec/ruby_warrior/abilities/direction_of_stairs_spec.rb +13 -0
  61. data/spec/ruby_warrior/abilities/distance_spec.rb +13 -0
  62. data/spec/ruby_warrior/abilities/explode_spec.rb +21 -0
  63. data/spec/ruby_warrior/abilities/feel_spec.rb +13 -0
  64. data/spec/ruby_warrior/abilities/health_spec.rb +13 -0
  65. data/spec/ruby_warrior/abilities/listen_spec.rb +17 -0
  66. data/spec/ruby_warrior/abilities/look_spec.rb +15 -0
  67. data/spec/ruby_warrior/abilities/pivot_spec.rb +18 -0
  68. data/spec/ruby_warrior/abilities/rescue_spec.rb +40 -0
  69. data/spec/ruby_warrior/abilities/rest_spec.rb +29 -0
  70. data/spec/ruby_warrior/abilities/shoot_spec.rb +22 -0
  71. data/spec/ruby_warrior/abilities/walk_spec.rb +25 -0
  72. data/spec/ruby_warrior/floor_spec.rb +81 -0
  73. data/spec/ruby_warrior/game_spec.rb +96 -0
  74. data/spec/ruby_warrior/level_loader_spec.rb +54 -0
  75. data/spec/ruby_warrior/level_spec.rb +163 -0
  76. data/spec/ruby_warrior/player_generator_spec.rb +12 -0
  77. data/spec/ruby_warrior/position_spec.rb +103 -0
  78. data/spec/ruby_warrior/profile_spec.rb +125 -0
  79. data/spec/ruby_warrior/space_spec.rb +165 -0
  80. data/spec/ruby_warrior/tower_spec.rb +15 -0
  81. data/spec/ruby_warrior/turn_spec.rb +42 -0
  82. data/spec/ruby_warrior/ui_spec.rb +96 -0
  83. data/spec/ruby_warrior/units/archer_spec.rb +23 -0
  84. data/spec/ruby_warrior/units/base_spec.rb +133 -0
  85. data/spec/ruby_warrior/units/captive_spec.rb +34 -0
  86. data/spec/ruby_warrior/units/sludge_spec.rb +27 -0
  87. data/spec/ruby_warrior/units/thick_sludge_spec.rb +19 -0
  88. data/spec/ruby_warrior/units/warrior_spec.rb +60 -0
  89. data/spec/ruby_warrior/units/wizard_spec.rb +23 -0
  90. data/spec/spec_helper.rb +7 -0
  91. data/templates/README.erb +20 -0
  92. data/templates/player.rb +5 -0
  93. data/towers/beginner/level_001.rb +15 -0
  94. data/towers/beginner/level_002.rb +17 -0
  95. data/towers/beginner/level_003.rb +20 -0
  96. data/towers/beginner/level_004.rb +17 -0
  97. data/towers/beginner/level_005.rb +21 -0
  98. data/towers/beginner/level_006.rb +18 -0
  99. data/towers/beginner/level_007.rb +17 -0
  100. data/towers/beginner/level_008.rb +20 -0
  101. data/towers/beginner/level_009.rb +19 -0
  102. data/towers/intermediate/level_001.rb +17 -0
  103. data/towers/intermediate/level_002.rb +19 -0
  104. data/towers/intermediate/level_003.rb +22 -0
  105. data/towers/intermediate/level_004.rb +23 -0
  106. data/towers/intermediate/level_005.rb +18 -0
  107. data/towers/intermediate/level_006.rb +23 -0
  108. metadata +218 -0
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe RubyWarrior::PlayerGenerator do
4
+ before(:each) do
5
+ @level = RubyWarrior::Level.new(RubyWarrior::Profile.new, 15)
6
+ @generator = RubyWarrior::PlayerGenerator.new(@level)
7
+ end
8
+
9
+ it "should know templates path" do
10
+ @generator.templates_path.should == File.expand_path(File.dirname(__FILE__) + "/../../templates")
11
+ end
12
+ end
@@ -0,0 +1,103 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe RubyWarrior::Position do
4
+ before(:each) do
5
+ @unit = RubyWarrior::Units::Base.new
6
+ @floor = RubyWarrior::Floor.new
7
+ @floor.width = 6
8
+ @floor.height = 5
9
+ @floor.add(@unit, 1, 2, :north)
10
+ @position = @unit.position
11
+ end
12
+
13
+ it "should rotate clockwise" do
14
+ @position.direction.should == :north
15
+ [:east, :south, :west, :north, :east].each do |dir|
16
+ @position.rotate(1)
17
+ @position.direction.should == dir
18
+ end
19
+ end
20
+
21
+ it "should rotate counterclockwise" do
22
+ @position.direction.should == :north
23
+ [:west, :south, :east, :north, :west].each do |dir|
24
+ @position.rotate(-1)
25
+ @position.direction.should == dir
26
+ end
27
+ end
28
+
29
+ it "should get relative space in front" do
30
+ unit = RubyWarrior::Units::Base.new
31
+ @floor.add(unit, 1, 1)
32
+ @position.relative_space(1).should_not be_empty
33
+ end
34
+
35
+ it "should get relative object in front when rotated" do
36
+ unit = RubyWarrior::Units::Base.new
37
+ @floor.add(unit, 2, 2)
38
+ @position.rotate(1)
39
+ @position.relative_space(1).should_not be_empty
40
+ end
41
+
42
+ it "should get relative object diagonally" do
43
+ unit = RubyWarrior::Units::Base.new
44
+ @floor.add(unit, 0, 1)
45
+ @position.relative_space(1, -1).should_not be_empty
46
+ end
47
+
48
+ it "should get relative object diagonally when rotating" do
49
+ unit = RubyWarrior::Units::Base.new
50
+ @floor.add(unit, 0, 1)
51
+ @position.rotate(2)
52
+ @position.relative_space(-1, 1).should_not be_empty
53
+ end
54
+
55
+ it "should move object on floor relatively" do
56
+ @floor.get(1, 2).should == @unit
57
+ @position.move(-1, 2)
58
+ @floor.get(1, 2).should be_nil
59
+ @floor.get(3, 3).should == @unit
60
+ @position.rotate(1)
61
+ @position.move(-1)
62
+ @floor.get(3, 3).should be_nil
63
+ @floor.get(2, 3).should == @unit
64
+ end
65
+
66
+ it "should return distance from stairs as 0 when on stairs" do
67
+ @floor.place_stairs(1, 2)
68
+ @position.distance_from_stairs.should == 0
69
+ end
70
+
71
+ it "should return distance from stairs in both directions" do
72
+ @floor.place_stairs(0, 3)
73
+ @position.distance_from_stairs.should == 2
74
+ end
75
+
76
+ it "should return relative direction of stairs" do
77
+ @floor.place_stairs(0, 0)
78
+ @position.relative_direction_of_stairs.should == :forward
79
+ end
80
+
81
+ it "should return relative direction of given space" do
82
+ @position.relative_direction_of(@floor.space(5, 3)).should == :right
83
+ @position.rotate 1
84
+ @position.relative_direction_of(@floor.space(1, 4)).should == :right
85
+ end
86
+
87
+ it "should be able to determine relative direction" do
88
+ @position.relative_direction(:north).should == :forward
89
+ @position.relative_direction(:south).should == :backward
90
+ @position.relative_direction(:west).should == :left
91
+ @position.relative_direction(:east).should == :right
92
+ @position.rotate 1
93
+ @position.relative_direction(:north).should == :left
94
+ @position.rotate 1
95
+ @position.relative_direction(:north).should == :backward
96
+ @position.rotate 1
97
+ @position.relative_direction(:north).should == :right
98
+ end
99
+
100
+ it "should return a space at the same location as position" do
101
+ @position.space.location.should == [1, 2]
102
+ end
103
+ end
@@ -0,0 +1,125 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe RubyWarrior::Profile do
4
+ before(:each) do
5
+ @profile = RubyWarrior::Profile.new
6
+ end
7
+
8
+ it "should have warrior name" do
9
+ @profile.warrior_name = 'Joe'
10
+ @profile.warrior_name.should == 'Joe'
11
+ end
12
+
13
+ it "should start level number at 0" do
14
+ @profile.level_number.should be_zero
15
+ end
16
+
17
+ it "should start score at 0 and allow it to increment" do
18
+ @profile.score.should be_zero
19
+ @profile.score += 5
20
+ @profile.score.should == 5
21
+ end
22
+
23
+ it "should have no abilities and allow adding" do
24
+ @profile.abilities.should == []
25
+ @profile.abilities += [:foo, :bar]
26
+ @profile.abilities.should == [:foo, :bar]
27
+ end
28
+
29
+ it "should encode with marshal + base64" do
30
+ @profile.encode.should == Base64.encode64(Marshal.dump(@profile))
31
+ end
32
+
33
+ it "should decode with marshal + base64" do
34
+ RubyWarrior::Profile.decode(@profile.encode).warrior_name.should == @profile.warrior_name
35
+ end
36
+
37
+ it "load should read file, decode and set player path" do
38
+ profile = 'profile'
39
+ profile.expects(:player_path=).with('path/to')
40
+ File.expects(:read).with('path/to/.profile').returns('encoded_profile')
41
+ RubyWarrior::Profile.expects(:decode).with('encoded_profile').returns(profile)
42
+ RubyWarrior::Profile.load('path/to/.profile').should == profile
43
+ end
44
+
45
+
46
+ it "should add abilities and remove duplicates" do
47
+ @profile.add_abilities(:foo, :bar, :blah, :bar)
48
+ @profile.abilities.should == [:foo, :bar, :blah]
49
+ end
50
+
51
+ it "should fetch new level with current number" do
52
+ @profile.level_number = 1
53
+ @profile.current_level.number.should == 1
54
+ end
55
+
56
+ it "should fetch next level" do
57
+ @profile.level_number = 1
58
+ @profile.next_level.number.should == 2
59
+ end
60
+
61
+ it "should enable epic mode and reset scores if nil" do
62
+ @profile.epic_score = nil
63
+ @profile.current_epic_score = nil
64
+ @profile.enable_epic_mode
65
+ @profile.should be_epic
66
+ @profile.epic_score.should be_zero
67
+ @profile.current_epic_score.should be_zero
68
+ end
69
+
70
+ it "should override epic score with current one if it is higher" do
71
+ @profile.enable_epic_mode
72
+ @profile.epic_score.should be_zero
73
+ @profile.current_epic_score = 123
74
+ @profile.update_epic_score
75
+ @profile.epic_score.should == 123
76
+ end
77
+
78
+ it "should not override epic score with current one if it is lower" do
79
+ @profile.enable_epic_mode
80
+ @profile.epic_score = 124
81
+ @profile.current_epic_score = 123
82
+ @profile.update_epic_score
83
+ @profile.epic_score.should == 124
84
+ end
85
+
86
+ describe "with tower path" do
87
+ before(:each) do
88
+ @profile.warrior_name = "John Smith"
89
+ @profile.tower_path = 'path/to/tower'
90
+ end
91
+
92
+ it "save should write file with encoded profile" do
93
+ file = stub
94
+ file.expects(:write).with('encoded_profile')
95
+ File.expects(:open).with(@profile.player_path + '/.profile', 'w').yields(file)
96
+ @profile.expects(:encode).returns('encoded_profile')
97
+ @profile.save
98
+ end
99
+
100
+ it "should have a nice string representation" do
101
+ @profile.warrior_name = 'Joe'
102
+ @profile.to_s.should == "Joe - tower - level 0 - score 0"
103
+ end
104
+
105
+ it "should include epic score in string representation" do
106
+ @profile.warrior_name = 'Joe'
107
+ @profile.enable_epic_mode
108
+ @profile.to_s.should == "Joe - tower - first score 0 - epic score 0"
109
+ end
110
+
111
+ it "should guess at the player path" do
112
+ @profile.player_path.should == './ruby-warrior/john-smith-tower'
113
+ end
114
+
115
+ it "should use specified player path" do
116
+ @profile.player_path = "path/to/player"
117
+ @profile.player_path.should == "path/to/player"
118
+ end
119
+
120
+ it "should load tower from path" do
121
+ RubyWarrior::Tower.expects(:new).with('path/to/tower').returns('tower')
122
+ @profile.tower.should == 'tower'
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,165 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe RubyWarrior::Space do
4
+ before(:each) do
5
+ @floor = RubyWarrior::Floor.new
6
+ @floor.width = 2
7
+ @floor.height = 3
8
+ end
9
+
10
+ describe "with empty space" do
11
+ before(:each) do
12
+ @space = @floor.space(0, 0)
13
+ end
14
+
15
+ it "should not be enemy" do
16
+ @space.should_not be_enemy
17
+ end
18
+
19
+ it "should not be warrior" do
20
+ @space.should_not be_warrior
21
+ end
22
+
23
+ it "should be empty" do
24
+ @space.should be_empty
25
+ end
26
+
27
+ it "should not be wall" do
28
+ @space.should_not be_wall
29
+ end
30
+
31
+ it "should not be stairs" do
32
+ @space.should_not be_stairs
33
+ end
34
+
35
+ it "should not be captive" do
36
+ @space.should_not be_captive
37
+ end
38
+
39
+ it "should say 'nothing' as name" do
40
+ @space.to_s.should == 'nothing'
41
+ end
42
+
43
+ it "should not be ticking" do
44
+ @space.should_not be_ticking
45
+ end
46
+ end
47
+
48
+ describe "out of bounds" do
49
+ before(:each) do
50
+ @space = @floor.space(-1, 1)
51
+ end
52
+
53
+ it "should be wall" do
54
+ @space.should be_wall
55
+ end
56
+
57
+ it "should not be empty" do
58
+ @space.should_not be_empty
59
+ end
60
+
61
+ it "should have name of 'wall'" do
62
+ @space.to_s.should == 'wall'
63
+ end
64
+ end
65
+
66
+ describe "with warrior" do
67
+ before(:each) do
68
+ warrior = RubyWarrior::Units::Warrior.new
69
+ @floor.add(warrior, 0, 0)
70
+ @space = @floor.space(0, 0)
71
+ end
72
+
73
+ it "should be warrior" do
74
+ @space.should be_warrior
75
+ end
76
+
77
+ it "should not be enemy" do
78
+ @space.should_not be_enemy
79
+ end
80
+
81
+ it "should not be empty" do
82
+ @space.should_not be_enemy
83
+ end
84
+
85
+ it "should know what unit is on that space" do
86
+ @space.unit.should be_kind_of(RubyWarrior::Units::Warrior)
87
+ end
88
+ end
89
+
90
+ describe "with enemy" do
91
+ before(:each) do
92
+ @floor.add(RubyWarrior::Units::Sludge.new, 0, 0)
93
+ @space = @floor.space(0, 0)
94
+ end
95
+
96
+ it "should be enemy" do
97
+ @space.should be_enemy
98
+ end
99
+
100
+ it "should not be warrior" do
101
+ @space.should_not be_warrior
102
+ end
103
+
104
+ it "should not be empty" do
105
+ @space.should_not be_empty
106
+ end
107
+
108
+ it "should have name of unit" do
109
+ @space.to_s.should == "Sludge"
110
+ end
111
+
112
+ describe "bound" do
113
+ before(:each) do
114
+ @space.unit.bind
115
+ end
116
+
117
+ it "should be captive" do
118
+ @space.should be_captive
119
+ end
120
+
121
+ it "should not look like enemy" do
122
+ @space.should_not be_enemy
123
+ end
124
+ end
125
+ end
126
+
127
+ describe "with captive" do
128
+ before(:each) do
129
+ @floor.add(RubyWarrior::Units::Captive.new, 0, 0)
130
+ @space = @floor.space(0, 0)
131
+ end
132
+
133
+ it "should be captive" do
134
+ @space.should be_captive
135
+ end
136
+
137
+ it "should not be enemy" do
138
+ @space.should_not be_enemy
139
+ end
140
+
141
+ it "should be ticking if captive has time bomb" do
142
+ @space.unit.bomb_time = 10
143
+ @space.should be_ticking
144
+ end
145
+
146
+ it "should not be ticking if captive does not have time bomb" do
147
+ @space.should_not be_ticking
148
+ end
149
+ end
150
+
151
+ describe "at stairs" do
152
+ before(:each) do
153
+ @floor.place_stairs(0, 0)
154
+ @space = @floor.space(0, 0)
155
+ end
156
+
157
+ it "should be empty" do
158
+ @space.should be_empty
159
+ end
160
+
161
+ it "should be stairs" do
162
+ @space.should be_stairs
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe RubyWarrior::Tower do
4
+ before(:each) do
5
+ @tower = RubyWarrior::Tower.new('path/to/tower')
6
+ end
7
+
8
+ it "should consider last part of path as name" do
9
+ @tower.name.should == 'tower'
10
+ end
11
+
12
+ it "should use name when converting to string" do
13
+ @tower.to_s.should == @tower.name
14
+ end
15
+ end
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe RubyWarrior::Turn do
4
+ describe "with actions" do
5
+ before(:each) do
6
+ @turn = RubyWarrior::Turn.new({:walk! => nil, :attack! => nil})
7
+ end
8
+
9
+ it "should have no action performed at first" do
10
+ @turn.action.should be_nil
11
+ end
12
+
13
+ it "should be able to perform action and recall it" do
14
+ @turn.walk!
15
+ @turn.action.should == [:walk!]
16
+ end
17
+
18
+ it "should include arguments passed to action" do
19
+ @turn.walk! :forward
20
+ @turn.action.should == [:walk!, :forward]
21
+ end
22
+
23
+ it "should not be able to call multiple actions per turn" do
24
+ @turn.walk! :forward
25
+ lambda { @turn.attack! }.should raise_error
26
+ end
27
+ end
28
+
29
+ describe "with senses" do
30
+ before(:each) do
31
+ @feel = RubyWarrior::Abilities::Feel.new(Object.new)
32
+ @feel.stubs(:space).returns(Object.new)
33
+ @feel.stubs(:space).with(:backward).returns(Object.new)
34
+ @turn = RubyWarrior::Turn.new({:feel => @feel})
35
+ end
36
+
37
+ it "should be able to call sense with any argument and return expected results" do
38
+ @turn.feel.should == @feel.perform
39
+ @turn.feel(:backward).should == @feel.perform(:backward)
40
+ end
41
+ end
42
+ end