1
1
package engine
2
2
3
3
import (
4
- "github.com/RoboCup-SSL/ssl-game-controller/internal/app/geom"
5
4
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/state"
6
5
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/statemachine"
7
6
"log"
8
7
"math"
9
- "sort"
10
8
"time"
11
9
)
12
10
13
- const similarLocationTolerance = 0.5
14
-
15
11
func (e * Engine ) processProposals () {
16
12
17
- deadline := e .timeProvider ().Add (- e .gameConfig .AutoRefProposalTimeout )
18
- matchingProposals := collectMatchingProposals (e .currentState .GameEventProposals , deadline )
19
- numProposals := len (matchingProposals )
20
- if numProposals == 0 {
21
- return
22
- }
23
-
24
- sort .Slice (matchingProposals , func (i , j int ) bool {
25
- return goTime (matchingProposals [i ].Timestamp ).Before (goTime (matchingProposals [j ].Timestamp ))
26
- })
13
+ now := e .timeProvider ()
14
+ proposalTimeout := e .gameConfig .AutoRefProposalTimeout
15
+ minTime := now .Add (- proposalTimeout )
27
16
28
- firstGameEvent := matchingProposals [0 ].GameEvent
29
- numAutoRefs := e .numAutoRefs (firstGameEvent )
30
- majority := int (math .Floor (float64 (numAutoRefs ) / 2.0 ))
31
-
32
- if numProposals > majority {
33
- log .Printf ("Majority of %v reached with %v out of %v for %v." , majority , numProposals , numAutoRefs , firstGameEvent .Type )
34
- e .Enqueue (& statemachine.Change {
35
- Change : & statemachine.Change_AcceptGameEventProposals {
36
- AcceptGameEventProposals : & statemachine.AcceptGameEventProposals {
37
- Proposals : matchingProposals ,
17
+ for i , group := range e .currentState .ProposalGroups {
18
+ if * group .Accepted || groupHasRecentProposal (group , minTime ) {
19
+ continue
20
+ }
21
+ numProposals := uniqueOrigins (group )
22
+ latestGameEvent := group .Proposals [len (group .Proposals )- 1 ].GameEvent
23
+ numAutoRefs := e .numAutoRefs (latestGameEvent )
24
+ majority := int (math .Floor (float64 (numAutoRefs ) / 2.0 ))
25
+
26
+ if numProposals > majority {
27
+ log .Printf ("Majority of %v reached with %v out of %v for %v." , majority , numProposals , numAutoRefs , latestGameEvent .Type )
28
+ groupId := uint32 (i )
29
+ acceptedBy := "Majority"
30
+ e .Enqueue (& statemachine.Change {
31
+ Change : & statemachine.Change_AcceptProposalGroup {
32
+ AcceptProposalGroup : & statemachine.AcceptProposalGroup {
33
+ GroupId : & groupId ,
34
+ AcceptedBy : & acceptedBy ,
35
+ },
38
36
},
39
- },
40
- })
37
+ })
38
+ }
39
+ }
40
+ }
41
+
42
+ func uniqueOrigins (group * state.ProposalGroup ) int {
43
+ origins := map [string ]bool {}
44
+ for _ , p := range group .Proposals {
45
+ for _ , o := range p .GameEvent .Origin {
46
+ origins [o ] = true
47
+ }
41
48
}
49
+ return len (origins )
50
+ }
51
+
52
+ func groupHasRecentProposal (group * state.ProposalGroup , minTime time.Time ) bool {
53
+ latestProposal := group .Proposals [len (group .Proposals )- 1 ]
54
+ return goTime (latestProposal .Timestamp ).Before (minTime )
42
55
}
43
56
44
57
func (e * Engine ) numAutoRefs (gameEvent * state.GameEvent ) (n int ) {
@@ -53,99 +66,3 @@ func (e *Engine) numAutoRefs(gameEvent *state.GameEvent) (n int) {
53
66
}
54
67
return
55
68
}
56
-
57
- func collectMatchingProposals (events []* state.GameEventProposal , deadline time.Time ) []* state.GameEventProposal {
58
- proposals := [][]* state.GameEventProposal {}
59
- for _ , proposal := range events {
60
- if (proposal .Accepted != nil && * proposal .Accepted ) ||
61
- goTime (proposal .Timestamp ).After (deadline ) {
62
- continue
63
- }
64
- if ok , pid := findGroup (proposal , proposals ); ok {
65
- proposals [pid ] = append (proposals [pid ], proposal )
66
- continue
67
- }
68
- proposals = append (proposals , []* state.GameEventProposal {proposal })
69
- }
70
-
71
- if len (proposals ) == 0 {
72
- return []* state.GameEventProposal {}
73
- }
74
-
75
- sort .SliceStable (proposals , func (i , j int ) bool {
76
- return len (proposals [i ]) > len (proposals [j ])
77
- })
78
-
79
- return proposals [0 ]
80
- }
81
-
82
- func findGroup (proposal * state.GameEventProposal , proposals [][]* state.GameEventProposal ) (bool , int ) {
83
- for i , p := range proposals {
84
- if gameEventsSimilar (proposal .GameEvent , p [0 ].GameEvent ) {
85
- return true , i
86
- }
87
- }
88
- return false , - 1
89
- }
90
-
91
- func gameEventsSimilar (e1 , e2 * state.GameEvent ) bool {
92
- if * e1 .Type != * e2 .Type {
93
- return false
94
- }
95
- // check similarity based on details for some events:
96
- switch * e1 .Type {
97
- case state .GameEvent_BOT_TOO_FAST_IN_STOP :
98
- return similarTeam (e1 .GetBotTooFastInStop ().ByTeam , e2 .GetBotTooFastInStop ().ByTeam ) &&
99
- similarBot (e1 .GetBotTooFastInStop ().ByBot , e2 .GetBotTooFastInStop ().ByBot )
100
- case state .GameEvent_DEFENDER_TOO_CLOSE_TO_KICK_POINT :
101
- return similarTeam (e1 .GetDefenderTooCloseToKickPoint ().ByTeam , e2 .GetDefenderTooCloseToKickPoint ().ByTeam ) &&
102
- similarBot (e1 .GetDefenderTooCloseToKickPoint ().ByBot , e2 .GetDefenderTooCloseToKickPoint ().ByBot )
103
- case state .GameEvent_BOT_CRASH_DRAWN :
104
- return similarBot (e1 .GetBotCrashDrawn ().BotYellow , e2 .GetBotCrashDrawn ().BotYellow ) &&
105
- similarBot (e1 .GetBotCrashDrawn ().BotBlue , e2 .GetBotCrashDrawn ().BotBlue ) &&
106
- similarLocation (e1 .GetBotCrashDrawn ().Location , e2 .GetBotCrashDrawn ().Location , similarLocationTolerance )
107
- case state .GameEvent_BOT_CRASH_UNIQUE :
108
- return similarTeam (e1 .GetBotCrashUnique ().ByTeam , e2 .GetBotCrashUnique ().ByTeam ) &&
109
- similarBot (e1 .GetBotCrashUnique ().Violator , e2 .GetBotCrashUnique ().Violator ) &&
110
- similarBot (e1 .GetBotCrashUnique ().Victim , e2 .GetBotCrashUnique ().Victim ) &&
111
- similarLocation (e1 .GetBotCrashUnique ().Location , e2 .GetBotCrashUnique ().Location , similarLocationTolerance )
112
- case state .GameEvent_BOT_PUSHED_BOT :
113
- return similarTeam (e1 .GetBotPushedBot ().ByTeam , e2 .GetBotPushedBot ().ByTeam ) &&
114
- similarBot (e1 .GetBotPushedBot ().Violator , e2 .GetBotPushedBot ().Violator ) &&
115
- similarBot (e1 .GetBotPushedBot ().Victim , e2 .GetBotPushedBot ().Victim ) &&
116
- similarLocation (e1 .GetBotPushedBot ().Location , e2 .GetBotPushedBot ().Location , similarLocationTolerance )
117
- case state .GameEvent_DEFENDER_IN_DEFENSE_AREA :
118
- return similarTeam (e1 .GetDefenderInDefenseArea ().ByTeam , e2 .GetDefenderInDefenseArea ().ByTeam ) &&
119
- similarBot (e1 .GetDefenderInDefenseArea ().ByBot , e2 .GetDefenderInDefenseArea ().ByBot )
120
- case state .GameEvent_ATTACKER_TOUCHED_BALL_IN_DEFENSE_AREA :
121
- return similarTeam (e1 .GetAttackerTouchedBallInDefenseArea ().ByTeam , e2 .GetAttackerTouchedBallInDefenseArea ().ByTeam ) &&
122
- similarBot (e1 .GetAttackerTouchedBallInDefenseArea ().ByBot , e2 .GetAttackerTouchedBallInDefenseArea ().ByBot )
123
- case state .GameEvent_BOT_KICKED_BALL_TOO_FAST :
124
- return similarTeam (e1 .GetBotKickedBallTooFast ().ByTeam , e2 .GetBotKickedBallTooFast ().ByTeam )
125
- case state .GameEvent_BOT_DRIBBLED_BALL_TOO_FAR :
126
- return similarTeam (e1 .GetBotDribbledBallTooFar ().ByTeam , e2 .GetBotDribbledBallTooFar ().ByTeam )
127
- case state .GameEvent_ATTACKER_DOUBLE_TOUCHED_BALL :
128
- return similarTeam (e1 .GetAttackerDoubleTouchedBall ().ByTeam , e2 .GetAttackerDoubleTouchedBall ().ByTeam )
129
- case state .GameEvent_ATTACKER_TOO_CLOSE_TO_DEFENSE_AREA :
130
- return similarTeam (e1 .GetAttackerTooCloseToDefenseArea ().ByTeam , e2 .GetAttackerTooCloseToDefenseArea ().ByTeam ) &&
131
- similarBot (e1 .GetAttackerTooCloseToDefenseArea ().ByBot , e2 .GetAttackerTooCloseToDefenseArea ().ByBot )
132
- case state .GameEvent_BOT_INTERFERED_PLACEMENT :
133
- return similarTeam (e1 .GetBotInterferedPlacement ().ByTeam , e2 .GetBotInterferedPlacement ().ByTeam ) &&
134
- similarBot (e1 .GetBotInterferedPlacement ().ByBot , e2 .GetBotInterferedPlacement ().ByBot )
135
- }
136
-
137
- // all others are considered similar based on the type only
138
- return true
139
- }
140
-
141
- func similarTeam (t1 , t2 * state.Team ) bool {
142
- return (t1 == nil && t2 == nil ) || (t1 != nil && t2 != nil && * t1 == * t2 )
143
- }
144
-
145
- func similarBot (b1 , b2 * uint32 ) bool {
146
- return (b1 == nil && b2 == nil ) || (b1 != nil && b2 != nil && * b1 == * b2 )
147
- }
148
-
149
- func similarLocation (l1 , l2 * geom.Vector2 , tolerance float64 ) bool {
150
- return (l1 == nil && l2 == nil ) || (l1 != nil && l2 != nil && l1 .DistanceTo (l2 ) <= tolerance )
151
- }
0 commit comments