rubygoal 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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