@@ -3,6 +3,7 @@ package controller
33import (
44 "github.com/RoboCup-SSL/ssl-game-controller/pkg/refproto"
55 "log"
6+ "math"
67)
78
89// BallPlacementPos determines the ball placement position based on the game event
@@ -17,81 +18,134 @@ func (e *Engine) BallPlacementPos() *Location {
1718
1819 switch event .Type {
1920 case GameEventBallLeftFieldTouchLine :
20- return validateProtoLocation (event .Details .BallLeftFieldTouchLine .Location )
21+ return e . validateProtoLocation (event .Details .BallLeftFieldTouchLine .Location )
2122 case GameEventBallLeftFieldGoalLine :
22- // TODO corner
23- return validateProtoLocation (event .Details .BallLeftFieldGoalLine .Location )
23+ if event .Details .BallLeftFieldGoalLine .Location != nil && e .isGoalKick (event ) {
24+ location := mapProtoLocation (event .Details .BallLeftFieldGoalLine .Location )
25+ maxX := e .Geometry .FieldLength / 2 - e .Geometry .PlacementOffsetGoalLineGoalKick
26+ if math .Abs (location .X ) > maxX {
27+ location .X = math .Copysign (maxX , location .X )
28+ }
29+ return e .validateLocation (location )
30+ }
31+ return e .validateProtoLocation (event .Details .BallLeftFieldGoalLine .Location )
2432 case GameEventIcing :
25- return validateProtoLocation (event .Details .Icing .KickLocation )
33+ return e . validateProtoLocation (event .Details .Icing .KickLocation )
2634 case GameEventGoal :
2735 return & Location {X : 0.0 , Y : 0.0 }
2836 case GameEventIndirectGoal :
29- return validateProtoLocation (event .Details .IndirectGoal .KickLocation )
37+ return e . validateProtoLocation (event .Details .IndirectGoal .KickLocation )
3038 case GameEventChippedGoal :
31- return validateProtoLocation (event .Details .ChippedGoal .KickLocation )
39+ return e . validateProtoLocation (event .Details .ChippedGoal .KickLocation )
3240 case GameEventBotTippedOver :
33- return validateProtoLocation (event .Details .BotTippedOver .Location )
41+ return e . validateProtoLocation (event .Details .BotTippedOver .Location )
3442 case GameEventBotInterferedPlacement :
35- return validateLocation (e .State .PlacementPos )
43+ return e . validateLocation (e .State .PlacementPos )
3644 case GameEventBotCrashDrawn :
37- return validateProtoLocation (event .Details .BotCrashDrawn .Location )
45+ return e . validateProtoLocation (event .Details .BotCrashDrawn .Location )
3846 case GameEventBotKickedBallTooFast :
39- return validateProtoLocation (event .Details .BotKickedBallTooFast .Location )
47+ return e . validateProtoLocation (event .Details .BotKickedBallTooFast .Location )
4048 case GameEventBotDribbledBallTooFar :
41- return validateProtoLocation (event .Details .BotDribbledBallTooFar .Start )
49+ return e . validateProtoLocation (event .Details .BotDribbledBallTooFar .Start )
4250 case GameEventBotCrashUnique :
43- return validateProtoLocation (event .Details .BotCrashUnique .Location )
51+ return e . validateProtoLocation (event .Details .BotCrashUnique .Location )
4452 case GameEventBotCrashUniqueContinue :
45- return validateProtoLocation (event .Details .BotCrashUniqueContinue .Location )
53+ return e . validateProtoLocation (event .Details .BotCrashUniqueContinue .Location )
4654 case GameEventBotPushedBot :
47- return validateProtoLocation (event .Details .BotPushedBot .Location )
55+ return e . validateProtoLocation (event .Details .BotPushedBot .Location )
4856 case GameEventBotPushedBotContinue :
49- return validateProtoLocation (event .Details .BotPushedBotContinue .Location )
57+ return e . validateProtoLocation (event .Details .BotPushedBotContinue .Location )
5058 case GameEventBotHeldBallDeliberately :
51- return validateProtoLocation (event .Details .BotHeldBallDeliberately .Location )
59+ return e . validateProtoLocation (event .Details .BotHeldBallDeliberately .Location )
5260 case GameEventAttackerDoubleTouchedBall :
53- return validateProtoLocation (event .Details .AttackerDoubleTouchedBall .Location )
61+ return e . validateProtoLocation (event .Details .AttackerDoubleTouchedBall .Location )
5462 case GameEventAttackerTooCloseToDefenseArea :
55- return validateProtoLocation (event .Details .AttackerTooCloseToDefenseArea .Location )
63+ return e . validateProtoLocation (event .Details .AttackerTooCloseToDefenseArea .Location )
5664 case GameEventAttackerInDefenseArea :
57- return validateProtoLocation (event .Details .AttackerInDefenseArea .Location )
65+ return e . validateProtoLocation (event .Details .AttackerInDefenseArea .Location )
5866 case GameEventAttackerTouchedKeeper :
59- return validateProtoLocation (event .Details .AttackerTouchedKeeper .Location )
67+ return e . validateProtoLocation (event .Details .AttackerTouchedKeeper .Location )
6068 case GameEventDefenderTooCloseToKickPoint :
61- return validateLocation (e .State .PlacementPos )
69+ return e . validateLocation (e .State .PlacementPos )
6270 case GameEventDefenderInDefenseAreaPartially :
63- return validateProtoLocation (event .Details .DefenderInDefenseAreaPartially .Location )
71+ return e . validateProtoLocation (event .Details .DefenderInDefenseAreaPartially .Location )
6472 case GameEventDefenderInDefenseArea :
65- // TODO penalty mark
66- return nil
73+ teamInFavor := event .ByTeam ().Opposite ()
74+ location := Location {}
75+ location .X = (e .Geometry .FieldLength / 2.0 ) - e .Geometry .PenaltyAreaDepth
76+ if e .State .TeamState [teamInFavor ].OnPositiveHalf {
77+ location .X *= - 1
78+ }
79+ return & location
6780 case GameEventKeeperHeldBall :
68- return validateProtoLocation (event .Details .KeeperHeldBall .Location )
81+ return e . validateProtoLocation (event .Details .KeeperHeldBall .Location )
6982 case GameEventKickTimeout :
70- return validateLocation (e .State .PlacementPos )
83+ return e . validateLocation (e .State .PlacementPos )
7184 case GameEventNoProgressInGame :
72- return validateProtoLocation (event .Details .NoProgressInGame .Location )
85+ return e . validateProtoLocation (event .Details .NoProgressInGame .Location )
7386 case GameEventPlacementFailedByTeamInFavor :
74- return validateLocation (e .State .PlacementPos )
87+ return e . validateLocation (e .State .PlacementPos )
7588 case GameEventPlacementFailedByOpponent :
76- return validateLocation (e .State .PlacementPos )
89+ return e . validateLocation (e .State .PlacementPos )
7790 default :
7891 log .Print ("Warn: Unknown game event: " , event .Type )
7992 return nil
8093 }
8194}
8295
83- func validateProtoLocation (location * refproto.Location ) * Location {
96+ func (e * Engine ) isGoalKick (event * GameEvent ) bool {
97+ teamInFavor := event .ByTeam ().Opposite ()
98+ location := mapProtoLocation (event .Details .BallLeftFieldGoalLine .Location )
99+ if e .State .TeamState [teamInFavor ].OnPositiveHalf && location .X > 0 {
100+ return true
101+ }
102+ if ! e .State .TeamState [teamInFavor ].OnPositiveHalf && location .X < 0 {
103+ return true
104+ }
105+ return false
106+ }
107+
108+ func mapProtoLocation (location * refproto.Location ) * Location {
109+ return & Location {X : float64 (* location .X ), Y : float64 (* location .Y )}
110+ }
111+
112+ func (e * Engine ) validateProtoLocation (location * refproto.Location ) * Location {
84113 if location == nil {
85114 return nil
86115 }
87- return validateLocation (& Location { X : * location . X , Y : * location . Y } )
116+ return e . validateLocation (mapProtoLocation ( location ) )
88117}
89118
90- func validateLocation (location * Location ) * Location {
119+ func ( e * Engine ) validateLocation (location * Location ) * Location {
91120 if location == nil {
92121 return nil
93122 }
94- // TODO move inside field
95- // TODO move away from defense area
123+
124+ e .movePositionInsideField (location )
125+ e .movePositionOutOfDefenseArea (location )
126+
96127 return location
97128}
129+
130+ func (e * Engine ) movePositionOutOfDefenseArea (location * Location ) {
131+ maxX := e .Geometry .FieldLength / 2 - e .Geometry .PenaltyAreaDepth - e .Geometry .PlacementOffsetDefenseArea
132+ minY := e .Geometry .PenaltyAreaWidth + e .Geometry .PlacementOffsetDefenseArea
133+ if math .Abs (location .X ) > maxX && math .Abs (location .Y ) < minY {
134+ if math .Abs (maxX - math .Abs (location .X )) < math .Abs (minY - math .Abs (location .Y )) {
135+ location .X = math .Copysign (maxX , location .X )
136+ } else {
137+ location .Y = math .Copysign (minY , location .Y )
138+ }
139+ }
140+ }
141+
142+ func (e * Engine ) movePositionInsideField (location * Location ) {
143+ maxX := e .Geometry .FieldLength / 2 - e .Geometry .PlacementOffsetGoalLine
144+ if math .Abs (location .X ) > maxX {
145+ location .X = math .Copysign (maxX , location .X )
146+ }
147+ maxY := e .Geometry .FieldWidth / 2 - e .Geometry .PlacementOffsetTouchLine
148+ if math .Abs (location .Y ) > maxY {
149+ location .Y = math .Copysign (maxY , location .Y )
150+ }
151+ }
0 commit comments