rubygoal 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a4171d4bce9224cff1d3b5b459453ad54a506b49
4
+ data.tar.gz: 54ae3a19f22af90981e5cf3e7110562494e155f4
5
+ SHA512:
6
+ metadata.gz: bac15b2f25e388b1232b600bf3848ce770e11a662a37b8af093e42426a13bb196fc6d7f6e982dae7c015cf895b26b7388886d05b81069bb3528f9f156f2662a8
7
+ data.tar.gz: a7887550de41ee2b0f1be75ff2a761128bb0a04e4bca26b565338dfb6576d2cf419ad2369fcf1cd0a2a12da8fc1cd4db8c2ed34e2d8f19f9bf32a590dbf38403
data/MIT-LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2014 Jorge Bejar
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ ---
23
+
24
+ This does not apply to files under the "media/" folder.
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+ #Bienvenidos a RubyGoal!
2
+
3
+ ## ¿Qué es RubyGoal?
4
+
5
+ RubyGoal es un juego en el cual tú serás el coach de un equipo de
6
+ fútbol.
7
+
8
+ La estrategia del coach la vas a tener que implementar tú en ruby.
9
+
10
+ ## Dependencias
11
+
12
+ GNU/Linux, Asegúrate tener todas las dependencias instaladas.
13
+
14
+ Ubuntu/Debian:
15
+
16
+ ```bash
17
+ # Gosu's dependencies for both C++ and Ruby
18
+ sudo apt-get install build-essential freeglut3-dev libfreeimage-dev libgl1-mesa-dev \
19
+ libopenal-dev libpango1.0-dev libsdl-ttf2.0-dev libsndfile-dev \
20
+ libxinerama-dev
21
+ ```
22
+
23
+ Para otras distros: https://github.com/jlnr/gosu/wiki/Getting-Started-on-Linux
24
+
25
+ ## ¿Cómo hago para correrlo?
26
+
27
+ ```bash
28
+ gem install rubygoal
29
+ ```
30
+
31
+ Correr el juego con los `Coach` de ejemplo
32
+ ```bash
33
+ rubygoal
34
+ ```
35
+
36
+ Correr el juego con tu implementación de `Coach`
37
+ ```bash
38
+ rubygoal coach_1.rb
39
+ ```
40
+
41
+ Correr el juego con tu implementación de ambos `Coach`
42
+ ```bash
43
+ rubygoal coach_1.rb coach_2.rb
44
+ ```
45
+
46
+ ## ¿Cómo hago para implementar mi Coach?
47
+
48
+ Mirate los `Coach` ya definidos en `lib/rubygoal/coaches`, sobre todo lee con
49
+ atención y en su totalidad `lib/rubygoal/coaches/template.rb`
50
+
51
+ ## Legal
52
+
53
+ Todo el código fuente, salvo los archivos bajo la carpeta `media/`, está
54
+ licenciado bajo los términos de la licencia del MIT. Ver el archivo `MIT-LICENSE`
55
+ bajo la ruta de la gema.
56
+
57
+ La imagen de Alberto Kesman utilizada en el archivo `media/goal.png` fue
58
+ tomada de https://commons.wikimedia.org/wiki/File:Albertok.jpg que se
59
+ encuentra licenciada bajo los términos de la licencia CC-BY-SA 3.0
60
+ (https://creativecommons.org/licenses/by-sa/3.0/deed.es). Como
61
+ consecuencia, el archivo `media/goal.png` queda licenciado también bajo
62
+ esta licencia como trabajo derivado.
data/bin/rubygoal ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby -*-
3
+
4
+ require 'rubygoal'
5
+ Rubygoal.start
@@ -0,0 +1,41 @@
1
+ require 'gosu'
2
+
3
+ require 'rubygoal/field_metrics'
4
+ require 'rubygoal/moveable'
5
+
6
+ module Rubygoal
7
+ class Ball
8
+ include Moveable
9
+
10
+ def initialize(window, position)
11
+ super()
12
+ @position = position
13
+ @image = Gosu::Image.new(window, Config.ball.image_file, false)
14
+ end
15
+
16
+ def goal?
17
+ FieldMetrics.goal?(position)
18
+ end
19
+
20
+ def draw
21
+ image.draw(position.x - Config.ball.width / 2, position.y - Config.ball.height / 2, 1)
22
+ end
23
+
24
+ def update
25
+ super
26
+ if FieldMetrics.out_of_bounds_width?(position)
27
+ velocity.x *= -1
28
+ end
29
+ if FieldMetrics.out_of_bounds_height?(position)
30
+ velocity.y *= -1
31
+ end
32
+
33
+ velocity.x *= 0.95
34
+ velocity.y *= 0.95
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :image
40
+ end
41
+ end
@@ -0,0 +1,11 @@
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
@@ -0,0 +1,32 @@
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
@@ -0,0 +1,52 @@
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
@@ -0,0 +1,28 @@
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
@@ -0,0 +1,198 @@
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
@@ -0,0 +1,64 @@
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
@@ -0,0 +1,77 @@
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
@@ -0,0 +1,25 @@
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