rubygoal-core 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +18 -0
- data/README.md +85 -0
- data/bin/rubygoal +15 -0
- data/lib/rubygoal.rb +1 -0
- data/lib/rubygoal/ball.rb +60 -0
- data/lib/rubygoal/coach.rb +81 -0
- data/lib/rubygoal/coach_definition.rb +54 -0
- data/lib/rubygoal/coach_loader.rb +55 -0
- data/lib/rubygoal/coaches/coach_definition_away.rb +72 -0
- data/lib/rubygoal/coaches/coach_definition_home.rb +76 -0
- data/lib/rubygoal/configuration.rb +49 -0
- data/lib/rubygoal/coordinate.rb +33 -0
- data/lib/rubygoal/field.rb +134 -0
- data/lib/rubygoal/formation.rb +73 -0
- data/lib/rubygoal/formation/formation_dsl.rb +67 -0
- data/lib/rubygoal/game.rb +162 -0
- data/lib/rubygoal/goal.rb +26 -0
- data/lib/rubygoal/match_data.rb +130 -0
- data/lib/rubygoal/moveable.rb +67 -0
- data/lib/rubygoal/player.rb +87 -0
- data/lib/rubygoal/players/average.rb +16 -0
- data/lib/rubygoal/players/captain.rb +15 -0
- data/lib/rubygoal/players/fast.rb +16 -0
- data/lib/rubygoal/players/goalkeeper.rb +26 -0
- data/lib/rubygoal/players/player_movement.rb +98 -0
- data/lib/rubygoal/recorder.rb +56 -0
- data/lib/rubygoal/simulator.rb +33 -0
- data/lib/rubygoal/team.rb +198 -0
- data/lib/rubygoal/teams/away.rb +15 -0
- data/lib/rubygoal/teams/home.rb +15 -0
- data/lib/rubygoal/util.rb +36 -0
- data/lib/rubygoal/version.rb +3 -0
- data/test/ball_test.rb +56 -0
- data/test/coach_test.rb +49 -0
- data/test/field_test.rb +103 -0
- data/test/fixtures/four_fast_players_coach_definition.rb +27 -0
- data/test/fixtures/less_players_coach_definition.rb +25 -0
- data/test/fixtures/mirror_strategy_coach_definition.rb +42 -0
- data/test/fixtures/more_players_coach_definition.rb +27 -0
- data/test/fixtures/test_away_coach_definition.rb +34 -0
- data/test/fixtures/test_home_coach_definition.rb +34 -0
- data/test/fixtures/two_captains_coach_definition.rb +27 -0
- data/test/fixtures/valid_coach_definition.rb +26 -0
- data/test/formation_test.rb +81 -0
- data/test/game_test.rb +84 -0
- data/test/match_data_test.rb +149 -0
- data/test/player_test.rb +125 -0
- data/test/players/goalkeeper_test.rb +49 -0
- data/test/players/player_movement_test.rb +76 -0
- data/test/recorder_test.rb +118 -0
- data/test/team_test.rb +97 -0
- data/test/test_helper.rb +21 -0
- metadata +158 -0
data/test/field_test.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'rubygoal/field'
|
4
|
+
|
5
|
+
module Rubygoal
|
6
|
+
class FieldTest < Minitest::Test
|
7
|
+
def test_center_position
|
8
|
+
assert_equal Position.new(959, 581), Field.center_position
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_home_goal_position
|
12
|
+
assert_equal Position.new(262, 581), Field.goal_position(:home)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_away_goal_position
|
16
|
+
assert_equal Position.new(1656, 581), Field.goal_position(:away)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_home_position_side
|
20
|
+
assert_equal :home, Field.position_side(Position.new(958, 0))
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_away_position_side
|
24
|
+
assert_equal :away, Field.position_side(Position.new(960, 0))
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_left_out_of_bounds_width
|
28
|
+
assert Field.out_of_bounds_width?(Position.new(261, 0))
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_inside_left_bounds_width
|
32
|
+
refute Field.out_of_bounds_width?(Position.new(262, 0))
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_inside_right_bounds_width
|
36
|
+
refute Field.out_of_bounds_width?(Position.new(1656, 0))
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_right_out_of_bounds_width
|
40
|
+
assert Field.out_of_bounds_width?(Position.new(1657, 0))
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_up_out_of_bounds_height
|
44
|
+
assert Field.out_of_bounds_height?(Position.new(0, 111))
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_inside_upper_bounds_height
|
48
|
+
refute Field.out_of_bounds_height?(Position.new(0, 112))
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_inside_bottom_bounds_height
|
52
|
+
refute Field.out_of_bounds_height?(Position.new(0, 1050))
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_down_out_of_bounds_width
|
56
|
+
assert Field.out_of_bounds_height?(Position.new(0, 1051))
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_middle_goal
|
60
|
+
assert Field.goal?(Position.new(261, 581))
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_upper_goal
|
64
|
+
assert Field.goal?(Position.new(261, 718))
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_bottom_goal
|
68
|
+
assert Field.goal?(Position.new(261, 444))
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_upper_missed_goal
|
72
|
+
refute Field.goal?(Position.new(261, 719))
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_bottom_missed_goal
|
76
|
+
refute Field.goal?(Position.new(261, 443))
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_close_to_goal_straight
|
80
|
+
assert Field.close_to_goal?(Position.new(536, 581), :home)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_not_close_to_goal_straight
|
84
|
+
refute Field.close_to_goal?(Position.new(537, 581), :home)
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_close_to_goal_upper_diagonal
|
88
|
+
assert Field.close_to_goal?(Position.new(456, 775), :home)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_not_close_to_goal_upper_diagonal
|
92
|
+
refute Field.close_to_goal?(Position.new(457, 776), :home)
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_close_to_goal_lower_diagonal
|
96
|
+
assert Field.close_to_goal?(Position.new(456, 387), :home)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_not_close_to_goal_lower_diagonal
|
100
|
+
refute Field.close_to_goal?(Position.new(457, 386), :home)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Rubygoal
|
2
|
+
class FourFastPlayersCoachDefinition < CoachDefinition
|
3
|
+
team do
|
4
|
+
name "FourFastPlayers"
|
5
|
+
|
6
|
+
players do
|
7
|
+
captain :captain
|
8
|
+
|
9
|
+
fast :fast1
|
10
|
+
fast :fast2
|
11
|
+
fast :fast3
|
12
|
+
fast :fast4
|
13
|
+
|
14
|
+
average :average1
|
15
|
+
average :average2
|
16
|
+
average :average3
|
17
|
+
average :average4
|
18
|
+
average :average5
|
19
|
+
average :average6
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def formation(match)
|
24
|
+
Formation.new
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rubygoal
|
2
|
+
class LessPlayersCoachDefnition < CoachDefinition
|
3
|
+
team do
|
4
|
+
name "LessPlayers"
|
5
|
+
|
6
|
+
players do
|
7
|
+
captain :captain
|
8
|
+
|
9
|
+
fast :fast1
|
10
|
+
fast :fast2
|
11
|
+
fast :fast3
|
12
|
+
|
13
|
+
average :average2
|
14
|
+
average :average3
|
15
|
+
average :average4
|
16
|
+
average :average5
|
17
|
+
average :average6
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def formation(match)
|
22
|
+
Formation.new
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Rubygoal
|
2
|
+
class MirrorStrategyCoachDefinition < CoachDefinition
|
3
|
+
team do
|
4
|
+
name "Mimic Team"
|
5
|
+
|
6
|
+
players do
|
7
|
+
average :average1
|
8
|
+
average :average2
|
9
|
+
average :average3
|
10
|
+
average :average4
|
11
|
+
average :average5
|
12
|
+
average :average6
|
13
|
+
|
14
|
+
fast :fast1
|
15
|
+
fast :fast2
|
16
|
+
fast :fast3
|
17
|
+
|
18
|
+
captain :captain
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def formation(match)
|
23
|
+
# Mirror opponent players
|
24
|
+
|
25
|
+
formation = Formation.new
|
26
|
+
|
27
|
+
opponent = match.other.positions
|
28
|
+
my_players = players
|
29
|
+
|
30
|
+
opponent.each_with_index do |(_, opponent_pos), index|
|
31
|
+
formation.lineup do
|
32
|
+
custom_position do
|
33
|
+
player my_players[index].name
|
34
|
+
position opponent_pos.x, 100.0 - opponent_pos.y
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
formation
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Rubygoal
|
2
|
+
class MorePlayersCoachDefinition < CoachDefinition
|
3
|
+
team do
|
4
|
+
name "MorePlayers"
|
5
|
+
|
6
|
+
players do
|
7
|
+
captain :captain
|
8
|
+
|
9
|
+
fast :fast1
|
10
|
+
fast :fast2
|
11
|
+
fast :fast3
|
12
|
+
|
13
|
+
average :average1
|
14
|
+
average :average2
|
15
|
+
average :average3
|
16
|
+
average :average4
|
17
|
+
average :average5
|
18
|
+
average :average6
|
19
|
+
average :average7
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def formation(match)
|
24
|
+
Formation.new
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rubygoal
|
2
|
+
class TestAwayCoachDefinition < CoachDefinition
|
3
|
+
team do
|
4
|
+
name "Test Away Team"
|
5
|
+
|
6
|
+
players do
|
7
|
+
captain :away_captain
|
8
|
+
|
9
|
+
fast :away_fast1
|
10
|
+
fast :away_fast2
|
11
|
+
fast :away_fast3
|
12
|
+
|
13
|
+
average :away_average1
|
14
|
+
average :away_average2
|
15
|
+
average :away_average3
|
16
|
+
average :away_average4
|
17
|
+
average :away_average5
|
18
|
+
average :away_average6
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def formation(match)
|
23
|
+
formation = Formation.new
|
24
|
+
|
25
|
+
formation.lineup do
|
26
|
+
defenders :away_average1, :away_fast1, :none, :away_fast3, :away_average5
|
27
|
+
midfielders :away_average2, :away_average3, :away_captain, :away_average4, :away_average6
|
28
|
+
attackers :away_fast2
|
29
|
+
end
|
30
|
+
|
31
|
+
formation
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rubygoal
|
2
|
+
class TestHomeCoachDefinition < CoachDefinition
|
3
|
+
team do
|
4
|
+
name "Test Home Team"
|
5
|
+
|
6
|
+
players do
|
7
|
+
captain :home_captain
|
8
|
+
|
9
|
+
fast :home_fast1
|
10
|
+
fast :home_fast2
|
11
|
+
fast :home_fast3
|
12
|
+
|
13
|
+
average :home_average1
|
14
|
+
average :home_average2
|
15
|
+
average :home_average3
|
16
|
+
average :home_average4
|
17
|
+
average :home_average5
|
18
|
+
average :home_average6
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def formation(match)
|
23
|
+
formation = Formation.new
|
24
|
+
|
25
|
+
formation.lineup do
|
26
|
+
defenders :home_average1, :home_fast1, :none, :home_fast3, :home_average5
|
27
|
+
midfielders :home_average2, :none, :home_captain, :none, :home_average6
|
28
|
+
attackers :none, :home_average3, :home_fast2, :home_average4, :none
|
29
|
+
end
|
30
|
+
|
31
|
+
formation
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Rubygoal
|
2
|
+
class TwoCaptainsCoachDefinition < CoachDefinition
|
3
|
+
team do
|
4
|
+
name "TwoCaptains"
|
5
|
+
|
6
|
+
players do
|
7
|
+
captain :captain
|
8
|
+
captain :captain2
|
9
|
+
|
10
|
+
fast :fast1
|
11
|
+
fast :fast2
|
12
|
+
fast :fast3
|
13
|
+
|
14
|
+
average :average1
|
15
|
+
average :average2
|
16
|
+
average :average3
|
17
|
+
average :average4
|
18
|
+
average :average5
|
19
|
+
average :average6
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def formation(match)
|
24
|
+
Formation.new
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Rubygoal
|
2
|
+
class ValidCoachDefinition < CoachDefinition
|
3
|
+
team do
|
4
|
+
name "ValidTeam"
|
5
|
+
|
6
|
+
players do
|
7
|
+
captain :captain
|
8
|
+
|
9
|
+
fast :fast1
|
10
|
+
fast :fast2
|
11
|
+
fast :fast3
|
12
|
+
|
13
|
+
average :average1
|
14
|
+
average :average2
|
15
|
+
average :average3
|
16
|
+
average :average4
|
17
|
+
average :average5
|
18
|
+
average :average6
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def formation(match)
|
23
|
+
Formation.new
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
require 'rubygoal/formation'
|
4
|
+
|
5
|
+
module Rubygoal
|
6
|
+
class TestFormation < Minitest::Test
|
7
|
+
def setup
|
8
|
+
@formation = Formation.new
|
9
|
+
@formation.lineup do
|
10
|
+
defenders :average1, :average2, :none, :average3, :average4
|
11
|
+
midfielders :average5, :fast1, :none, :fast2, :average6
|
12
|
+
attackers :none, :captain, :none, :fast3, :none
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_default_formation_is_valid
|
17
|
+
assert @formation.valid?
|
18
|
+
assert_empty @formation.errors
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_player_default_positions
|
22
|
+
expected_positions = {
|
23
|
+
average1: Position.new(232, 156),
|
24
|
+
average2: Position.new(232, 312),
|
25
|
+
average3: Position.new(232, 625),
|
26
|
+
average4: Position.new(232, 782),
|
27
|
+
average5: Position.new(697, 156),
|
28
|
+
average6: Position.new(697, 782),
|
29
|
+
captain: Position.new(1162, 312),
|
30
|
+
fast1: Position.new(697, 312),
|
31
|
+
fast2: Position.new(697, 625),
|
32
|
+
fast3: Position.new(1162, 625)
|
33
|
+
}
|
34
|
+
|
35
|
+
expected_positions.each do |name, pos|
|
36
|
+
assert_in_delta pos, @formation.players_position[name], 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_custom_default_positions
|
41
|
+
@formation.lineup do
|
42
|
+
lines do
|
43
|
+
defenders 13
|
44
|
+
midfielders 43
|
45
|
+
attackers 65
|
46
|
+
end
|
47
|
+
|
48
|
+
defenders :average1, :average2, :none, :average3, :average4
|
49
|
+
midfielders :none, :fast1, :none, :fast2, :average6
|
50
|
+
attackers :none, :captain, :none, :none, :none
|
51
|
+
|
52
|
+
custom_position do
|
53
|
+
player :fast3
|
54
|
+
position 30, 10
|
55
|
+
end
|
56
|
+
custom_position do
|
57
|
+
player :average5
|
58
|
+
position 60, 50
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
expected_positions = {
|
63
|
+
average1: Position.new(181, 156),
|
64
|
+
average2: Position.new(181, 312),
|
65
|
+
average3: Position.new(181, 625),
|
66
|
+
average4: Position.new(181, 781),
|
67
|
+
average6: Position.new(600, 781),
|
68
|
+
captain: Position.new(906, 312),
|
69
|
+
fast1: Position.new(600, 312),
|
70
|
+
fast2: Position.new(600, 625),
|
71
|
+
|
72
|
+
fast3: Position.new(418, 94),
|
73
|
+
average5: Position.new(836, 469)
|
74
|
+
}
|
75
|
+
|
76
|
+
expected_positions.each do |name, pos|
|
77
|
+
assert_in_delta pos, @formation.players_position[name], 1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/test/game_test.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'timecop'
|
3
|
+
|
4
|
+
module Rubygoal
|
5
|
+
class GameTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
home_coach = Coach.new(TestHomeCoachDefinition.new)
|
8
|
+
away_coach = Coach.new(TestAwayCoachDefinition.new)
|
9
|
+
@game = Game.new(home_coach, away_coach)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_initial_score
|
13
|
+
assert_equal 0, @game.score_home
|
14
|
+
assert_equal 0, @game.score_away
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_score_after_home_team_goal
|
18
|
+
goal_position = Field::goal_position(:away).add(Position.new(1, 0))
|
19
|
+
@game.ball.position = goal_position
|
20
|
+
|
21
|
+
@game.update
|
22
|
+
|
23
|
+
assert_equal 1, @game.score_home
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_score_after_away_team_goal
|
27
|
+
goal_position = Field::goal_position(:home).add(Position.new(-1, 0))
|
28
|
+
@game.ball.position = goal_position
|
29
|
+
|
30
|
+
@game.update
|
31
|
+
|
32
|
+
assert_equal 1, @game.score_away
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_celebrating_goal_after_init
|
36
|
+
refute @game.celebrating_goal?
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_celebrating_goal_after_away_team_goal
|
40
|
+
goal_position = Field::goal_position(:home).add(Position.new(-1, 0))
|
41
|
+
@game.ball.position = goal_position
|
42
|
+
|
43
|
+
@game.update
|
44
|
+
|
45
|
+
assert @game.celebrating_goal?
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_initial_time
|
49
|
+
assert_equal Rubygoal.configuration.game_time, @game.time
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_time_pass
|
53
|
+
# Begin game with an initial update call
|
54
|
+
@game.update
|
55
|
+
|
56
|
+
# Simulate time passing
|
57
|
+
elapsed_time = 70
|
58
|
+
Timecop.travel(Time.now + elapsed_time)
|
59
|
+
|
60
|
+
@game.update
|
61
|
+
|
62
|
+
remaining_time = Rubygoal.configuration.game_time - elapsed_time
|
63
|
+
assert_in_delta remaining_time, @game.time, 0.05
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_players
|
67
|
+
assert_equal 22, @game.players.size
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_recorded_game
|
71
|
+
Rubygoal.configuration.record_game = true
|
72
|
+
home_coach = Coach.new(TestHomeCoachDefinition.new)
|
73
|
+
away_coach = Coach.new(TestAwayCoachDefinition.new)
|
74
|
+
game = Game.new(home_coach, away_coach)
|
75
|
+
|
76
|
+
expected_teams = {
|
77
|
+
home: 'Test Home Team',
|
78
|
+
away: 'Test Away Team'
|
79
|
+
}
|
80
|
+
|
81
|
+
assert_equal expected_teams, game.recorded_game[:teams]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|