rubygoal-core 1.0.0

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