rubygoal 0.0.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +0,0 @@
1
- module Rubygoal
2
- class Coach
3
- def name
4
- raise NotImplementedError
5
- end
6
-
7
- def formation(match)
8
- raise NotImplementedError
9
- end
10
- end
11
- end
@@ -1,32 +0,0 @@
1
- module Rubygoal
2
- module CoachLoader
3
- class << self
4
- def get(default)
5
- file = ARGV.shift
6
-
7
- if file && File.exists?(file)
8
- load file
9
-
10
- class_name = camelize(File.basename(file, ".rb"))
11
- Rubygoal.const_get(class_name).new
12
- else
13
- if file
14
- puts "File `#{file}` doesn't exist. Using #{default.name}."
15
- end
16
-
17
- default.new
18
- end
19
- end
20
-
21
- private
22
-
23
- def camelize(term)
24
- string = term.to_s
25
- string = string.sub(/^[a-z\d]*/) { $&.capitalize }
26
- string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
27
- string.gsub!('/', '::')
28
- string
29
- end
30
- end
31
- end
32
- end
@@ -1,52 +0,0 @@
1
- require 'rubygoal/coach'
2
- require 'rubygoal/formation'
3
-
4
- module Rubygoal
5
- class CoachAway < Coach
6
- def name
7
- "Danubio"
8
- end
9
-
10
- def formation(match)
11
- formation = Formation.new
12
-
13
- if match.me.winning?
14
- formation.lineup = [
15
- [:average, :none, :average, :none, :none],
16
- [:fast, :none, :none, :average, :none],
17
- [:none, :none, :captain, :none, :fast],
18
- [:fast, :none, :none, :none, :average],
19
- [:average, :none, :average, :none, :none],
20
- ]
21
- elsif match.me.draw?
22
- formation.lineup = [
23
- [:average, :none, :average, :none, :none],
24
- [:fast, :none, :none, :none, :fast],
25
- [:none, :fast, :none, :captain, :none],
26
- [:average, :none, :none, :none, :average],
27
- [:average, :none, :average, :none, :none],
28
- ]
29
- elsif match.me.losing?
30
- if match.time < 30
31
- formation.lineup = [
32
- [:none, :none, :average, :none, :none],
33
- [:average, :none, :none, :none, :average],
34
- [:average, :fast, :none, :captain, :none],
35
- [:average, :none, :fast, :none, :fast],
36
- [:none, :none, :average, :none, :none],
37
- ]
38
- else
39
- formation.lineup = [
40
- [:none, :none, :average, :none, :none],
41
- [:average, :none, :none, :none, :average],
42
- [:fast, :average, :none, :fast, :none],
43
- [:average, :none, :captain, :none, :fast],
44
- [:none, :none, :average, :none, :none],
45
- ]
46
- end
47
- end
48
-
49
- formation
50
- end
51
- end
52
- end
@@ -1,28 +0,0 @@
1
- require 'rubygoal/coach'
2
- require 'rubygoal/formation'
3
-
4
- module Rubygoal
5
- class CoachHome < Coach
6
- def name
7
- "Wanderers"
8
- end
9
-
10
- def formation(match)
11
- formation = Formation.new
12
-
13
- if match.me.winning?
14
- formation.defenders = [:average, :average, :average, :captain, :average]
15
- formation.midfielders = [:average, :none, :fast, :none, :average]
16
- formation.attackers = [:none, :fast, :none, :fast, :none]
17
- elsif match.time < 20
18
- formation.defenders = [:none, :fast, :average, :average, :none]
19
- formation.midfielders = [:average, :average, :captain, :none, :average]
20
- formation.attackers = [:fast, :none, :none, :fast, :average]
21
- else
22
- formation.lineup = match.other.formation.lineup
23
- end
24
-
25
- formation
26
- end
27
- end
28
- end
@@ -1,198 +0,0 @@
1
- # RubyGoal - Fútbol para Rubistas
2
- #
3
- # Este documento contiene varias implementaciones mínimas de un entrenador de RubyGoal.#
4
- #
5
- # Esta clase debe implementar, como mínimo, los métodos `name` y `formation(match)`
6
- # Esta clase debe ser implementada dentro del módulo Rubygoal
7
-
8
- module Rubygoal
9
- class MyCoach < Coach
10
- # Indica el nombre del equipo
11
- # Debe retornar un string
12
- def name
13
- "My team name"
14
- end
15
-
16
- # Este método debe devolver una instancia de Formation indicando como
17
- # se tienen que parar los jugadores en la cancha
18
- #
19
- # Este método es invocado constantemente (varias veces por segundo)
20
- # proporcionando información de como va el partido utilizando el
21
- # parámetro match
22
- def formation(match)
23
- formation = Formation.new
24
-
25
- # La clase Formation tiene varios helpers para ayudar a definir la
26
- # formación del equipo
27
- #
28
- # La cancha se divide en una matriz de 5 por 5
29
- #
30
- # ------------------------------
31
- # | N N N N N |
32
- # | |
33
- # | N N N N N |
34
- # A | | A
35
- # R | N N N N N | R
36
- # C | | C
37
- # O | N N N N N | O
38
- # | |
39
- # | N N N N N |
40
- # ------------------------------
41
- #
42
- # Esto es un ejemplo que posiciona jugadores en columnas de la matriz
43
- #
44
- # Los tipos de jugadores válidos son :average, :fast, :captain
45
- # Se usa :none para las posiciones que no se usen en la línea
46
- #
47
- # Restricciones:
48
- # Exactamente un :captain
49
- # Exactamente tres :fast
50
- # Exactamente seis :average
51
- #
52
- # :captain -> Este jugador es el más rápido y preciso del equipo
53
- # :fast -> Estos jugadores son más rápidos que los demás (aunque más lentos que
54
- # el capitán del equipo)
55
- # :average -> Estos jugadores completan el equipo
56
- #
57
- # El arquero no hay que especificarlo, ya viene incluido por defecto
58
- formation.defenders = [:none, :average, :average, :average, :none]
59
- formation.midfielders = [:average, :fast, :captain, :none, :average]
60
- formation.attackers = [:none, :fast, :none, :fast, :average]
61
-
62
- # Esto produce la siguiente alineación
63
- #
64
- # ------------------------------
65
- # | N N A N N |
66
- # | |
67
- # | A N F N F |
68
- # A | | A
69
- # R | A N C N N | R
70
- # C | | C
71
- # O | A N N N F | O
72
- # | |
73
- # | N N A N A |
74
- # ------------------------------
75
-
76
- formation
77
- end
78
- end
79
-
80
- # Lo siguiente es otra implementación posible de una instancia de Coach
81
-
82
- class AnotherCoach < Coach
83
- def name
84
- "Maeso FC"
85
- end
86
-
87
- # El método formation debe devolver una instancia de Formation
88
- # El siguiten ejemplo muestra como controlar la posición de los jugadores
89
- # de una forma más fina, usando el método `lineup`
90
- #
91
- def formation(match)
92
- formation = Formation.new
93
-
94
- # Por defecto el valor de formation.lineup es
95
- #
96
- # [
97
- # [:none, :none, :none, :none, :none],
98
- # [:none, :none, :none, :none, :none],
99
- # [:none, :none, :none, :none, :none],
100
- # [:none, :none, :none, :none, :none],
101
- # [:none, :none, :none, :none, :none],
102
- # ]
103
- #
104
- # Este valor DEBE sobreescribirse con una formación que incluya las
105
- # cantidades correctas de :average, :fast y :captain
106
- #
107
- # Para este tipo de estrategias es importante siempre considerar que el arco
108
- # que atacas es el de la derecha.
109
- #
110
- # En el siguiente ejemplo, la formación 4322 puede interpretarse
111
- # de la siguiente manera
112
- # | |
113
- # defensa | medio campo | delantera
114
- # [ | |
115
- # [ :average, | :none, :average, :none, | :none ],
116
- # [ :fast, | :none, :none, :average, | :none ],
117
- # [ :none, | :none, :captain, :none, | :fast ],
118
- # [ :fast, | :none, :none, :average, | :average ],
119
- # [ :average, | :none, :average, :none, | :none ],
120
- # ] | |
121
- # | |
122
- #
123
- # Usando `lineup`, la línea mas defensiva son los primeros elementos de
124
- # cada uno de los arrays (:average, :fast, :none, :fast, :average)
125
- #
126
- # La segunda línea (entre la defensa y los mediocampistas) no tiene jugadores
127
- # (son todos :none)
128
- #
129
- # La tercer línea, la que corresponde a los mediocampistas, son el tercer
130
- # elemento de cada array (:average, :none, :captain, :none, :average)
131
- #
132
- # La cuarta línea está ubicada entre los mediocampistas y delanteros
133
- # (:none, :average, :none, :average, :none)
134
- #
135
- # Los últimos elementos de los arrays corresponden a la línea de
136
- # delanteros (:none, :none, :fast, :average, :none)
137
- formation.lineup = [
138
- [:average, :none, :average, :none, :none],
139
- [:fast, :none, :none, :average, :none],
140
- [:none, :none, :captain, :none, :fast],
141
- [:fast, :none, :none, :average, :average],
142
- [:average, :none, :average, :none, :none],
143
- ]
144
-
145
- formation
146
- end
147
- end
148
-
149
- # Otra implementación posible de una instancia de Coach
150
-
151
- # Gran parte de la gracia de este juego está en hacer cambios en la formación
152
- # a medida que va transcurriendo el partido
153
- #
154
- # La instancia de `match` que recibe el método `formation` contiene información
155
- # sobre el partido y el rival de turno
156
- #
157
- # Veamos un ejemplo
158
-
159
- class MyCoach < Coach
160
- def name
161
- "Villa Pancha"
162
- end
163
-
164
- def formation(match)
165
- formation = Formation.new
166
-
167
- # El método `me` trae información sobre mi equipo en el partido
168
- #
169
- # me.winning? indica si estoy ganando
170
- # me.losing? y me.draw? son análogos al anterior :)
171
- # me.score me indica la cantidad exacta de goles que marcó mi equipo
172
- if match.me.winning?
173
- formation.defenders = [:average, :average, :average, :captain, :average]
174
- formation.midfielders = [:average, :none, :fast, :none, :average]
175
- formation.attackers = [:none, :fast, :none, :fast, :none]
176
- #
177
- # El método `time` indica cuanto tiempo (segundos) le queda al partido.
178
- # Devuelve un número entre 120 y 0 (120 cuando comienza el partido)
179
- elsif match.time < 10
180
- formation.defenders = [:none, :average, :average, :average, :none]
181
- formation.midfielders = [:average, :average, :captain, :none, :average]
182
- formation.attackers = [:fast, :fast, :none, :fast, :average]
183
- else
184
- #
185
- # El método `other` devuelve información básica del rival. Tiene los mismos
186
- # métodos que `me`.
187
- #
188
- # En particular, se puede acceder a la formación definida por el equipo
189
- # contrario. En la siguiente linea, a modo de ejemplo, se estableció
190
- # una táctica `espejo` con respecto al rival (posiciono mis jugadores en forma
191
- # simétrica)
192
- formation.lineup = match.other.formation.lineup
193
- end
194
-
195
- formation
196
- end
197
- end
198
- end
@@ -1,64 +0,0 @@
1
- require 'rubygoal/config_definitions'
2
- require 'rubygoal/coordinate'
3
-
4
- module Rubygoal
5
- module Config
6
- field.width = 1392
7
- field.height = 934
8
- field.offset = Position.new(262, 114)
9
- field.goal_height = 275
10
- field.close_to_goal_distance = 275
11
- field.background_image_file = File.dirname(__FILE__) + '/../../media/background.png'
12
-
13
- team.initial_player_positions = [
14
- [50, 466],
15
- [236, 106],
16
- [236, 286],
17
- [236, 646],
18
- [236, 826],
19
- [436, 106],
20
- [436, 286],
21
- [436, 646],
22
- [436, 826],
23
- [616, 436],
24
- [616, 496]
25
- ]
26
- team.average_players_count = 7
27
- team.fast_players_count = 3
28
- team.captain_players_count = 1
29
-
30
-
31
- ball.width = 20
32
- ball.height = 20
33
- ball.image_file = File.dirname(__FILE__) + '/../../media/ball.png'
34
-
35
-
36
- player.time_to_kick_again = 60
37
- player.distance_control_ball = 30
38
- player.kick_strength = 20
39
-
40
-
41
- player.captain_home_image_file = File.dirname(__FILE__) + '/../../media/captain_home.png'
42
- player.captain_away_image_file = File.dirname(__FILE__) + '/../../media/captain_away.png'
43
- player.fast_home_image_file = File.dirname(__FILE__) + '/../../media/fast_home.png'
44
- player.fast_away_image_file = File.dirname(__FILE__) + '/../../media/fast_away.png'
45
- player.average_home_image_file = File.dirname(__FILE__) + '/../../media/average_home.png'
46
- player.average_away_image_file = File.dirname(__FILE__) + '/../../media/average_away.png'
47
-
48
-
49
- goal.image_file = File.dirname(__FILE__) + '/../../media/goal.png'
50
-
51
-
52
- game.time = 120
53
- game.goal_image_position = Position.new(596, 466)
54
- game.time_label_position = Position.new(870, 68)
55
- game.score_home_label_position = Position.new(1150, 68)
56
- game.score_away_label_position = Position.new(1220, 68)
57
- game.max_name_length = 20
58
- game.default_font_size = 48
59
- game.team_label_font_size = 64
60
- game.team_label_width = 669
61
- game.home_team_label_position = Position.new(105, 580)
62
- game.away_team_label_position = Position.new(1815, 580)
63
- end
64
- end
@@ -1,77 +0,0 @@
1
- module Rubygoal
2
- module Config
3
- class Field < Struct.new(:width,
4
- :height,
5
- :offset,
6
- :goal_height,
7
- :close_to_goal_distance,
8
- :background_image_file)
9
- end
10
-
11
- class Team < Struct.new(:initial_player_positions,
12
- :average_players_count,
13
- :fast_players_count,
14
- :captain_players_count)
15
- end
16
-
17
- class Ball < Struct.new(:width,
18
- :height,
19
- :image_file)
20
- end
21
-
22
- class Player < Struct.new(:time_to_kick_again,
23
- :distance_control_ball,
24
- :kick_strength,
25
- :average_home_image_file,
26
- :average_away_image_file,
27
- :fast_home_image_file,
28
- :fast_away_image_file,
29
- :captain_home_image_file,
30
- :captain_away_image_file)
31
- end
32
-
33
- class Goal < Struct.new(:image_file,
34
- :sound_file)
35
- end
36
-
37
- class Game < Struct.new(:time,
38
- :goal_image_position,
39
- :time_label_position,
40
- :score_home_label_position,
41
- :score_away_label_position,
42
- :max_name_length,
43
- :default_font_size,
44
- :team_label_font_size,
45
- :team_label_width,
46
- :home_team_label_position,
47
- :away_team_label_position,
48
- :background_sound_file)
49
- end
50
-
51
- class << self
52
- def field
53
- @field ||= Field.new
54
- end
55
-
56
- def team
57
- @team ||= Team.new
58
- end
59
-
60
- def ball
61
- @ball ||= Ball.new
62
- end
63
-
64
- def player
65
- @player ||= Player.new
66
- end
67
-
68
- def goal
69
- @goal ||= Goal.new
70
- end
71
-
72
- def game
73
- @game ||= Game.new
74
- end
75
- end
76
- end
77
- end
@@ -1,25 +0,0 @@
1
- require 'gosu'
2
-
3
- module Rubygoal
4
- class Coordinate < Struct.new(:x, :y)
5
- def distance(coordinate)
6
- Gosu.distance(x, y, coordinate.x, coordinate.y)
7
- end
8
-
9
- def add(coordinate)
10
- Coordinate.new(x + coordinate.x, y + coordinate.y)
11
- end
12
-
13
- def to_s
14
- "(#{x}, #{y})"
15
- end
16
- end
17
-
18
- class Position < Coordinate; end
19
-
20
- class Velocity < Coordinate
21
- def nonzero?
22
- x != 0 && y != 0
23
- end
24
- end
25
- end
@@ -1,84 +0,0 @@
1
- require 'forwardable'
2
- require 'gosu'
3
-
4
- require 'rubygoal/ball'
5
- require 'rubygoal/coach_loader'
6
- require 'rubygoal/team'
7
- require 'rubygoal/field_metrics'
8
- require 'rubygoal/match'
9
- require 'rubygoal/coaches/coach_home'
10
- require 'rubygoal/coaches/coach_away'
11
-
12
- module Rubygoal
13
- class Field
14
- attr_reader :ball, :team_home, :team_away
15
-
16
- extend Forwardable
17
- def_delegators :ball, :goal?
18
-
19
- def initialize(game_window)
20
- @game_window = game_window
21
- @background_image = Gosu::Image.new(game_window, Config.field.background_image_file, true)
22
-
23
- @ball = Ball.new(game_window, FieldMetrics.center_position)
24
-
25
- coach_home = CoachLoader.get(CoachHome)
26
- coach_away = CoachLoader.get(CoachAway)
27
-
28
- puts "Home coach: #{coach_home.class.name}"
29
- puts "Away coach: #{coach_away.class.name}"
30
-
31
- @team_home = Team.new(game_window, :home, coach_home)
32
- @team_away = Team.new(game_window, :away, coach_away)
33
- end
34
-
35
- def reinitialize
36
- team_home.players_to_initial_position
37
- team_away.players_to_initial_position
38
- ball.position = FieldMetrics.center_position
39
- end
40
-
41
- def team_names
42
- {
43
- home: team_home.name,
44
- away: team_away.name
45
- }
46
- end
47
-
48
- def update
49
- team_home.update(game_data(:home))
50
- team_away.update(game_data(:away))
51
- ball.update
52
- end
53
-
54
- def draw
55
- background_image.draw(0, 0, 0);
56
- ball.draw
57
- team_home.draw
58
- team_away.draw
59
- end
60
-
61
- private
62
-
63
- def game_data(side)
64
- case side
65
- when :home
66
- Match.new(
67
- game_window.score_home,
68
- game_window.score_away,
69
- game_window.time,
70
- team_away.formation
71
- )
72
- when :away
73
- Match.new(
74
- game_window.score_away,
75
- game_window.score_home,
76
- game_window.time,
77
- team_home.formation
78
- )
79
- end
80
- end
81
-
82
- attr_reader :background_image, :game_window
83
- end
84
- end
@@ -1,85 +0,0 @@
1
- require 'rubygoal/config'
2
- require 'rubygoal/coordinate'
3
- require 'rubygoal/field_metrics'
4
-
5
- module Rubygoal
6
- module FieldMetrics
7
- class << self
8
- def center_position
9
- center = Position.new(
10
- Config.field.width / 2,
11
- Config.field.height / 2
12
- )
13
- Config.field.offset.add(center)
14
- end
15
-
16
- def goal_position(side)
17
- position = center_position
18
- case side
19
- when :home
20
- position.x = Config.field.offset.x
21
- when :away
22
- position.x = Config.field.offset.x + Config.field.width
23
- end
24
- position
25
- end
26
-
27
- def initial_player_positions(side)
28
- Config.team.initial_player_positions.map do |pos|
29
- case side
30
- when :home
31
- Position.new(
32
- Config.field.offset.x + pos[0],
33
- Config.field.offset.y + pos[1]
34
- )
35
- when :away
36
- Position.new(
37
- Config.field.offset.x + Config.field.width - pos[0],
38
- Config.field.offset.y + Config.field.height - pos[1]
39
- )
40
- end
41
- end
42
- end
43
-
44
- def goalkeeper_position(side)
45
- initial_player_positions(side).first
46
- end
47
-
48
- def position_side(position)
49
- if position.x < FieldMetrics.center_position.x
50
- :home
51
- else
52
- :away
53
- end
54
- end
55
-
56
- def out_of_bounds_width?(position)
57
- lower_limit = Config.field.offset.x
58
- upper_limit = Config.field.offset.x + Config.field.width
59
- !(lower_limit..upper_limit).include?(position.x)
60
- end
61
-
62
- def out_of_bounds_height?(position)
63
- lower_limit = Config.field.offset.y
64
- upper_limit = Config.field.offset.y + Config.field.height
65
- !(lower_limit..upper_limit).include?(position.y)
66
- end
67
-
68
- def goal?(position)
69
- if out_of_bounds_width?(position)
70
- lower_limit = center_position.y - Config.field.goal_height / 2
71
- upper_limit = center_position.y + Config.field.goal_height / 2
72
-
73
- (lower_limit..upper_limit).include?(position.y)
74
- else
75
- false
76
- end
77
- end
78
-
79
- def close_to_goal?(position, side)
80
- goal_position = FieldMetrics.goal_position(side)
81
- goal_position.distance(position) < Config.field.close_to_goal_distance
82
- end
83
- end
84
- end
85
- end