1
1
package engine
2
2
3
3
import (
4
+ "fmt"
4
5
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/geom"
5
6
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/state"
6
7
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/statemachine"
@@ -15,98 +16,133 @@ func (e *Engine) processContinue() {
15
16
* e .currentState .Command .Type == state .Command_STOP ||
16
17
(e .gameConfig .ContinueFromHalt && * e .currentState .Command .Type == state .Command_HALT )) ||
17
18
e .gcState .TrackerStateGc .Ball == nil {
19
+ // Reset ready to continue
18
20
e .gcState .ReadyToContinue = nil
21
+ e .gcState .ContinuationIssues = []string {}
19
22
return
20
23
}
21
24
22
- readyToContinue := false
25
+ e .gcState .ContinuationIssues = e .findIssueForContinuation ()
26
+ readyToContinue := len (e .gcState .ContinuationIssues ) == 0
27
+ e .gcState .ReadyToContinue = & readyToContinue
23
28
24
- defer func () {
25
- // set at the end of this function when the flag has its final value
26
- e .gcState .ReadyToContinue = & readyToContinue
27
- }()
29
+ if readyToContinue && e .currentState .GetAutoContinue () {
30
+ e .Enqueue (& statemachine.Change {
31
+ Origin : & changeOriginEngine ,
32
+ Change : & statemachine.Change_Continue {
33
+ Continue : & statemachine.Continue {},
34
+ },
35
+ })
36
+ }
37
+ }
28
38
29
- if e .timeSinceLastChange () < minPreparationTime {
30
- // Too early
31
- return
39
+ func (e * Engine ) findIssueForContinuation () (issues []string ) {
40
+ preparationTimeLeft := e .timeSinceLastChange () - minPreparationTime
41
+ if preparationTimeLeft < 0 {
42
+ issues = append (issues , fmt .Sprintf ("%.1fs left for preparation" , - preparationTimeLeft .Seconds ()))
32
43
}
33
44
34
45
if * e .currentState .Command .Type == state .Command_KICKOFF {
35
- // ball in center circle
36
- if e .gcState .TrackerStateGc .Ball .Pos .ToVector2 ().Length () > e .getGeometry ().CenterCircleRadius {
37
- return
38
- }
39
-
40
- // bots on wrong side
41
- for _ , robot := range e .gcState .TrackerStateGc .Robots {
42
- if * e .currentState .TeamState [robot .Id .Team .String ()].OnPositiveHalf {
43
- if * robot .Pos .X < robotRadius {
44
- return
45
- }
46
- } else if * robot .Pos .X > - robotRadius {
47
- return
48
- }
49
- }
46
+ issues = append (issues , e .readyToContinueKickoff ()... )
50
47
}
51
48
52
49
if * e .currentState .Command .Type == state .Command_PENALTY {
53
- keeperId := e .penaltyKeeperId ()
54
- if keeperId == nil {
55
- return
56
- }
57
- keeperPos := e .robotPos (keeperId )
58
- if keeperPos == nil || ! e .posInsideGoal (keeperPos ) {
59
- return
60
- }
50
+ issues = append (issues , e .readyToContinuePenalty ()... )
51
+ }
61
52
62
- keeperTeamInfo := e .currentState .TeamState [keeperId .Team .String ()]
63
- ballPos := e .gcState .TrackerStateGc .Ball .Pos
53
+ if * e .currentState .Command .Type == state .Command_STOP {
54
+ issues = append (issues , e .readyToContinueFromStop ()... )
55
+ }
64
56
65
- numAttackersInFrontOfBall := 0
66
- for _ , robot := range e .gcState .TrackerStateGc .Robots {
67
- if * robot .Id .Id == * keeperId .Id && * robot .Id .Team == * keeperId .Team {
68
- // its the keeper
69
- continue
70
- }
71
- if * keeperTeamInfo .OnPositiveHalf &&
72
- * robot .Pos .X < * ballPos .X - distanceToBallDuringPenalty {
73
- continue
74
- } else if ! * keeperTeamInfo .OnPositiveHalf &&
75
- * robot .Pos .X > * ballPos .X + distanceToBallDuringPenalty {
76
- continue
77
- }
78
- if * robot .Id .Team == * keeperId .Team {
79
- return
80
- } else if numAttackersInFrontOfBall >= 1 {
81
- return
82
- } else {
83
- numAttackersInFrontOfBall ++
57
+ return
58
+ }
59
+
60
+ func (e * Engine ) readyToContinueKickoff () (issues []string ) {
61
+ ballToCenterCircleDist := e .gcState .TrackerStateGc .Ball .Pos .ToVector2 ().Length () - e .getGeometry ().CenterCircleRadius
62
+ if ballToCenterCircleDist > 0 {
63
+ issues = append (issues , fmt .Sprintf ("Ball is %.1f m away from center circle" , ballToCenterCircleDist ))
64
+ }
65
+
66
+ for _ , robot := range e .gcState .TrackerStateGc .Robots {
67
+ if * e .currentState .TeamState [robot .Id .Team .String ()].OnPositiveHalf {
68
+ if * robot .Pos .X < robotRadius {
69
+ issues = append (issues , fmt .Sprintf ("Robot %s is not in its own half" , robot .Id .PrettyString ()))
84
70
}
71
+ } else if * robot .Pos .X > - robotRadius {
72
+ issues = append (issues , fmt .Sprintf ("Robot %s is not in its own half" , robot .Id .PrettyString ()))
85
73
}
86
74
}
75
+ return issues
76
+ }
87
77
88
- if * e .currentState .Command .Type == state .Command_STOP &&
89
- (e .currentState .NextCommand == nil ||
90
- ! e .readyToContinueFromStop ()) {
78
+ func (e * Engine ) readyToContinuePenalty () (issues []string ) {
79
+ keeperId := e .penaltyKeeperId ()
80
+ if keeperId == nil {
81
+ issues = append (issues , "There is no keeper" )
91
82
return
92
83
}
93
-
94
- if * e . currentState . Command . Type == state . Command_STOP &&
95
- ( e . currentState . NextCommand == nil ||
96
- ! e .readyToContinueFromHalt () ) {
97
- return
84
+ keeperPos := e . robotPos ( keeperId )
85
+ if keeperPos == nil {
86
+ issues = append ( issues , "Keeper position is unknown" )
87
+ } else if ! e .posInsideGoal ( keeperPos ) {
88
+ issues = append ( issues , "Keeper is not inside goal" )
98
89
}
99
90
100
- readyToContinue = true
91
+ keeperTeamInfo := e .currentState .TeamState [keeperId .Team .String ()]
92
+ ballPos := e .gcState .TrackerStateGc .Ball .Pos
101
93
102
- if e .currentState .GetAutoContinue () {
103
- e .Enqueue (& statemachine.Change {
104
- Origin : & changeOriginEngine ,
105
- Change : & statemachine.Change_Continue {
106
- Continue : & statemachine.Continue {},
107
- },
108
- })
94
+ numAttackersInFrontOfBall := 0
95
+ for _ , robot := range e .gcState .TrackerStateGc .Robots {
96
+ if * robot .Id .Id == * keeperId .Id && * robot .Id .Team == * keeperId .Team {
97
+ // it's the keeper
98
+ continue
99
+ }
100
+ if * keeperTeamInfo .OnPositiveHalf &&
101
+ * robot .Pos .X < * ballPos .X - distanceToBallDuringPenalty {
102
+ continue
103
+ } else if ! * keeperTeamInfo .OnPositiveHalf &&
104
+ * robot .Pos .X > * ballPos .X + distanceToBallDuringPenalty {
105
+ continue
106
+ }
107
+ if * robot .Id .Team == * keeperId .Team {
108
+ issues = append (issues , fmt .Sprintf (
109
+ "Robot %s does not keep required distance to ball" , robot .Id .PrettyString ()))
110
+ } else if numAttackersInFrontOfBall >= 1 {
111
+ issues = append (issues , fmt .Sprintf (
112
+ "Robot %s does not keep required distance to ball" , robot .Id .PrettyString ()))
113
+ } else {
114
+ numAttackersInFrontOfBall ++
115
+ }
109
116
}
117
+ return
118
+ }
119
+
120
+ func (e * Engine ) readyToContinueFromStop () (issues []string ) {
121
+ if e .tooManyRobots (state .Team_YELLOW ) {
122
+ issues = append (issues , "Yellow team has too many robots" )
123
+ }
124
+ if e .tooManyRobots (state .Team_BLUE ) {
125
+ issues = append (issues , "Blue team has too many robots" )
126
+ }
127
+ radius := e .gameConfig .DistanceToBallInStop + robotRadius - distanceThreshold
128
+ robotNearBall := e .findRobotInsideRadius (e .gcState .TrackerStateGc .Robots , e .gcState .TrackerStateGc .Ball .Pos .ToVector2 (), radius )
129
+ if robotNearBall != nil {
130
+ issues = append (issues , fmt .Sprintf ("Robot %s is too close to ball" , robotNearBall .Id .PrettyString ()))
131
+ }
132
+ if e .currentState .PlacementPos != nil {
133
+ ballToPlacementPosDist := e .currentState .PlacementPos .DistanceTo (e .gcState .TrackerStateGc .Ball .Pos .ToVector2 ())
134
+ if ballToPlacementPosDist > e .gameConfig .BallPlacementTolerance {
135
+ issues = append (issues , fmt .Sprintf ("Ball is %.1fm (>%.1fm) away from placement pos" ,
136
+ ballToPlacementPosDist , e .gameConfig .BallPlacementTolerance ))
137
+ }
138
+ }
139
+ if ! e .ballSteady () {
140
+ issues = append (issues , "Ball position is not steady" )
141
+ }
142
+ if e .currentState .NextCommand == nil {
143
+ issues = append (issues , "No next command" )
144
+ }
145
+ return
110
146
}
111
147
112
148
func (e * Engine ) penaltyKeeperId () * state.RobotId {
@@ -136,28 +172,6 @@ func (e *Engine) posInsideGoal(pos *geom.Vector2) bool {
136
172
return goalArea .IsPointInside (pos )
137
173
}
138
174
139
- func (e * Engine ) readyToContinueFromStop () bool {
140
- radius := e .gameConfig .DistanceToBallInStop + robotRadius - distanceThreshold
141
- if e .gcState .TrackerStateGc .Ball == nil ||
142
- ! e .ballSteady () ||
143
- e .robotsInsideRadius (e .gcState .TrackerStateGc .Robots , e .gcState .TrackerStateGc .Ball .Pos .ToVector2 (), radius ) {
144
- return false
145
- }
146
- return true
147
- }
148
-
149
- func (e * Engine ) readyToContinueFromHalt () bool {
150
- if e .gcState .TrackerStateGc .Ball == nil ||
151
- e .currentState .PlacementPos == nil ||
152
- ! e .ballSteady () ||
153
- e .currentState .PlacementPos .DistanceTo (e .gcState .TrackerStateGc .Ball .Pos .ToVector2 ()) > e .gameConfig .BallPlacementTolerance ||
154
- e .tooManyRobots (state .Team_BLUE ) ||
155
- e .tooManyRobots (state .Team_YELLOW ) {
156
- return false
157
- }
158
- return true
159
- }
160
-
161
175
func (e * Engine ) tooManyRobots (team state.Team ) bool {
162
176
maxAllowed := * e .currentState .TeamState [team .String ()].MaxAllowedBots
163
177
current := numRobotsOfTeam (e .gcState .TrackerStateGc .Robots , team )
0 commit comments