rubygoal 2.0.0 → 2.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. checksums.yaml +4 -4
  2. data/bin/rubygoal +12 -2
  3. data/lib/rubygoal.rb +1 -18
  4. data/lib/rubygoal/ball.rb +60 -0
  5. data/lib/rubygoal/coach.rb +81 -0
  6. data/lib/rubygoal/coach_definition.rb +54 -0
  7. data/lib/rubygoal/coach_loader.rb +55 -0
  8. data/lib/rubygoal/coaches/coach_definition_away.rb +72 -0
  9. data/lib/rubygoal/coaches/coach_definition_home.rb +76 -0
  10. data/lib/rubygoal/configuration.rb +49 -0
  11. data/lib/rubygoal/coordinate.rb +33 -0
  12. data/lib/rubygoal/field.rb +134 -0
  13. data/lib/rubygoal/formation.rb +73 -0
  14. data/lib/rubygoal/formation/formation_dsl.rb +67 -0
  15. data/lib/rubygoal/game.rb +162 -0
  16. data/lib/rubygoal/goal.rb +26 -0
  17. data/lib/rubygoal/match_data.rb +130 -0
  18. data/lib/rubygoal/moveable.rb +68 -0
  19. data/lib/rubygoal/player.rb +87 -0
  20. data/lib/rubygoal/players/average.rb +16 -0
  21. data/lib/rubygoal/players/captain.rb +15 -0
  22. data/lib/rubygoal/players/fast.rb +16 -0
  23. data/lib/rubygoal/players/goalkeeper.rb +26 -0
  24. data/lib/rubygoal/players/player_movement.rb +98 -0
  25. data/lib/rubygoal/recorder.rb +53 -0
  26. data/lib/rubygoal/simulator.rb +33 -0
  27. data/lib/rubygoal/team.rb +198 -0
  28. data/lib/rubygoal/teams/away.rb +15 -0
  29. data/lib/rubygoal/teams/home.rb +15 -0
  30. data/lib/rubygoal/util.rb +36 -0
  31. data/lib/rubygoal/version.rb +3 -0
  32. metadata +35 -23
  33. data/lib/rubygoal/gui.rb +0 -20
  34. data/lib/rubygoal/gui/ball.rb +0 -26
  35. data/lib/rubygoal/gui/field.rb +0 -21
  36. data/lib/rubygoal/gui/game.rb +0 -166
  37. data/lib/rubygoal/gui/goal.rb +0 -23
  38. data/lib/rubygoal/gui/players.rb +0 -28
  39. data/lib/rubygoal/gui/version.rb +0 -5
  40. data/media/average_away.png +0 -0
  41. data/media/average_home.png +0 -0
  42. data/media/background.png +0 -0
  43. data/media/ball.png +0 -0
  44. data/media/captain_away.png +0 -0
  45. data/media/captain_home.png +0 -0
  46. data/media/fast_away.png +0 -0
  47. data/media/fast_home.png +0 -0
  48. data/media/goal.png +0 -0
@@ -0,0 +1,53 @@
1
+ require 'rubygoal/game'
2
+
3
+ module Rubygoal
4
+ class Recorder
5
+ def initialize(game)
6
+ @game = game
7
+ @frames = []
8
+ end
9
+
10
+ def update
11
+ @frames << frame_info
12
+ end
13
+
14
+ def to_hash
15
+ {
16
+ teams: {
17
+ home: @game.coach_home.name,
18
+ away: @game.coach_away.name
19
+ },
20
+ score: [@game.score_home, @game.score_away],
21
+ frames: @frames
22
+ }
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :game, :frames
28
+
29
+ def frame_info
30
+ {
31
+ time: @game.time.round(0),
32
+ score: [@game.score_home, @game.score_away],
33
+ ball: [
34
+ @game.ball.position.x.round(0),
35
+ @game.ball.position.y.round(0)
36
+ ],
37
+ home: team_info(@game.team_home),
38
+ away: team_info(@game.team_away)
39
+ }
40
+ end
41
+
42
+ def team_info(team)
43
+ team.players.map do |_, player|
44
+ [
45
+ player.position.x.round(0),
46
+ player.position.y.round(0),
47
+ player.rotation.round(0),
48
+ player.type[0]
49
+ ]
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,33 @@
1
+ require 'timecop'
2
+ require 'json'
3
+ require 'rubygoal/game'
4
+
5
+ module Rubygoal
6
+ class Simulator
7
+ extend Forwardable
8
+ def_delegators :game, :recorded_game
9
+
10
+ def initialize
11
+ Rubygoal.configuration.record_game = true
12
+ @game = Rubygoal::Game.new(load_coach(:home), load_coach(:away))
13
+ end
14
+
15
+ def simulate
16
+ time = Time.now
17
+
18
+ while !game.ended? do
19
+ game.update
20
+ time += 1.0 / 60.0
21
+ Timecop.travel(time)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :game
28
+
29
+ def load_coach(side)
30
+ CoachLoader.new(side).coach
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,198 @@
1
+ require 'forwardable'
2
+
3
+ require 'rubygoal/formation'
4
+ require 'rubygoal/field'
5
+ require 'rubygoal/players/average'
6
+ require 'rubygoal/players/fast'
7
+ require 'rubygoal/players/captain'
8
+ require 'rubygoal/players/goalkeeper'
9
+ require 'rubygoal/match_data'
10
+
11
+ module Rubygoal
12
+ class Team
13
+ attr_reader :players, :side, :opponent_side, :coach, :formation
14
+ attr_accessor :goalkeeper
15
+
16
+ INFINITE = 100_000
17
+
18
+ extend Forwardable
19
+ def_delegators :coach, :name
20
+ def_delegators :game, :ball
21
+
22
+ def initialize(game, coach)
23
+ @game = game
24
+ @players = {}
25
+ @coach = coach
26
+
27
+ @match_data_factory = MatchData::Factory.new(game, side)
28
+
29
+ initialize_lineup_values
30
+ initialize_players
31
+ initialize_formation
32
+ end
33
+
34
+ def players_to_initial_position
35
+ match_data = match_data_factory.create
36
+ formation = coach.formation(match_data)
37
+ restart_player_positions_in_own_field(formation)
38
+ end
39
+
40
+ def update(elapsed_time)
41
+ match_data = match_data_factory.create
42
+ self.formation = coach.formation(match_data)
43
+
44
+ unless formation.valid?
45
+ puts formation.errors
46
+ raise "Invalid formation: #{coach.name}"
47
+ end
48
+
49
+ update_coach_defined_positions(formation)
50
+
51
+ player_to_move = nil
52
+ min_distance_to_ball = INFINITE
53
+ players_list.each do |player|
54
+ pass_or_shoot(player) if player.can_kick?(ball)
55
+
56
+ distance_to_ball = player.distance(ball.position)
57
+ if min_distance_to_ball > distance_to_ball
58
+ min_distance_to_ball = distance_to_ball
59
+ player_to_move = player
60
+ end
61
+ end
62
+
63
+ player_to_move.move_to(ball.position)
64
+
65
+ players.each do |name, player|
66
+ if name == :goalkeeper
67
+ if player != player_to_move
68
+ player.move_to_cover_goal(ball)
69
+ player.update(elapsed_time)
70
+ next
71
+ end
72
+ end
73
+
74
+ player.move_to_coach_position unless player == player_to_move
75
+ player.update(elapsed_time)
76
+ end
77
+ end
78
+
79
+ def players_list
80
+ players.values
81
+ end
82
+
83
+ def players_position
84
+ players.each_with_object({}) do |(name, player), hash|
85
+ hash[name] = Field.field_position(player.position, side)
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ attr_reader :game, :match_data_factory
92
+ attr_writer :formation
93
+
94
+ def initialize_lineup_values
95
+ @average_players_count = 6
96
+ @fast_players_count = 3
97
+ end
98
+
99
+ def initialize_formation
100
+ @formation = @coach.initial_formation
101
+ end
102
+
103
+ def initialize_players
104
+ @players = { goalkeeper: GoalKeeperPlayer.new(game, side) }
105
+
106
+ unless @coach.valid?
107
+ puts @coach.errors
108
+ raise "Invalid team definition: #{@coach.name}"
109
+ end
110
+
111
+ @players[@coach.captain_player.name] = CaptainPlayer.new(game, side)
112
+
113
+ @coach.players_by_type(:fast).each do |player_def|
114
+ @players[player_def.name] = FastPlayer.new(game, side)
115
+ end
116
+
117
+ @coach.players_by_type(:average).each do |player_def|
118
+ @players[player_def.name] = AveragePlayer.new(game, side)
119
+ end
120
+
121
+ initialize_player_positions
122
+ end
123
+
124
+ def pass_or_shoot(player)
125
+ # Kick straight to the goal whether the distance is short (200)
126
+ # or we don't have a better option
127
+ target = shoot_target
128
+
129
+ unless Field.close_to_goal?(player.position, opponent_side)
130
+ if teammate = nearest_forward_teammate(player)
131
+ target = teammate.position
132
+ end
133
+ end
134
+
135
+ player.kick(ball, target)
136
+ end
137
+
138
+ def nearest_forward_teammate(player)
139
+ min_dist = INFINITE
140
+ nearest_teammate = nil
141
+
142
+ (players.values - [player]).each do |teammate|
143
+ if teammate_is_on_front?(player, teammate)
144
+ dist = player.distance(teammate.position)
145
+ if min_dist > dist
146
+ nearest_teammate = teammate
147
+ min_dist = dist
148
+ end
149
+ end
150
+ end
151
+
152
+ nearest_teammate
153
+ end
154
+
155
+ def shoot_target
156
+ # Do not kick always to the center, look for the sides of the goal
157
+ limit = Field::GOAL_HEIGHT / 2
158
+ offset = Random.rand(-limit..limit)
159
+
160
+ target = Field.goal_position(opponent_side)
161
+ target.y += offset
162
+ target
163
+ end
164
+
165
+ def initialize_player_positions
166
+ Field.default_player_field_positions.each_with_index do |pos, index|
167
+ players.values[index].position = lineup_to_position(pos)
168
+ players.values[index].coach_defined_position = lineup_to_position(pos)
169
+ end
170
+ end
171
+
172
+ def update_coach_defined_positions(formation)
173
+ formation.players_position.each do |player_name, pos|
174
+ players[player_name].coach_defined_position = lineup_to_position(pos)
175
+ end
176
+ end
177
+
178
+ def restart_player_positions_in_own_field(formation)
179
+ formation.players_position.each do |player_name, pos|
180
+ pos.x *= 0.5
181
+ pos = lineup_to_position(pos)
182
+
183
+ player = players[player_name]
184
+
185
+ player.coach_defined_position = pos
186
+ player.position = pos
187
+ end
188
+ end
189
+
190
+ def lineup_to_position(field_position)
191
+ Field.absolute_position(field_position, side)
192
+ end
193
+
194
+ def goalkeeper
195
+ players[:goalkeeper]
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,15 @@
1
+ require 'rubygoal/team'
2
+
3
+ module Rubygoal
4
+ class AwayTeam < Team
5
+ def initialize(*args)
6
+ @side = :away
7
+ @opponent_side = :home
8
+ super
9
+ end
10
+
11
+ def teammate_is_on_front?(player, teammate)
12
+ teammate.position.x < player.position.x - 40
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'rubygoal/team'
2
+
3
+ module Rubygoal
4
+ class HomeTeam < Team
5
+ def initialize(*args)
6
+ @side = :home
7
+ @opponent_side = :away
8
+ super
9
+ end
10
+
11
+ def teammate_is_on_front?(player, teammate)
12
+ teammate.position.x > player.position.x + 40
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,36 @@
1
+ module Rubygoal
2
+ module Util
3
+ class << self
4
+ def offset_x(angle, distance)
5
+ distance * Math.cos(angle * Math::PI / 180.0)
6
+ end
7
+
8
+ def offset_y(angle, distance)
9
+ distance * Math.sin(angle * Math::PI / 180.0)
10
+ end
11
+
12
+ def distance(x1, y1, x2, y2)
13
+ Math.hypot(x2 - x1, y2 - y1)
14
+ end
15
+
16
+ def angle(x1, y1, x2, y2)
17
+ Math.atan2(y2 - y1, x2 - x1) / Math::PI * 180.0
18
+ end
19
+
20
+ def positive_angle(x1, y1, x2, y2)
21
+ angle = self.angle(x1, y1, x2, y2)
22
+ if angle < 0
23
+ 360 + angle
24
+ else
25
+ angle
26
+ end
27
+ end
28
+
29
+ def y_intercept_with_line(x, pos1, pos2)
30
+ slope = (pos2.y - pos1.y) / (pos2.x - pos1.x)
31
+
32
+ Position.new(x, slope * (x - pos1.x) + pos1.y)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ module Rubygoal
2
+ VERSION = Gem::Version.new '1.1.0'
3
+ end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubygoal
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jorge Bejar
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-01 00:00:00.000000000 Z
11
+ date: 2017-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubygoal-core
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.0.0
19
+ version: '1.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '='
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.0.0
26
+ version: '1.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: gosu
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -50,22 +50,34 @@ files:
50
50
  - README.md
51
51
  - bin/rubygoal
52
52
  - lib/rubygoal.rb
53
- - lib/rubygoal/gui.rb
54
- - lib/rubygoal/gui/ball.rb
55
- - lib/rubygoal/gui/field.rb
56
- - lib/rubygoal/gui/game.rb
57
- - lib/rubygoal/gui/goal.rb
58
- - lib/rubygoal/gui/players.rb
59
- - lib/rubygoal/gui/version.rb
60
- - media/average_away.png
61
- - media/average_home.png
62
- - media/background.png
63
- - media/ball.png
64
- - media/captain_away.png
65
- - media/captain_home.png
66
- - media/fast_away.png
67
- - media/fast_home.png
68
- - media/goal.png
53
+ - lib/rubygoal/ball.rb
54
+ - lib/rubygoal/coach.rb
55
+ - lib/rubygoal/coach_definition.rb
56
+ - lib/rubygoal/coach_loader.rb
57
+ - lib/rubygoal/coaches/coach_definition_away.rb
58
+ - lib/rubygoal/coaches/coach_definition_home.rb
59
+ - lib/rubygoal/configuration.rb
60
+ - lib/rubygoal/coordinate.rb
61
+ - lib/rubygoal/field.rb
62
+ - lib/rubygoal/formation.rb
63
+ - lib/rubygoal/formation/formation_dsl.rb
64
+ - lib/rubygoal/game.rb
65
+ - lib/rubygoal/goal.rb
66
+ - lib/rubygoal/match_data.rb
67
+ - lib/rubygoal/moveable.rb
68
+ - lib/rubygoal/player.rb
69
+ - lib/rubygoal/players/average.rb
70
+ - lib/rubygoal/players/captain.rb
71
+ - lib/rubygoal/players/fast.rb
72
+ - lib/rubygoal/players/goalkeeper.rb
73
+ - lib/rubygoal/players/player_movement.rb
74
+ - lib/rubygoal/recorder.rb
75
+ - lib/rubygoal/simulator.rb
76
+ - lib/rubygoal/team.rb
77
+ - lib/rubygoal/teams/away.rb
78
+ - lib/rubygoal/teams/home.rb
79
+ - lib/rubygoal/util.rb
80
+ - lib/rubygoal/version.rb
69
81
  homepage: https://github.com/wyeworks/rubygoal
70
82
  licenses:
71
83
  - Apache License 2.0
@@ -86,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
98
  version: '0'
87
99
  requirements: []
88
100
  rubyforge_project:
89
- rubygems_version: 2.4.5
101
+ rubygems_version: 2.6.11
90
102
  signing_key:
91
103
  specification_version: 4
92
104
  summary: Rubygoal Game - Soccer game for Rubysts