rubygoal-core 1.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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +18 -0
  3. data/README.md +85 -0
  4. data/bin/rubygoal +15 -0
  5. data/lib/rubygoal.rb +1 -0
  6. data/lib/rubygoal/ball.rb +60 -0
  7. data/lib/rubygoal/coach.rb +81 -0
  8. data/lib/rubygoal/coach_definition.rb +54 -0
  9. data/lib/rubygoal/coach_loader.rb +55 -0
  10. data/lib/rubygoal/coaches/coach_definition_away.rb +72 -0
  11. data/lib/rubygoal/coaches/coach_definition_home.rb +76 -0
  12. data/lib/rubygoal/configuration.rb +49 -0
  13. data/lib/rubygoal/coordinate.rb +33 -0
  14. data/lib/rubygoal/field.rb +134 -0
  15. data/lib/rubygoal/formation.rb +73 -0
  16. data/lib/rubygoal/formation/formation_dsl.rb +67 -0
  17. data/lib/rubygoal/game.rb +162 -0
  18. data/lib/rubygoal/goal.rb +26 -0
  19. data/lib/rubygoal/match_data.rb +130 -0
  20. data/lib/rubygoal/moveable.rb +67 -0
  21. data/lib/rubygoal/player.rb +87 -0
  22. data/lib/rubygoal/players/average.rb +16 -0
  23. data/lib/rubygoal/players/captain.rb +15 -0
  24. data/lib/rubygoal/players/fast.rb +16 -0
  25. data/lib/rubygoal/players/goalkeeper.rb +26 -0
  26. data/lib/rubygoal/players/player_movement.rb +98 -0
  27. data/lib/rubygoal/recorder.rb +56 -0
  28. data/lib/rubygoal/simulator.rb +33 -0
  29. data/lib/rubygoal/team.rb +198 -0
  30. data/lib/rubygoal/teams/away.rb +15 -0
  31. data/lib/rubygoal/teams/home.rb +15 -0
  32. data/lib/rubygoal/util.rb +36 -0
  33. data/lib/rubygoal/version.rb +3 -0
  34. data/test/ball_test.rb +56 -0
  35. data/test/coach_test.rb +49 -0
  36. data/test/field_test.rb +103 -0
  37. data/test/fixtures/four_fast_players_coach_definition.rb +27 -0
  38. data/test/fixtures/less_players_coach_definition.rb +25 -0
  39. data/test/fixtures/mirror_strategy_coach_definition.rb +42 -0
  40. data/test/fixtures/more_players_coach_definition.rb +27 -0
  41. data/test/fixtures/test_away_coach_definition.rb +34 -0
  42. data/test/fixtures/test_home_coach_definition.rb +34 -0
  43. data/test/fixtures/two_captains_coach_definition.rb +27 -0
  44. data/test/fixtures/valid_coach_definition.rb +26 -0
  45. data/test/formation_test.rb +81 -0
  46. data/test/game_test.rb +84 -0
  47. data/test/match_data_test.rb +149 -0
  48. data/test/player_test.rb +125 -0
  49. data/test/players/goalkeeper_test.rb +49 -0
  50. data/test/players/player_movement_test.rb +76 -0
  51. data/test/recorder_test.rb +118 -0
  52. data/test/team_test.rb +97 -0
  53. data/test/test_helper.rb +21 -0
  54. metadata +158 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b9467e3e2d813c7e05c2b773fa9552c551c1b3d1
4
+ data.tar.gz: 547398aa354e4077b01b0348ce7f70cfca999880
5
+ SHA512:
6
+ metadata.gz: 878e490f660c88b9809959c5839833413b4d8dd5fbd7243615b82a2760d335467499c3cf8e03234442a385348665c452fe9bc1e46a132102b57a7cc5e25a11e7
7
+ data.tar.gz: 5497617e5e87057f6d235461a3a73f7e74cf53b88ce8eed99d4b583b74227aa78f321355dd27723527d6925ad2e715e0d179be84968f1f4dcd9d71fe63fe6fd2
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright 2014 Jorge Bejar
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
14
+
15
+ -----
16
+
17
+ This does not apply to files under the "media/" folder. For licensing of
18
+ those files refer to the Legal section in the README.md file.
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ [![Build Status](https://travis-ci.org/wyeworks/rubygoal.png)](https://travis-ci.org/wyeworks/rubygoal)
2
+ [![Code Climate](https://codeclimate.com/github/wyeworks/rubygoal.png)](https://codeclimate.com/github/wyeworks/rubygoal)
3
+ [![Inline docs](http://inch-ci.org/github/wyeworks/rubygoal.png?branch=master)](http://inch-ci.org/github/wyeworks/rubygoal)
4
+
5
+ #Welcome to RubyGoal!
6
+
7
+ ## What is RubyGoal?
8
+
9
+ RubyGoal is a game in which you will be coaching your football team.
10
+
11
+ You will be coding your strategy in RUBY :D .
12
+
13
+ ## Dependencies
14
+
15
+ GNU/Linux, Make sure you have all dependencies installed.
16
+
17
+ Ubuntu/Debian:
18
+
19
+ ```bash
20
+ # Gosu's dependencies for both C++ and Ruby
21
+ sudo apt-get install build-essential libsdl2-dev libsdl2-ttf-dev
22
+ libpango1.0-dev \
23
+ libgl1-mesa-dev libfreeimage-dev libopenal-dev
24
+ libsndfile-dev
25
+ ```
26
+
27
+ For other distros: https://github.com/jlnr/gosu/wiki/Getting-Started-on-Linux
28
+
29
+ ## How do i run it?
30
+
31
+ ```bash
32
+ gem install rubygoal
33
+ ```
34
+
35
+ Run the game with example `CoachDefinition`
36
+ ```bash
37
+ rubygoal
38
+ ```
39
+
40
+ Run the game with your custom `CoachDefinition` implementation
41
+ ```bash
42
+ rubygoal coach_1.rb
43
+ ```
44
+
45
+ Run the game with your home and away `CoachDefinition` implementations
46
+ ```bash
47
+ rubygoal coach_1.rb coach_2.rb
48
+ ```
49
+
50
+ If you want to run the game from the source code, clone the project and
51
+ run the following commands:
52
+
53
+ ```bash
54
+ BUNDLE_GEMFILE=Gemfile.dev bundle install
55
+ BUNDLE_GEMFILE=Gemfile.dev bundle exec ruby gui/bin/rubygoal [coach_file] [coach_file]
56
+ ```
57
+
58
+ Also, you can simulate a game without the GUI by running
59
+
60
+ ```bash
61
+ bundle install
62
+ bundle exec ruby bin/rubygoal [coach_file] [coach_file]
63
+ ```
64
+
65
+ When you simuate a game, a JSON file is created in the same folder. You
66
+ could run this using our experiment webcomponent to play Rubygoal in the
67
+ web: https://github.com/jmbejar/rubygoal-webplayer
68
+
69
+ ## How do i write my own coach class?
70
+
71
+ You can find a complete guide explaining how to program a coach in
72
+ www.rubygoal.com
73
+
74
+ Aditionally, you can take a look to the already defined `CoachDefinition` at
75
+ `lib/rubygoal/coach_definition`.
76
+ Specially pay attention to the example coaches in `lib/rubygoal/coaches/`
77
+
78
+
79
+ ## Legal
80
+ All source code, except the files under the `media/` folder, is
81
+ licensed under the Apache License 2.0. Please see the `LICENSE` file under
82
+ the gem root folder.
83
+
84
+ All media files under the `media/` folder are licensed under the Creative
85
+ Commons 4.0 Attribution license. Please see https://creativecommons.org/licenses/by/4.0/
data/bin/rubygoal ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby -*-
3
+
4
+ require 'rubygoal/simulator'
5
+
6
+ simulator = Rubygoal::Simulator.new
7
+ simulator.simulate
8
+
9
+ timestamp = Time.now.strftime("%Y%m%d%H%M%S")
10
+ file = File.new("recorded_game_#{timestamp}.json", 'w')
11
+ JSON.dump(simulator.recorded_game, file)
12
+
13
+ p "Match recorded in #{file.path}"
14
+
15
+
data/lib/rubygoal.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rubygoal/game'
@@ -0,0 +1,60 @@
1
+ require 'rubygoal/util'
2
+ require 'rubygoal/field'
3
+ require 'rubygoal/moveable'
4
+
5
+ module Rubygoal
6
+ class Ball
7
+ include Moveable
8
+
9
+ def initialize
10
+ super
11
+ reinitialize_position
12
+ end
13
+
14
+ def goal?
15
+ Field.goal?(position)
16
+ end
17
+
18
+ def move(direction, speed)
19
+ self.velocity = Velocity.new(
20
+ Util.offset_x(direction, speed),
21
+ Util.offset_y(direction, speed)
22
+ )
23
+ end
24
+
25
+ def reinitialize_position
26
+ self.position = Field.center_position
27
+ end
28
+
29
+ def update(elapsed_time)
30
+ super
31
+
32
+ prevent_out_of_bounds
33
+ decelerate(elapsed_time)
34
+ end
35
+
36
+ private
37
+
38
+ def prevent_out_of_bounds
39
+ if Field.out_of_bounds_width?(position)
40
+ velocity.x *= -1
41
+ end
42
+ if Field.out_of_bounds_height?(position)
43
+ velocity.y *= -1
44
+ end
45
+ end
46
+
47
+ def decelerate(elapsed_time)
48
+ coef = deceleration_coef(elapsed_time)
49
+
50
+ self.velocity = velocity.mult(coef)
51
+ end
52
+
53
+ def deceleration_coef(elapsed_time)
54
+ custom_frame_rate = 1 / 60.0
55
+ time_coef = elapsed_time / custom_frame_rate
56
+
57
+ Rubygoal.configuration.deceleration_coef ** time_coef
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,81 @@
1
+ require 'forwardable'
2
+
3
+ module Rubygoal
4
+ class Coach
5
+ extend Forwardable
6
+
7
+ def_delegators :coach_definition, :players, :name, :formation
8
+
9
+ def initialize(coach_definition)
10
+ @coach_definition = coach_definition
11
+ end
12
+
13
+ def errors
14
+ [].tap do |errors|
15
+ check_unique_captain(errors)
16
+ check_players_count(:average, errors)
17
+ check_players_count(:fast, errors)
18
+ end
19
+ end
20
+
21
+ def valid?
22
+ errors.empty?
23
+ end
24
+
25
+ def players_by_type(type)
26
+ players.select { |p| p.type == type }
27
+ end
28
+
29
+ def captain_player
30
+ players_by_type(:captain).first
31
+ end
32
+
33
+ def fast_players
34
+ players_by_type(:fast)
35
+ end
36
+
37
+ def average_players
38
+ players_by_type(:average)
39
+ end
40
+
41
+ def initial_formation
42
+ average_names = average_players.map(&:name)
43
+ fast_names = fast_players.map(&:name)
44
+ captain_name = captain_player.name
45
+
46
+ formation = Formation.new
47
+
48
+ formation.lineup do
49
+ defenders average_names[0], average_names[2], :none, average_names[3], average_names[4]
50
+ midfielders average_names[1], fast_names[0], :none, fast_names[1], average_names[5]
51
+ attackers :none, captain_name, :none, fast_names[2], :none
52
+ end
53
+
54
+ formation
55
+ end
56
+
57
+ private
58
+
59
+ attr_reader :coach_definition
60
+
61
+ def game_config
62
+ Rubygoal.configuration
63
+ end
64
+
65
+ def check_unique_captain(errors)
66
+ captain_count = players_by_type(:captain).size
67
+
68
+ if captain_count != 1
69
+ errors << "The number of captains is #{captain_count}"
70
+ end
71
+ end
72
+
73
+ def check_players_count(type, errors)
74
+ players_count = players_by_type(type).size
75
+
76
+ if players_count != game_config.send("#{type}_players_count")
77
+ errors << "The number of #{type} players is #{players_count}"
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,54 @@
1
+ module Rubygoal
2
+ class CoachDefinition
3
+ PlayerDefinition = Struct.new(:name, :type)
4
+
5
+ class << self
6
+ attr_reader :team_name
7
+
8
+ def team(&block)
9
+ instance_eval(&block)
10
+ end
11
+
12
+ def name(team_name)
13
+ @team_name = team_name
14
+ end
15
+
16
+ def players(&block)
17
+ @team_players = []
18
+ instance_eval(&block)
19
+ end
20
+
21
+ def method_missing(method, *args)
22
+ name = args.first.to_sym
23
+ @team_players << PlayerDefinition.new(name, method.to_sym)
24
+ end
25
+
26
+ def team_players
27
+ @team_players || [
28
+ PlayerDefinition.new(:captain, :captain),
29
+ PlayerDefinition.new(:fast1, :fast),
30
+ PlayerDefinition.new(:fast2, :fast),
31
+ PlayerDefinition.new(:fast3, :fast),
32
+ PlayerDefinition.new(:average1, :average),
33
+ PlayerDefinition.new(:average2, :average),
34
+ PlayerDefinition.new(:average3, :average),
35
+ PlayerDefinition.new(:average4, :average),
36
+ PlayerDefinition.new(:average5, :average),
37
+ PlayerDefinition.new(:average6, :average),
38
+ ]
39
+ end
40
+ end
41
+
42
+ def players
43
+ self.class.team_players
44
+ end
45
+
46
+ def name
47
+ self.class.team_name
48
+ end
49
+
50
+ def formation(match)
51
+ raise NotImplementedError
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,55 @@
1
+ require 'rubygoal/coach'
2
+ require 'rubygoal/coaches/coach_definition_home'
3
+ require 'rubygoal/coaches/coach_definition_away'
4
+
5
+ module Rubygoal
6
+ class CoachLoader
7
+ DEFAULT_COACH_DEFINITIONS = {
8
+ home: CoachDefinitionHome,
9
+ away: CoachDefinitionAway
10
+ }
11
+
12
+ def initialize(side)
13
+ @side = side
14
+ end
15
+
16
+ def coach
17
+ Coach.new(load_definition_coach)
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :side
23
+
24
+ def default_definition_class
25
+ DEFAULT_COACH_DEFINITIONS[side]
26
+ end
27
+
28
+ def load_definition_coach
29
+ if filename && File.exists?(filename)
30
+ load filename
31
+
32
+ class_name = camelize(File.basename(filename, ".rb"))
33
+ Rubygoal.const_get(class_name).new
34
+ else
35
+ if filename && Rubygoal.configuration.debug_output
36
+ puts "File `#{filename}` doesn't exist. Using #{default_definition_class.name}."
37
+ end
38
+
39
+ default_definition_class.new
40
+ end
41
+ end
42
+
43
+ def filename
44
+ side == :home ? ARGV[0] : ARGV[1]
45
+ end
46
+
47
+ def camelize(term)
48
+ string = term.to_s
49
+ string = string.sub(/^[a-z\d]*/) { $&.capitalize }
50
+ string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{$2.capitalize}" }
51
+ string.gsub!('/', '::')
52
+ string
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,72 @@
1
+ require 'rubygoal/coach_definition'
2
+ require 'rubygoal/formation'
3
+
4
+ module Rubygoal
5
+ class CoachDefinitionAway < CoachDefinition
6
+
7
+ team do
8
+ name "Argentina"
9
+ end
10
+
11
+ def formation(match)
12
+ formation = Formation.new
13
+
14
+ if match.me.winning?
15
+ formation.lineup do
16
+ defenders :average1, :fast1, :none, :fast3, :average5
17
+ midfielders :average2, :none, :captain, :none, :average6
18
+ att_midfielders :average3
19
+ attackers :none, :none, :fast2, :average4, :none
20
+ end
21
+ elsif match.me.draw?
22
+ formation.lineup do
23
+ lines do
24
+ defenders 13
25
+ midfielders 40
26
+ attackers 65
27
+ end
28
+
29
+ defenders :average1, :fast1, :none, :average3, :average5
30
+ midfielders :average2, :none, :none, :none, :average6
31
+ attackers :none, :fast2, :none, :average4, :none
32
+
33
+ custom_position do
34
+ player :fast3
35
+ position 30, 10
36
+ end
37
+ custom_position do
38
+ player :captain
39
+ position match.ball.x, match.ball.y
40
+ end
41
+ end
42
+ elsif match.me.losing?
43
+ if match.time < 30
44
+ formation.lineup do
45
+ defenders :none, :average2, :average4, :average5, :none
46
+ midfielders :average1, :none, :none, :fast2, :average6
47
+ attackers :none, :average3, :none, :fast3, :none
48
+
49
+ custom_position do
50
+ player :fast1
51
+ position 33, 50
52
+ end
53
+ custom_position do
54
+ player :captain
55
+ position 67, 50
56
+ end
57
+ end
58
+ else
59
+ formation.lineup do
60
+ defenders :none, :average2, :fast1, :average5, :none
61
+ def_midfielders :average4
62
+ midfielders :average1, :none, :none, :captain, :average6
63
+ att_midfielders :fast2
64
+ attackers :none, :average3, :none, :fast3, :none
65
+ end
66
+ end
67
+ end
68
+
69
+ formation
70
+ end
71
+ end
72
+ end