zombie-chaser 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/History.txt +22 -0
  2. data/README.txt +57 -47
  3. data/Rakefile +26 -24
  4. data/bin/zombie-chaser +77 -79
  5. data/lib/{chaser.rb → zombie-chaser/chaser.rb} +392 -373
  6. data/lib/zombie-chaser/human.rb +312 -0
  7. data/{ui → lib/zombie-chaser}/icons/death.png +0 -0
  8. data/{ui → lib/zombie-chaser}/icons/robot.png +0 -0
  9. data/lib/zombie-chaser/interface.rb +153 -0
  10. data/{ui → lib/zombie-chaser}/sprites/robot-attacking.png +0 -0
  11. data/{ui → lib/zombie-chaser}/sprites/robot-dead.png +0 -0
  12. data/{ui → lib/zombie-chaser}/sprites/robot-dying.png +0 -0
  13. data/{ui → lib/zombie-chaser}/sprites/robot-idle.png +0 -0
  14. data/{ui → lib/zombie-chaser}/sprites/robot-moving.png +0 -0
  15. data/{ui → lib/zombie-chaser}/sprites/robot-turning.png +0 -0
  16. data/{ui → lib/zombie-chaser}/sprites/tank-attacking.png +0 -0
  17. data/{ui → lib/zombie-chaser}/sprites/tank-dead.png +0 -0
  18. data/{ui → lib/zombie-chaser}/sprites/tank-idle.png +0 -0
  19. data/{ui → lib/zombie-chaser}/sprites/tank-moving.png +0 -0
  20. data/{ui → lib/zombie-chaser}/sprites/tank-turning.png +0 -0
  21. data/{ui → lib/zombie-chaser}/sprites/witch-attacking.png +0 -0
  22. data/{ui → lib/zombie-chaser}/sprites/witch-dead.png +0 -0
  23. data/{ui → lib/zombie-chaser}/sprites/witch-idle.png +0 -0
  24. data/{ui → lib/zombie-chaser}/sprites/witch-moving.png +0 -0
  25. data/{ui → lib/zombie-chaser}/sprites/witch-turning.png +0 -0
  26. data/{ui → lib/zombie-chaser}/sprites/zombie-attacking.png +0 -0
  27. data/{ui → lib/zombie-chaser}/sprites/zombie-dead.png +0 -0
  28. data/{ui → lib/zombie-chaser}/sprites/zombie-dying.png +0 -0
  29. data/{ui → lib/zombie-chaser}/sprites/zombie-idle.png +0 -0
  30. data/{ui → lib/zombie-chaser}/sprites/zombie-moving.png +0 -0
  31. data/{ui → lib/zombie-chaser}/sprites/zombie-turning.png +0 -0
  32. data/lib/zombie-chaser/test_unit_handler.rb +78 -0
  33. data/{ui → lib/zombie-chaser}/tiles/grass.png +0 -0
  34. data/{ui → lib/zombie-chaser}/tiles/shrubbery.png +0 -0
  35. data/{ui → lib/zombie-chaser}/ui.rb +165 -127
  36. data/lib/{world.rb → zombie-chaser/world.rb} +105 -98
  37. data/lib/zombie-chaser/zombie_test_chaser.rb +139 -0
  38. data/test/fixtures/chased.rb +56 -56
  39. data/test/integration.rb +58 -0
  40. data/test/test_chaser.rb +150 -144
  41. data/test/test_unit.rb +2 -2
  42. data/test/test_zombie.rb +302 -108
  43. data/zombie-chaser.gemspec +88 -88
  44. metadata +40 -46
  45. data/lib/human.rb +0 -189
  46. data/lib/interface.rb +0 -86
  47. data/lib/test_unit_handler.rb +0 -43
  48. data/lib/zombie_test_chaser.rb +0 -133
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,78 @@
1
+ require "test/unit/collector/objectspace"
2
+ require "test/unit/ui/testrunnermediator"
3
+
4
+ require "thread"
5
+
6
+ class TestUnitHandler
7
+ attr_reader :test_suite_size, :result_queue
8
+
9
+ def initialize(test_pattern)
10
+ raise "Error: can't detect any files in test pattern #{test_pattern.inspect} (Don't forget to use forward slashes even in Windows)" if Dir.glob(test_pattern).empty?
11
+ Dir.glob(test_pattern).each {|test| require test} #In heckle, this is separated out
12
+ obj_sp = Test::Unit::Collector::ObjectSpace.new
13
+ test_suite = Test::Unit::TestSuite.new("Mutation slayer test suite")
14
+ test_suite << obj_sp.collect
15
+ @test_suite_size = test_suite.size
16
+ @test_runner_mediator = Test::Unit::UI::TestRunnerMediator.new(test_suite)
17
+ @test_runner_mediator.add_listener(Test::Unit::TestResult::FAULT) {test_failed}
18
+ @test_runner_mediator.add_listener(Test::Unit::TestCase::FINISHED) {test_finished}
19
+ @result_queue = Queue.new
20
+ @failure_encountered = false
21
+ end
22
+
23
+ def run
24
+ begin
25
+ catch(:stop_test_runner) do
26
+ @test_runner_mediator.run_suite
27
+ end
28
+ rescue Chaser::Timeout
29
+ @result_queue.enq(:failure)
30
+ raise
31
+ ensure
32
+ @result_queue.enq(:end_of_work)
33
+ end
34
+ not @failure_encountered
35
+ end
36
+
37
+ def test_failed
38
+ @result_queue.enq(:failure)
39
+ @failure_encountered = true
40
+ throw :stop_test_runner
41
+ end
42
+
43
+ def test_finished
44
+ @result_queue.enq(:pass)
45
+ end
46
+
47
+ end
48
+
49
+ class MockTestHandler
50
+ attr_reader :result_queue
51
+
52
+ def initialize(results)
53
+ @results = results
54
+ @result_queue = Queue.new
55
+ @failure_encountered = false
56
+ end
57
+
58
+ def test_suite_size
59
+ @results.size
60
+ end
61
+
62
+ def run
63
+ begin
64
+ @results.each do |result|
65
+ raise Timeout::Error, "Out of time" if result == :timeout
66
+ @result_queue.enq(result)
67
+ if result == :failure
68
+ @failure_encountered = true
69
+ break
70
+ end
71
+ end
72
+ ensure
73
+ @result_queue.enq(:end_of_work)
74
+ end
75
+ not @failure_encountered
76
+ end
77
+
78
+ end
File without changes
File without changes
@@ -1,127 +1,165 @@
1
- require 'gosu'
2
-
3
- class ZIndex
4
- LAYERS = [:world, :dead, :human, :zombie, :overlay]
5
-
6
- def self.for(type); LAYERS.index(type) end
7
- end
8
-
9
- class Actor
10
-
11
- def self.window=(window); @window = window end
12
- def self.window; @window end
13
-
14
- def self.sprites
15
- @sprites ||= Dir[File.join(File.dirname(__FILE__),'sprites/*.png')].inject({}) do |sprites,f|
16
- sprite = File.basename(f,'.*').split('-')
17
- sprites[sprite.first] ||= {}
18
- sprites[sprite.first][sprite.last] = Gosu::Image.new(window, f, false)
19
- sprites
20
- end
21
- end
22
-
23
- def image
24
- #self.class.sprites['robot']['idle'] #FIXME adjust this to indicate human versus zombie, and status of alive, dying or dead
25
- self.class.sprites[actor_type][actor_state]
26
- end
27
-
28
- def actor_type
29
- raise NotImplementedError
30
- end
31
-
32
- def draw
33
- image.draw_rot(x, y, z, actor_direction)
34
- end
35
-
36
- def x
37
- max_position = Window.width - 10
38
- left_offset = 10
39
- left_offset + ((@successful_step_count * 10) * (max_position - left_offset) / [test_suite_size * 10 + 10, (max_position - left_offset)].max).round
40
- end
41
-
42
- def y
43
- 100
44
- end
45
-
46
- def z
47
- #(data['state'] == 'dead') ? ZIndex.for(:dead) : ZIndex.for(data['type'].to_sym)
48
- ZIndex.for(:human)
49
- end
50
-
51
- def window
52
- self.class.window
53
- end
54
- end
55
-
56
- class Window < Gosu::Window
57
- @width = 400
58
- @height = 300
59
-
60
- def self.width=(width); @width = width end
61
- def self.width; @width end
62
-
63
- def self.height=(height); @height = height end
64
- def self.height; @height end
65
-
66
- attr_accessor :grid
67
- attr_writer :human, :current_zombie
68
-
69
- def initialize
70
- super(self.class.width, self.class.height, false)
71
-
72
- self.caption = 'Zombie-chaser'
73
- self.grid = 1
74
-
75
- @grass = Gosu::Image.new(self, File.join(File.dirname(__FILE__),'tiles/grass.png'), true)
76
- @shrubbery = Gosu::Image.new(self, File.join(File.dirname(__FILE__),'tiles/shrubbery.png'), true)
77
- end
78
-
79
- def draw
80
- draw_scenery
81
- draw_human
82
- draw_zombie
83
- end
84
-
85
- def button_down(id)
86
- close if id == Gosu::Button::KbEscape
87
- end
88
-
89
- # private
90
-
91
- def tile_positions
92
- w, h = @grass.width, @grass.height
93
- @tile_positions ||= {
94
- :x => (0...width).to_a.inject([]) {|a,x| a << x if x % w == 0; a},
95
- :y => (0...height).to_a.inject([]) {|a,y| a << y if y % h == 0; a}
96
- }
97
- end
98
-
99
- def map
100
- @map ||= tile_positions[:y].map do |y|
101
- tile_positions[:x].map do |x|
102
- {
103
- :x => x,
104
- :y => y,
105
- :tile => (rand(32) % 32 == 0) ? @shrubbery : @grass
106
- }
107
- end
108
- end
109
- end
110
-
111
- def draw_scenery
112
- map.each do |row|
113
- row.each do |col|
114
- col[:tile].draw(col[:x], col[:y], ZIndex.for(:world))
115
- end
116
- end
117
- end
118
-
119
- def draw_human
120
- @human.draw
121
- end
122
-
123
- def draw_zombie
124
- @current_zombie.draw if defined?(@current_zombie)
125
- end
126
-
127
- end
1
+ begin
2
+ require 'gosu'
3
+ rescue LoadError => e
4
+ require 'ostruct'
5
+ module Gosu
6
+ class Window
7
+ attr_accessor :caption, :grid
8
+ def initialize(one, two, three)
9
+ abort "Gosu not installed. Please use the --console option, or install gosu"
10
+ end
11
+ end
12
+
13
+ class Image
14
+ def initialize(*args)
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ class ZIndex
21
+ LAYERS = [:world, :dead, :actor, :attacking, :overlay]
22
+
23
+ def self.for(type); LAYERS.index(type) end
24
+ end
25
+
26
+ class Actor
27
+
28
+ def self.window=(window); @window = window end
29
+ def self.window; @window end
30
+
31
+ def self.sprites
32
+ @sprites ||= Dir[File.join(File.dirname(__FILE__),'sprites/*.png')].inject({}) do |sprites,f|
33
+ sprite = File.basename(f,'.*').split('-')
34
+ sprites[sprite.first] ||= {}
35
+ sprites[sprite.first][sprite.last] = Gosu::Image.new(window, f, false)
36
+ sprites
37
+ end
38
+ end
39
+
40
+ def image
41
+ #self.class.sprites['robot']['idle'] #FIXME adjust this to indicate human versus zombie, and status of alive, dying or dead
42
+ self.class.sprites[actor_type][actor_state]
43
+ end
44
+
45
+ def actor_type
46
+ raise NotImplementedError
47
+ end
48
+
49
+ def draw
50
+ raise "actor is off the screen" unless (x > 0 and x < self.class.window.width and y > 0 and y < self.class.window.height)
51
+ image.draw_rot(x, y, z, actor_direction)
52
+ end
53
+
54
+ def calculate_x(successful_step_count)
55
+ preferred_step_size = 10
56
+ max_distance = ([Window.width, Window.height].min / 2) - preferred_step_size
57
+ (Window.width / 2) + Math::sin(@angle) * ((test_suite_size - successful_step_count) * preferred_step_size) * [1, max_distance * 1.0 / (test_suite_size * preferred_step_size)].min
58
+ end
59
+
60
+ def calculate_y(successful_step_count)
61
+ preferred_step_size = 10
62
+ max_distance = ([Window.width, Window.height].min / 2) - preferred_step_size
63
+ ((Window.height / 2) + Math::cos(@angle) * ((test_suite_size - successful_step_count) * preferred_step_size) * [1, max_distance * 1.0 / (test_suite_size * preferred_step_size)].min)
64
+ end
65
+
66
+ def x
67
+ calculate_x(@successful_step_count)
68
+ end
69
+
70
+ def y
71
+ calculate_y(@successful_step_count)
72
+ end
73
+
74
+ def z
75
+ case actor_state
76
+ when "dead" then ZIndex.for(:dead)
77
+ when "attacking" then ZIndex.for(:attacking)
78
+ when "moving" then ZIndex.for(:actor)
79
+ when "dying" then ZIndex.for(:actor)
80
+ else raise "Unknown state"
81
+ end
82
+ end
83
+
84
+ def window
85
+ self.class.window
86
+ end
87
+ end
88
+
89
+ class Window < Gosu::Window
90
+ @width = 400
91
+ @height = 300
92
+
93
+ def self.width=(width); @width = width end
94
+ def self.width; @width end
95
+
96
+ def self.height=(height); @height = height end
97
+ def self.height; @height end
98
+
99
+ attr_accessor :grid
100
+ attr_writer :human, :zombie_list
101
+
102
+ def initialize
103
+ super(self.class.width, self.class.height, false)
104
+
105
+ self.caption = 'Zombie-chaser'
106
+ self.grid = 1
107
+
108
+ @grass = Gosu::Image.new(self, File.join(File.dirname(__FILE__),'tiles/grass.png'), true)
109
+ @shrubbery = Gosu::Image.new(self, File.join(File.dirname(__FILE__),'tiles/shrubbery.png'), true)
110
+ end
111
+
112
+ def draw
113
+ draw_scenery
114
+ draw_human
115
+ draw_zombies
116
+ end
117
+
118
+ def button_down(id)
119
+ close if id == Gosu::Button::KbEscape
120
+ end
121
+
122
+ # private
123
+
124
+ def tile_positions
125
+ w, h = @grass.width, @grass.height
126
+ @tile_positions ||= {
127
+ :x => (0...width).to_a.inject([]) {|a,x| a << x if x % w == 0; a},
128
+ :y => (0...height).to_a.inject([]) {|a,y| a << y if y % h == 0; a}
129
+ }
130
+ end
131
+
132
+ def map
133
+ @map ||= tile_positions[:y].map do |y|
134
+ tile_positions[:x].map do |x|
135
+ {
136
+ :x => x,
137
+ :y => y,
138
+ :tile => (rand(32) % 32 == 0) ? @shrubbery : @grass
139
+ }
140
+ end
141
+ end
142
+ end
143
+
144
+ def draw_scenery
145
+ map.each do |row|
146
+ row.each do |col|
147
+ col[:tile].draw(col[:x], col[:y], ZIndex.for(:world))
148
+ end
149
+ end
150
+ end
151
+
152
+ def draw_human
153
+ @human.draw if defined?(@human)
154
+ end
155
+
156
+ def draw_zombies
157
+ @zombie_list.draw_zombies if defined?(@zombie_list)
158
+ end
159
+
160
+ #No longer a major issue now zombies approach from all directions in GUI mode
161
+ def no_living_zombies_apart_from_me?(desired_step_count, actor)
162
+ true
163
+ end
164
+
165
+ end
@@ -1,98 +1,105 @@
1
- require "human"
2
- require "interface"
3
-
4
- class World
5
- @interface_type = :gui_interface
6
-
7
- def self.interface_type=(interface_type); @interface_type = interface_type end
8
- def self.interface_type; @interface_type end
9
-
10
- attr_reader :interface
11
-
12
- def self.new_using_results(human_results, zombies_results)
13
- world = new(:no_interface)
14
- human = MockHuman.new_using_results(human_results, world)
15
- zombie_list = MockZombieList.new_using_results(zombies_results, world)
16
- world.set_human(human)
17
- world.set_zombie_list(zombie_list)
18
- world
19
- end
20
-
21
- def self.new_using_test_unit_handler(test_pattern)
22
- world = new(self.interface_type)
23
- human = Human.new_using_test_unit_handler(test_pattern, world)
24
- zombie_list = MockZombieList.new_using_results([], world) #Fixme
25
- world.set_human(human)
26
- world.set_zombie_list(zombie_list)
27
- world.set_test_pattern(test_pattern)
28
- world
29
- end
30
-
31
- def initialize(interface_type)
32
- @human = nil
33
- @current_zombie = nil
34
- @zombie_list = nil
35
- @test_pattern = nil
36
- @interface = case interface_type
37
- when :console_interface then ConsoleInterface.new
38
- when :no_interface then NoInterface.new
39
- when :gui_interface then GuiInterface.new
40
- end
41
- end
42
-
43
- def set_human(human)
44
- raise "Already set" unless @human.nil?
45
- @human = human
46
- interface.human = human
47
- end
48
-
49
- def set_zombie_list(zombie_list)
50
- raise "Already set" unless @zombie_list.nil?
51
- @zombie_list = zombie_list
52
- end
53
-
54
- def set_test_pattern(test_pattern)
55
- raise "Already set" unless @test_pattern.nil?
56
- @test_pattern = test_pattern
57
- end
58
-
59
- #FIXME currently only used by the unit tests. It is equivalent to ZombieTestChaser.validate
60
- def run
61
- run_human
62
- until (@human.dead? or @zombie_list.all_slain?)
63
- run_zombie(@zombie_list.supply_next_zombie)
64
- end
65
- @interface.finish
66
- end
67
-
68
- def run_human
69
- @human.run
70
- @human.finish_dying if @human.dying?
71
- ! @human.dead?
72
- end
73
-
74
- def create_zombie_using_test_unit_handler
75
- raise "@test_pattern not defined?" if @test_pattern.nil?
76
- zombie = Zombie.new_using_test_unit_handler(@test_pattern, self)
77
- end
78
-
79
- def run_zombie(zombie)
80
- @current_zombie = zombie
81
- @interface.current_zombie = zombie
82
- sleep 0.2
83
- @current_zombie.run
84
- if @current_zombie.dying?
85
- @current_zombie.finish_dying
86
- else
87
- @current_zombie.eat(@human)
88
- sleep 1
89
- end
90
- ! @current_zombie.dead?
91
- end
92
-
93
- def something_happened
94
- @interface.something_happened
95
- end
96
-
97
- end
98
-
1
+ require "zombie-chaser/human"
2
+ require "zombie-chaser/interface"
3
+
4
+ class World
5
+ @interface_type = :gui_interface
6
+
7
+ def self.interface_type=(interface_type); @interface_type = interface_type end
8
+ def self.interface_type; @interface_type end
9
+
10
+ attr_reader :interface
11
+
12
+ def self.new_using_results(human_results, zombies_results)
13
+ world = new(:no_interface)
14
+ human = MockHuman.new_using_results(human_results, world)
15
+ zombie_list = MockZombieList.new_using_results(zombies_results, world)
16
+ world.set_human(human)
17
+ world.set_zombie_list(zombie_list)
18
+ world
19
+ end
20
+
21
+ def self.new_using_test_unit_handler(test_pattern)
22
+ world = new(self.interface_type)
23
+ human = Human.new_using_test_unit_handler(test_pattern, world)
24
+ zombie_list = ZombieList.new_using_test_unit_handler(test_pattern, world)
25
+ world.set_human(human)
26
+ world.set_zombie_list(zombie_list)
27
+ world
28
+ end
29
+
30
+ def initialize(interface_type)
31
+ @human = nil
32
+ @zombie_list = nil
33
+ @interface = case interface_type
34
+ when :console_interface then ConsoleInterface.new
35
+ when :no_interface then NoInterface.new
36
+ when :gui_interface then GuiInterface.new
37
+ end
38
+ @view_update_threads = nil
39
+ @collision_detection_lock = Monitor.new
40
+ end
41
+
42
+ def set_human(human)
43
+ raise "Already set" unless @human.nil?
44
+ @human = human
45
+ interface.human = human
46
+ end
47
+
48
+ def set_zombie_list(zombie_list)
49
+ raise "Already set" unless @zombie_list.nil?
50
+ @zombie_list = zombie_list
51
+ @interface.zombie_list = zombie_list
52
+ end
53
+
54
+ def while_world_running
55
+ @view_update_threads = Queue.new
56
+ yield
57
+ @view_update_threads.enq(:end_of_work)
58
+ thread = @view_update_threads.deq
59
+ until thread == :end_of_work
60
+ thread.join
61
+ thread = @view_update_threads.deq
62
+ end
63
+ @interface.finish_if_neccessary
64
+ end
65
+
66
+ def run_human
67
+ @human.run
68
+ ! @human.dead?
69
+ end
70
+
71
+ def run_next_zombie
72
+ # Since zombies can come from multiple directions, rather than queueing against each other,
73
+ # separating out when they appear isn't required
74
+ zombie = @zombie_list.supply_next_zombie
75
+ @view_update_threads.enq(Thread.new{zombie.build_view_queue})
76
+ @view_update_threads.enq(Thread.new{zombie.update_view})
77
+ zombie.run_tests
78
+ end
79
+
80
+ def synchronize_for_collision_detection
81
+ @collision_detection_lock.synchronize {yield}
82
+ end
83
+
84
+ def something_happened
85
+ @interface.something_happened
86
+ end
87
+
88
+ def sleep(duration)
89
+ @interface.sleep(duration)
90
+ end
91
+
92
+ def notify_human_eaten
93
+ @human.get_eaten
94
+ end
95
+
96
+ #Assumption: this is called after human is in a valid state
97
+ def human_dead?
98
+ @human.dead?
99
+ end
100
+
101
+ def no_living_zombies_apart_from_me?(desired_step_count, actor)
102
+ @interface.no_living_zombies_apart_from_me?(desired_step_count, actor)
103
+ end
104
+ end
105
+