Skip to content

Commit 2778b61

Browse files
committed
[test] Add tests for ball placement and fixed some issues
1 parent 194f6f1 commit 2778b61

File tree

3 files changed

+169
-8
lines changed

3 files changed

+169
-8
lines changed

internal/app/controller/placementPos.go

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,32 @@ func (e *Engine) BallPlacementPos() *Location {
1818

1919
switch event.Type {
2020
case GameEventBallLeftFieldTouchLine:
21-
return e.validateProtoLocation(event.Details.BallLeftFieldTouchLine.Location)
21+
if event.Details.BallLeftFieldTouchLine.Location != nil {
22+
location := mapProtoLocation(event.Details.BallLeftFieldTouchLine.Location)
23+
x := e.Geometry.FieldLength/2 - e.Geometry.PlacementOffsetGoalLine
24+
if math.Abs(location.X) > x {
25+
location.X = math.Copysign(x, location.X)
26+
}
27+
y := e.Geometry.FieldWidth/2 - e.Geometry.PlacementOffsetTouchLine
28+
location.Y = math.Copysign(y, location.Y)
29+
return e.validateLocation(location)
30+
}
31+
return nil
2232
case GameEventBallLeftFieldGoalLine:
23-
if event.Details.BallLeftFieldGoalLine.Location != nil && e.isGoalKick(event) {
33+
if event.Details.BallLeftFieldGoalLine.Location != nil {
2434
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)
35+
var x float64
36+
if e.isGoalKick(event) {
37+
x = e.Geometry.FieldLength/2 - e.Geometry.PlacementOffsetGoalLineGoalKick
38+
} else {
39+
x = e.Geometry.FieldLength/2 - e.Geometry.PlacementOffsetGoalLine
2840
}
41+
location.X = math.Copysign(x, location.X)
42+
y := e.Geometry.FieldWidth/2 - e.Geometry.PlacementOffsetTouchLine
43+
location.Y = math.Copysign(y, location.Y)
2944
return e.validateLocation(location)
3045
}
31-
return e.validateProtoLocation(event.Details.BallLeftFieldGoalLine.Location)
46+
return nil
3247
case GameEventIcing:
3348
return e.validateProtoLocation(event.Details.Icing.KickLocation)
3449
case GameEventGoal:
@@ -129,9 +144,11 @@ func (e *Engine) validateLocation(location *Location) *Location {
129144

130145
func (e *Engine) movePositionOutOfDefenseArea(location *Location) {
131146
maxX := e.Geometry.FieldLength/2 - e.Geometry.DefenseAreaDepth - e.Geometry.PlacementOffsetDefenseArea
132-
minY := e.Geometry.DefenseAreaWidth + e.Geometry.PlacementOffsetDefenseArea
147+
minY := e.Geometry.DefenseAreaWidth/2 + e.Geometry.PlacementOffsetDefenseArea
133148
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)) {
149+
diffX := math.Abs(maxX - math.Abs(location.X))
150+
diffY := math.Abs(minY - math.Abs(location.Y))
151+
if diffX < diffY {
135152
location.X = math.Copysign(maxX, location.X)
136153
} else {
137154
location.Y = math.Copysign(minY, location.Y)
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package controller
2+
3+
import (
4+
"github.com/RoboCup-SSL/ssl-game-controller/pkg/refproto"
5+
"math"
6+
"testing"
7+
)
8+
9+
func TestEngine_BallPlacementPos(t *testing.T) {
10+
config := DefaultConfig()
11+
engine := NewEngine(config.Game)
12+
engine.State.TeamState[TeamYellow].OnPositiveHalf = true
13+
engine.State.TeamState[TeamBlue].OnPositiveHalf = false
14+
engine.Geometry.PlacementOffsetTouchLine = 0.2
15+
engine.Geometry.PlacementOffsetGoalLine = 0.3 // avoid confusion with touchLine value
16+
engine.Geometry.PlacementOffsetGoalLineGoalKick = 1.0
17+
fw := engine.Geometry.FieldWidth
18+
fl := engine.Geometry.FieldLength
19+
dd := engine.Geometry.DefenseAreaDepth
20+
dw := engine.Geometry.DefenseAreaWidth
21+
ot := engine.Geometry.PlacementOffsetTouchLine
22+
og := engine.Geometry.PlacementOffsetGoalLine
23+
ogg := engine.Geometry.PlacementOffsetGoalLineGoalKick
24+
od := engine.Geometry.PlacementOffsetDefenseArea
25+
26+
// ball left field touch line
27+
setBallLeftFieldTouchLine(&engine, Location{0, fw / 2}.toProto())
28+
assertSimilar(t, &engine, Location{0, fw/2 - ot})
29+
30+
setBallLeftFieldTouchLine(&engine, Location{0.1, fw / 2}.toProto())
31+
assertSimilar(t, &engine, Location{0.1, fw/2 - ot})
32+
33+
setBallLeftFieldTouchLine(&engine, Location{0, 42}.toProto())
34+
assertSimilar(t, &engine, Location{0, fw/2 - ot})
35+
36+
setBallLeftFieldTouchLine(&engine, Location{0, 1}.toProto())
37+
assertSimilar(t, &engine, Location{0, fw/2 - ot})
38+
39+
setBallLeftFieldTouchLine(&engine, Location{0, -fw / 2}.toProto())
40+
assertSimilar(t, &engine, Location{0, -(fw/2 - ot)})
41+
42+
setBallLeftFieldTouchLine(&engine, Location{fl / 2, fw / 2}.toProto())
43+
assertSimilar(t, &engine, Location{fl/2 - og, fw/2 - ot})
44+
45+
setBallLeftFieldTouchLine(&engine, Location{-fl / 2, fw / 2}.toProto())
46+
assertSimilar(t, &engine, Location{-(fl/2 - og), fw/2 - ot})
47+
48+
// ball left field goal line
49+
setBallLeftFieldGoalLine(&engine, Location{fl / 2, fw / 2}.toProto(), TeamYellow)
50+
assertSimilar(t, &engine, Location{fl/2 - ogg, fw/2 - ot})
51+
52+
setBallLeftFieldGoalLine(&engine, Location{-fl / 2, fw / 2}.toProto(), TeamYellow)
53+
assertSimilar(t, &engine, Location{-(fl/2 - og), fw/2 - ot})
54+
55+
setBallLeftFieldGoalLine(&engine, Location{fl / 2, fw / 4}.toProto(), TeamYellow)
56+
assertSimilar(t, &engine, Location{fl/2 - ogg, fw/2 - ot})
57+
58+
setBallLeftFieldGoalLine(&engine, Location{fl / 2, fw / 4}.toProto(), TeamBlue)
59+
assertSimilar(t, &engine, Location{fl/2 - og, fw/2 - ot})
60+
61+
setBallLeftFieldGoalLine(&engine, Location{fl / 2, 0}.toProto(), TeamBlue)
62+
assertSimilar(t, &engine, Location{fl/2 - og, fw/2 - ot})
63+
64+
setBallLeftFieldGoalLine(&engine, Location{fl / 2, -fw}.toProto(), TeamBlue)
65+
assertSimilar(t, &engine, Location{fl/2 - og, -(fw/2 - ot)})
66+
67+
// bot crash unique
68+
setBotCrashUnique(&engine, Location{0, 0}.toProto())
69+
assertSimilar(t, &engine, Location{0, 0})
70+
71+
setBotCrashUnique(&engine, Location{1, -2}.toProto())
72+
assertSimilar(t, &engine, Location{1, -2})
73+
74+
setBotCrashUnique(&engine, Location{1, -42}.toProto())
75+
assertSimilar(t, &engine, Location{1, -(fw/2 - ot)})
76+
77+
setBotCrashUnique(&engine, Location{1, 42}.toProto())
78+
assertSimilar(t, &engine, Location{1, fw/2 - ot})
79+
80+
setBotCrashUnique(&engine, Location{fl / 2, -42}.toProto())
81+
assertSimilar(t, &engine, Location{fl/2 - og, -(fw/2 - ot)})
82+
83+
setBotCrashUnique(&engine, Location{-fl / 2, -42}.toProto())
84+
assertSimilar(t, &engine, Location{-(fl/2 - og), -(fw/2 - ot)})
85+
86+
setBotCrashUnique(&engine, Location{42, 0}.toProto())
87+
assertSimilar(t, &engine, Location{fl/2 - dd - od, 0})
88+
89+
setBotCrashUnique(&engine, Location{fl/2 - 0.1, dw/2 - 0.1}.toProto())
90+
assertSimilar(t, &engine, Location{fl/2 - og, dw/2 + od})
91+
92+
setBotCrashUnique(&engine, Location{fl/2 - dd, dw/2 - 0.1}.toProto())
93+
assertSimilar(t, &engine, Location{fl/2 - dd - od, dw/2 - 0.1})
94+
}
95+
96+
func assertSimilar(t *testing.T, engine *Engine, expected Location) {
97+
placementPos := engine.BallPlacementPos()
98+
if !similar(expected, *placementPos) {
99+
t.Fatalf("Expected placement pos to be %v, but was %v", expected, *placementPos)
100+
}
101+
}
102+
103+
func setBallLeftFieldTouchLine(engine *Engine, eventLocation *refproto.Location) {
104+
var byTeam = TeamYellow.toProto()
105+
engine.State.GameEvents = []*GameEvent{{
106+
Type: GameEventBallLeftFieldTouchLine,
107+
Details: GameEventDetails{
108+
BallLeftFieldTouchLine: &refproto.GameEvent_BallLeftFieldEvent{
109+
ByTeam: &byTeam,
110+
Location: eventLocation}}}}
111+
}
112+
113+
func setBallLeftFieldGoalLine(engine *Engine, eventLocation *refproto.Location, placingTeam Team) {
114+
var byTeam = placingTeam.Opposite().toProto()
115+
engine.State.GameEvents = []*GameEvent{{
116+
Type: GameEventBallLeftFieldGoalLine,
117+
Details: GameEventDetails{
118+
BallLeftFieldGoalLine: &refproto.GameEvent_BallLeftFieldEvent{
119+
ByTeam: &byTeam,
120+
Location: eventLocation}}}}
121+
}
122+
123+
func setBotCrashUnique(engine *Engine, eventLocation *refproto.Location) {
124+
var byTeam = TeamYellow.toProto()
125+
engine.State.GameEvents = []*GameEvent{{
126+
Type: GameEventBotCrashUnique,
127+
Details: GameEventDetails{
128+
BotCrashUnique: &refproto.GameEvent_BotCrashUnique{
129+
ByTeam: &byTeam,
130+
Location: eventLocation}}}}
131+
}
132+
133+
func similar(l1 Location, l2 Location) bool {
134+
return math.Abs(l1.X-l2.X) < 1e-4 && math.Abs(l1.Y-l2.Y) < 1e-4
135+
}

internal/app/controller/state.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,3 +357,12 @@ type Location struct {
357357
X float64
358358
Y float64
359359
}
360+
361+
func (l Location) toProto() (p *refproto.Location) {
362+
p = new(refproto.Location)
363+
p.X = new(float32)
364+
p.Y = new(float32)
365+
*p.X = float32(l.X)
366+
*p.Y = float32(l.Y)
367+
return
368+
}

0 commit comments

Comments
 (0)