rubygoal 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,217 @@
1
+ require 'forwardable'
2
+
3
+ require 'rubygoal/config'
4
+ require 'rubygoal/formation'
5
+ require 'rubygoal/field_metrics'
6
+ require 'rubygoal/player'
7
+
8
+ module Rubygoal
9
+ class Team
10
+ attr_reader :game, :players, :side, :coach, :formation
11
+ attr_accessor :goalkeeper, :positions
12
+
13
+ INFINITE = 100_000
14
+
15
+ extend Forwardable
16
+ def_delegators :coach, :name
17
+
18
+ def initialize(game_window, side, coach)
19
+ @game = game_window
20
+ @players = []
21
+ @side = side
22
+ @coach = coach
23
+
24
+ initialize_formation
25
+ initialize_players(game_window)
26
+ end
27
+
28
+ def players_to_initial_position
29
+ positions = FieldMetrics.initial_player_positions(side)
30
+ players.each_with_index do |player, index|
31
+ player.position = positions[index]
32
+ end
33
+ end
34
+
35
+ def update(match)
36
+ self.formation = coach.formation(match)
37
+ unless formation.valid?
38
+ puts formation.errors
39
+ raise "Invalid formation: #{coach.name}"
40
+ end
41
+ update_positions(formation.lineup)
42
+
43
+ player_to_move = nil
44
+ min_distance_to_ball = INFINITE
45
+ players.each do |player|
46
+ pass_or_shoot(player) if player.can_kick?(game.ball)
47
+
48
+ distance_to_ball = player.distance(game.ball.position)
49
+ if min_distance_to_ball > distance_to_ball
50
+ min_distance_to_ball = distance_to_ball
51
+ player_to_move = player
52
+ end
53
+ end
54
+
55
+ player_to_move.move_to(game.ball.position)
56
+
57
+ average_players = []
58
+ fast_players = []
59
+ captain_player = nil
60
+
61
+ players.each do |player|
62
+ if player.is_a? AveragePlayer
63
+ average_players << player
64
+ elsif player.is_a? FastPlayer
65
+ fast_players << player
66
+ else
67
+ captain_player = player
68
+ end
69
+ end
70
+
71
+ if captain_player != player_to_move
72
+ captain_player.move_to(positions[:captain])
73
+ end
74
+ captain_player.update
75
+
76
+ average_players.each_with_index do |player, index|
77
+ if player != player_to_move
78
+ player.move_to(positions[:average][index])
79
+ end
80
+
81
+ player.update
82
+ end
83
+
84
+ fast_players.each_with_index do |player, index|
85
+ if player != player_to_move
86
+ player.move_to(positions[:fast][index])
87
+ end
88
+
89
+ player.update
90
+ end
91
+ end
92
+
93
+ def draw
94
+ players.each(&:draw)
95
+ end
96
+
97
+ private
98
+
99
+ attr_writer :formation
100
+
101
+ def initialize_formation
102
+ @formation = Formation.new
103
+ @formation.lineup = [
104
+ [:average, :none, :average, :none, :none ],
105
+ [:average, :none, :fast, :none, :captain],
106
+ [:none, :none, :none, :none, :none ],
107
+ [:average, :none, :fast, :none, :fast ],
108
+ [:average, :none, :average, :none, :none ]
109
+ ]
110
+ end
111
+
112
+ def initialize_players(game_window)
113
+ Config.team.average_players_count.times do
114
+ players << AveragePlayer.new(game_window, side)
115
+ end
116
+ Config.team.fast_players_count.times do
117
+ players << FastPlayer.new(game_window, side)
118
+ end
119
+ Config.team.captain_players_count.times do
120
+ players << CaptainPlayer.new(game_window, side)
121
+ end
122
+
123
+ players_to_initial_position
124
+ end
125
+
126
+ def pass_or_shoot(player)
127
+ # Kick straight to the goal whether the distance is short (200)
128
+ # or we don't have a better option
129
+ target = shoot_target
130
+
131
+ unless FieldMetrics.close_to_goal?(player.position, opponent_side)
132
+ if teammate = nearest_forward_teammate(player)
133
+ target = teammate.position
134
+ end
135
+ end
136
+
137
+ player.kick(game.ball, target)
138
+ end
139
+
140
+ def nearest_forward_teammate(player)
141
+ min_dist = INFINITE
142
+ nearest_teammate = nil
143
+
144
+ (players - [player]).each do |teammate|
145
+ if side == :home
146
+ is_forward = teammate.position.x > player.position.x + 40
147
+ else
148
+ is_forward = teammate.position.x < player.position.x - 40
149
+ end
150
+
151
+ if is_forward
152
+ dist = player.distance(teammate.position)
153
+ if min_dist > dist
154
+ nearest_teammate = teammate
155
+ min_dist = dist
156
+ end
157
+ end
158
+ end
159
+
160
+ nearest_teammate
161
+ end
162
+
163
+ def opponent_side
164
+ if side == :home
165
+ :away
166
+ else
167
+ :home
168
+ end
169
+ end
170
+
171
+ def shoot_target
172
+ # Do not kick always to the center, look for the sides of the goal
173
+ limit = Config.field.goal_height / 2
174
+ offset = Random.rand(-limit..limit)
175
+
176
+ target = FieldMetrics.goal_position(opponent_side)
177
+ target.y += offset
178
+ target
179
+ end
180
+
181
+ def update_positions(lineup)
182
+ self.positions = {
183
+ average: [FieldMetrics.goalkeeper_position(side)],
184
+ fast: []
185
+ }
186
+
187
+ lineup.each_with_index do |row, i|
188
+ row.each_with_index do |player, j|
189
+ if player == :average
190
+ positions[:average] << matrix_to_position(i, j)
191
+ elsif player == :captain
192
+ positions[:captain] = matrix_to_position(i, j)
193
+ elsif player == :fast
194
+ positions[:fast] << matrix_to_position(i, j)
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ def matrix_to_position(i, j)
201
+ step_x = Config.field.width / 6
202
+ step_y = Config.field.height / 6
203
+ if side == :home
204
+ Config.field.offset.add(
205
+ Position.new((j+1) * step_x - 30, (i+1) * step_y)
206
+ )
207
+ else
208
+ Config.field.offset.add(
209
+ Position.new(
210
+ Config.field.width - (j+1) * step_x + 30,
211
+ Config.field.height - (i+1) * step_y
212
+ )
213
+ )
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,3 @@
1
+ module Rubygoal
2
+ VERSION = Gem::Version.new '0.0.1'
3
+ end
data/lib/rubygoal.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'rubygoal/game'
2
+
3
+ module Rubygoal
4
+ def self.start
5
+ Game.new.show
6
+ end
7
+ end
Binary file
Binary file
Binary file
data/media/ball.png ADDED
Binary file
Binary file
Binary file
Binary file
Binary file
data/media/goal.png ADDED
Binary file
@@ -0,0 +1,66 @@
1
+ require 'minitest/autorun'
2
+
3
+ require 'rubygoal/formation'
4
+
5
+ module Rubygoal
6
+ class TestFormation < Minitest::Test
7
+ def setup
8
+ @formation = Formation.new
9
+ end
10
+
11
+ def test_valid_formation
12
+ @formation.lineup = [
13
+ [:average, :none, :average, :none, :none],
14
+ [:fast, :none, :none, :average, :none],
15
+ [:none, :none, :captain, :none, :fast],
16
+ [:fast, :none, :none, :none, :average],
17
+ [:average, :none, :average, :none, :none],
18
+ ]
19
+ assert_equal @formation.valid?, true
20
+ end
21
+
22
+ def test_less_players
23
+ @formation.lineup = [
24
+ [:average, :none, :average, :none, :none],
25
+ [:fast, :none, :none, :none, :none],
26
+ [:none, :none, :captain, :none, :fast],
27
+ [:fast, :none, :none, :none, :average],
28
+ [:average, :none, :average, :none, :none],
29
+ ]
30
+ assert_equal @formation.valid?, false
31
+ end
32
+
33
+ def test_more_players
34
+ @formation.lineup = [
35
+ [:average, :none, :average, :none, :average],
36
+ [:fast, :none, :none, :average, :none],
37
+ [:none, :none, :captain, :none, :fast],
38
+ [:fast, :none, :none, :none, :average],
39
+ [:average, :none, :average, :none, :none],
40
+ ]
41
+ assert_equal @formation.valid?, false
42
+ end
43
+
44
+ def test_more_than_one_captain
45
+ @formation.lineup = [
46
+ [:average, :none, :average, :none, :none],
47
+ [:fast, :none, :none, :captain, :none],
48
+ [:none, :none, :captain, :none, :fast],
49
+ [:fast, :none, :none, :none, :average],
50
+ [:average, :none, :average, :none, :none],
51
+ ]
52
+ assert_equal @formation.valid?, false
53
+ end
54
+
55
+ def test_more_than_three_fast
56
+ @formation.lineup = [
57
+ [:average, :none, :average, :none, :none],
58
+ [:fast, :none, :none, :fast, :none],
59
+ [:none, :none, :captain, :none, :fast],
60
+ [:fast, :none, :none, :none, :average],
61
+ [:average, :none, :average, :none, :none],
62
+ ]
63
+ assert_equal @formation.valid?, false
64
+ end
65
+ end
66
+ end