Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
Seminar-HFO
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Shashank Suhas
Seminar-HFO
Commits
f076b7d9
Commit
f076b7d9
authored
Aug 23, 2015
by
Matthew Hausknecht
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added a force pass behavior.
parent
5bc12581
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1733 additions
and
1 deletion
+1733
-1
src/agent.cpp
src/agent.cpp
+6
-1
src/bhv_force_pass.cpp
src/bhv_force_pass.cpp
+1556
-0
src/bhv_force_pass.h
src/bhv_force_pass.h
+171
-0
No files found.
src/agent.cpp
View file @
f076b7d9
...
...
@@ -47,6 +47,7 @@
#include "bhv_set_play_kick_in.h"
#include "bhv_set_play_indirect_free_kick.h"
#include "shoot_generator.h"
#include "bhv_force_pass.h"
#include "bhv_custom_before_kick_off.h"
#include "bhv_strict_check_shoot.h"
...
...
@@ -411,6 +412,11 @@ void Agent::actionImpl() {
=
std
::
min_element
(
cont
.
begin
(),
cont
.
end
(),
ShootGenerator
::
ScoreCmp
());
Body_SmartKick
(
best_shoot
->
target_point_
,
best_shoot
->
first_ball_speed_
,
best_shoot
->
first_ball_speed_
*
0.99
,
3
).
execute
(
this
);
}
else
if
(
action
.
action
==
PASS
)
{
Force_Pass
pass
;
int
receiver
=
int
(
action
.
arg1
);
pass
.
get_pass_to_player
(
this
->
world
(),
receiver
);
pass
.
execute
(
this
);
}
switch
(
action
.
action
)
{
case
DASH
:
...
...
@@ -431,7 +437,6 @@ void Agent::actionImpl() {
case
SHOOT
:
break
;
case
PASS
:
this
->
doPass
();
break
;
case
DRIBBLE
:
this
->
doDribble
();
...
...
src/bhv_force_pass.cpp
0 → 100644
View file @
f076b7d9
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "bhv_force_pass.h"
#include <rcsc/action/body_kick_one_step.h>
#include <rcsc/action/body_smart_kick.h>
#include <rcsc/action/body_stop_ball.h>
#include <rcsc/action/body_hold_ball2008.h>
#include <rcsc/player/player_agent.h>
#include <rcsc/player/debug_client.h>
#include <rcsc/player/audio_sensor.h>
#include <rcsc/player/say_message_builder.h>
#include <rcsc/common/logger.h>
#include <rcsc/common/server_param.h>
#include <rcsc/geom/rect_2d.h>
#include <rcsc/geom/sector_2d.h>
#include <rcsc/soccer_math.h>
#include <rcsc/math_util.h>
//#define DEBUG
using
namespace
rcsc
;
std
::
vector
<
Force_Pass
::
PassRoute
>
Force_Pass
::
S_cached_pass_route
;
/*-------------------------------------------------------------------*/
/*!
execute action
*/
bool
Force_Pass
::
execute
(
PlayerAgent
*
agent
)
{
dlog
.
addText
(
Logger
::
ACTION
,
"%s:%d: Force_Pass. execute()"
,
__FILE__
,
__LINE__
);
if
(
!
agent
->
world
().
self
().
isKickable
()
)
{
std
::
cerr
<<
__FILE__
<<
": "
<<
__LINE__
<<
" not ball kickable!"
<<
std
::
endl
;
dlog
.
addText
(
Logger
::
ACTION
,
"%s:%d: not kickable"
,
__FILE__
,
__LINE__
);
return
false
;
}
Vector2D
target_point
(
50.0
,
0.0
);
double
first_speed
=
0.0
;
int
receiver
=
0
;
if
(
!
get_best_pass
(
agent
->
world
(),
&
target_point
,
&
first_speed
,
&
receiver
)
)
{
return
false
;
}
// evaluation
// judge situation
// decide max kick step
//
agent
->
debugClient
().
addMessage
(
"pass"
);
agent
->
debugClient
().
setTarget
(
target_point
);
int
kick_step
=
(
agent
->
world
().
gameMode
().
type
()
!=
GameMode
::
PlayOn
&&
agent
->
world
().
gameMode
().
type
()
!=
GameMode
::
GoalKick_
?
1
:
3
);
if
(
!
Body_SmartKick
(
target_point
,
first_speed
,
first_speed
*
0.96
,
kick_step
).
execute
(
agent
)
)
{
if
(
agent
->
world
().
gameMode
().
type
()
!=
GameMode
::
PlayOn
&&
agent
->
world
().
gameMode
().
type
()
!=
GameMode
::
GoalKick_
)
{
first_speed
=
std
::
min
(
agent
->
world
().
self
().
kickRate
()
*
ServerParam
::
i
().
maxPower
(),
first_speed
);
Body_KickOneStep
(
target_point
,
first_speed
).
execute
(
agent
);
dlog
.
addText
(
Logger
::
ACTION
,
__FILE__
": execute() one step kick"
);
}
else
{
dlog
.
addText
(
Logger
::
ACTION
,
__FILE__
": execute() failed to pass kick."
);
return
false
;
}
}
if
(
agent
->
config
().
useCommunication
()
&&
receiver
!=
Unum_Unknown
)
{
dlog
.
addText
(
Logger
::
ACTION
,
__FILE__
": execute() set pass communication."
);
Vector2D
target_buf
=
target_point
-
agent
->
world
().
self
().
pos
();
target_buf
.
setLength
(
1.0
);
agent
->
addSayMessage
(
new
PassMessage
(
receiver
,
target_point
+
target_buf
,
agent
->
effector
().
queuedNextBallPos
(),
agent
->
effector
().
queuedNextBallVel
()
)
);
}
return
true
;
}
/*-------------------------------------------------------------------*/
/*!
static method
*/
bool
Force_Pass
::
get_best_pass
(
const
WorldModel
&
world
,
Vector2D
*
target_point
,
double
*
first_speed
,
int
*
receiver
)
{
static
GameTime
S_last_calc_time
(
0
,
0
);
static
bool
S_last_calc_valid
=
false
;
static
Vector2D
S_last_calc_target
;
static
double
S_last_calc_speed
=
0.0
;
static
int
S_last_calc_receiver
=
Unum_Unknown
;
if
(
S_last_calc_time
==
world
.
time
()
)
{
if
(
S_last_calc_valid
)
{
if
(
target_point
)
{
*
target_point
=
S_last_calc_target
;
}
if
(
first_speed
)
{
*
first_speed
=
S_last_calc_speed
;
}
if
(
receiver
)
{
*
receiver
=
S_last_calc_receiver
;
}
return
true
;
}
return
false
;
}
S_last_calc_time
=
world
.
time
();
S_last_calc_valid
=
false
;
// create route
create_routes
(
world
);
if
(
!
S_cached_pass_route
.
empty
()
)
{
std
::
vector
<
PassRoute
>::
iterator
max_it
=
std
::
max_element
(
S_cached_pass_route
.
begin
(),
S_cached_pass_route
.
end
(),
PassRouteScoreComp
()
);
S_last_calc_target
=
max_it
->
receive_point_
;
S_last_calc_speed
=
max_it
->
first_speed_
;
S_last_calc_receiver
=
max_it
->
receiver_
->
unum
();
S_last_calc_valid
=
true
;
dlog
.
addText
(
Logger
::
ACTION
,
"%s:%d: get_best_pass() size=%d. target=(%.1f %.1f)"
" speed=%.3f receiver=%d"
,
__FILE__
,
__LINE__
,
S_cached_pass_route
.
size
(),
S_last_calc_target
.
x
,
S_last_calc_target
.
y
,
S_last_calc_speed
,
S_last_calc_receiver
);
}
if
(
S_last_calc_valid
)
{
if
(
target_point
)
{
*
target_point
=
S_last_calc_target
;
}
if
(
first_speed
)
{
*
first_speed
=
S_last_calc_speed
;
}
if
(
receiver
)
{
*
receiver
=
S_last_calc_receiver
;
}
dlog
.
addText
(
Logger
::
ACTION
,
"%s:%d: best pass (%.2f, %.2f). speed=%.2f. receiver=%d"
,
__FILE__
,
__LINE__
,
S_last_calc_target
.
x
,
S_last_calc_target
.
y
,
S_last_calc_speed
,
S_last_calc_receiver
);
}
return
S_last_calc_valid
;
}
/*-------------------------------------------------------------------*/
/*!
static method
*/
bool
Force_Pass
::
get_pass_to_player
(
const
WorldModel
&
world
,
int
receiver_unum
)
{
static
GameTime
S_last_calc_time
(
0
,
0
);
static
bool
S_last_calc_valid
=
false
;
static
Vector2D
S_last_calc_target
;
static
double
S_last_calc_speed
=
0.0
;
static
int
S_last_calc_receiver
=
Unum_Unknown
;
if
(
S_last_calc_time
==
world
.
time
()
)
{
if
(
S_last_calc_valid
)
{
return
true
;
}
return
false
;
}
S_last_calc_time
=
world
.
time
();
S_last_calc_valid
=
false
;
S_cached_pass_route
.
clear
();
const
PlayerPtrCont
::
const_iterator
t_end
=
world
.
teammatesFromSelf
().
end
();
for
(
PlayerPtrCont
::
const_iterator
it
=
world
.
teammatesFromSelf
().
begin
();
it
!=
t_end
;
++
it
)
{
if
((
*
it
)
->
unum
()
==
receiver_unum
&&
(
*
it
)
->
pos
().
x
>
-
10.0
)
{
// create route
create_routes_to_player
(
world
,
*
it
);
if
(
S_cached_pass_route
.
empty
()
)
{
// Couldn't find a good pass. Add a dumb forced pass to the player.
create_forced_pass
(
world
,
*
it
);
evaluate_routes
(
world
);
}
break
;
}
}
if
(
S_cached_pass_route
.
empty
()
)
{
std
::
cerr
<<
"Cannot find a way to pass to teammate "
<<
receiver_unum
<<
std
::
endl
;
}
else
{
std
::
vector
<
PassRoute
>::
iterator
max_it
=
std
::
max_element
(
S_cached_pass_route
.
begin
(),
S_cached_pass_route
.
end
(),
PassRouteScoreComp
()
);
S_last_calc_target
=
max_it
->
receive_point_
;
S_last_calc_speed
=
max_it
->
first_speed_
;
S_last_calc_receiver
=
max_it
->
receiver_
->
unum
();
S_last_calc_valid
=
true
;
dlog
.
addText
(
Logger
::
ACTION
,
"%s:%d: get_best_pass() size=%d. target=(%.1f %.1f)"
" speed=%.3f receiver=%d"
,
__FILE__
,
__LINE__
,
S_cached_pass_route
.
size
(),
S_last_calc_target
.
x
,
S_last_calc_target
.
y
,
S_last_calc_speed
,
S_last_calc_receiver
);
dlog
.
addText
(
Logger
::
ACTION
,
"%s:%d: best pass (%.2f, %.2f). speed=%.2f. receiver=%d"
,
__FILE__
,
__LINE__
,
S_last_calc_target
.
x
,
S_last_calc_target
.
y
,
S_last_calc_speed
,
S_last_calc_receiver
);
}
return
S_last_calc_valid
;
}
/*-------------------------------------------------------------------*/
/*!
static method
*/
void
Force_Pass
::
create_routes
(
const
WorldModel
&
world
)
{
// reset old info
S_cached_pass_route
.
clear
();
// loop candidate teammates
const
PlayerPtrCont
::
const_iterator
t_end
=
world
.
teammatesFromSelf
().
end
();
for
(
PlayerPtrCont
::
const_iterator
it
=
world
.
teammatesFromSelf
().
begin
();
it
!=
t_end
;
++
it
)
{
if
(
(
*
it
)
->
goalie
()
&&
(
*
it
)
->
pos
().
x
<
-
22.0
)
{
// goalie is rejected.
continue
;
}
if
(
(
*
it
)
->
posCount
()
>
3
)
{
// low confidence players are rejected.
continue
;
}
if
(
(
*
it
)
->
pos
().
x
>
world
.
offsideLineX
()
+
1.0
)
{
// offside players are rejected.
continue
;
}
if
(
(
*
it
)
->
pos
().
x
<
world
.
ball
().
pos
().
x
-
25.0
)
{
// too back
continue
;
}
// create & verify each route
create_direct_pass
(
world
,
*
it
);
create_lead_pass
(
world
,
*
it
);
if
(
world
.
self
().
pos
().
x
>
world
.
offsideLineX
()
-
20.0
)
{
create_through_pass
(
world
,
*
it
);
}
}
////////////////////////////////////////////////////////////////
// evaluation
evaluate_routes
(
world
);
}
/*-------------------------------------------------------------------*/
/*!
static method
*/
void
Force_Pass
::
create_routes_to_player
(
const
WorldModel
&
world
,
const
PlayerObject
*
teammate
)
{
// reset old info
S_cached_pass_route
.
clear
();
if
(
teammate
->
goalie
()
&&
teammate
->
pos
().
x
<
-
22.0
)
{
// goalie is rejected.
return
;
}
if
(
teammate
->
posCount
()
>
3
)
{
// low confidence players are rejected.
return
;
}
if
(
teammate
->
pos
().
x
>
world
.
offsideLineX
()
+
1.0
)
{
// offside players are rejected.
return
;
}
if
(
teammate
->
pos
().
x
<
world
.
ball
().
pos
().
x
-
25.0
)
{
// too back
return
;
}
// create & verify each route
create_direct_pass
(
world
,
teammate
);
create_lead_pass
(
world
,
teammate
);
if
(
world
.
self
().
pos
().
x
>
world
.
offsideLineX
()
-
20.0
)
{
create_through_pass
(
world
,
teammate
);
}
////////////////////////////////////////////////////////////////
// evaluation
evaluate_routes
(
world
);
}
/*-------------------------------------------------------------------*/
/*!
static method
*/
void
Force_Pass
::
create_direct_pass
(
const
WorldModel
&
world
,
const
PlayerObject
*
receiver
)
{
static
const
double
MAX_DIRECT_PASS_DIST
=
0.8
*
inertia_final_distance
(
ServerParam
::
i
().
ballSpeedMax
(),
ServerParam
::
i
().
ballDecay
()
);
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"Create_direct_pass() to %d(%.1f %.1f)"
,
receiver
->
unum
(),
receiver
->
pos
().
x
,
receiver
->
pos
().
y
);
#endif
// out of pitch?
if
(
receiver
->
pos
().
absX
()
>
ServerParam
::
i
().
pitchHalfLength
()
-
3.0
||
receiver
->
pos
().
absY
()
>
ServerParam
::
i
().
pitchHalfWidth
()
-
3.0
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ out of pitch"
);
#endif
return
;
}
/////////////////////////////////////////////////////////////////
// too far
if
(
receiver
->
distFromSelf
()
>
MAX_DIRECT_PASS_DIST
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ over max distance %.2f > %.2f"
,
receiver
->
distFromSelf
(),
MAX_DIRECT_PASS_DIST
);
#endif
return
;
}
// too close
if
(
receiver
->
distFromSelf
()
<
6.0
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ too close. dist = %.2f canceled"
,
receiver
->
distFromSelf
()
);
#endif
return
;
}
/////////////////
if
(
receiver
->
pos
().
x
<
world
.
self
().
pos
().
x
+
5.0
)
{
if
(
receiver
->
angleFromSelf
().
abs
()
<
40.0
||
(
receiver
->
pos
().
x
>
world
.
ourDefenseLineX
()
+
10.0
&&
receiver
->
pos
().
x
>
0.0
)
)
{
// "DIRECT: not defender." <<;
}
else
{
// "DIRECT: back.;
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ looks back pass. DF Line=%.1f. canceled"
,
world
.
defenseLineX
()
);
#endif
return
;
}
}
// not safety area
if
(
receiver
->
pos
().
x
<
-
20.0
)
{
if
(
receiver
->
pos
().
x
>
world
.
self
().
pos
().
x
+
13.0
)
{
// safety clear??
}
else
if
(
receiver
->
pos
().
x
>
world
.
self
().
pos
().
x
+
5.0
&&
receiver
->
pos
().
absY
()
>
20.0
&&
fabs
(
receiver
->
pos
().
y
-
world
.
self
().
pos
().
y
)
<
20.0
)
{
// safety area
}
else
{
// dangerous
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ receiver is in dangerous area. canceled"
);
#endif
return
;
}
}
/////////////////////////////////////////////////////////////////
// set base target
Vector2D
base_player_pos
=
receiver
->
pos
();
if
(
receiver
->
velCount
()
<
3
)
{
Vector2D
fvel
=
receiver
->
vel
();
fvel
/=
ServerParam
::
i
().
defaultPlayerDecay
();
fvel
*=
std
::
min
(
receiver
->
velCount
()
+
1
,
2
);
base_player_pos
+=
fvel
;
}
const
Vector2D
receiver_rel
=
base_player_pos
-
world
.
ball
().
pos
();
const
double
receiver_dist
=
receiver_rel
.
r
();
const
AngleDeg
receiver_angle
=
receiver_rel
.
th
();
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ receiver. predict pos(%.2f %.2f) rel(%.2f %.2f)"
" dist=%.2f angle=%.1f"
,
base_player_pos
.
x
,
base_player_pos
.
y
,
receiver_rel
.
x
,
receiver_rel
.
y
,
receiver_dist
,
receiver_angle
.
degree
()
);
#endif
double
end_speed
=
1.5
;
double
first_speed
=
100.0
;
do
{
first_speed
=
calc_first_term_geom_series_last
(
end_speed
,
receiver_dist
,
ServerParam
::
i
().
ballDecay
()
);
//= required_first_speed( receiver_dist,
//ServerParam::i().ballDecay(),
//end_speed );
if
(
first_speed
<
ServerParam
::
i
().
ballSpeedMax
()
)
{
break
;
}
end_speed
-=
0.1
;
}
while
(
end_speed
>
0.8
);
if
(
first_speed
>
ServerParam
::
i
().
ballSpeedMax
()
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ ball first speed= %.3f. too high. canceled"
,
first_speed
);
#endif
return
;
}
// add strictly direct pass
if
(
verify_direct_pass
(
world
,
receiver
,
base_player_pos
,
receiver_dist
,
receiver_angle
,
first_speed
)
)
{
S_cached_pass_route
.
push_back
(
PassRoute
(
DIRECT
,
receiver
,
base_player_pos
,
first_speed
,
can_kick_by_one_step
(
world
,
first_speed
,
receiver_angle
)
)
);
}
// add kickable edge points
double
kickable_angle_buf
=
360.0
*
(
ServerParam
::
i
().
defaultKickableArea
()
/
(
2.0
*
M_PI
*
receiver_dist
)
);
first_speed
*=
ServerParam
::
i
().
ballDecay
();
// right side
Vector2D
target_new
=
world
.
ball
().
pos
();
AngleDeg
angle_new
=
receiver_angle
;
angle_new
+=
kickable_angle_buf
;
target_new
+=
Vector2D
::
polar2vector
(
receiver_dist
,
angle_new
);
if
(
verify_direct_pass
(
world
,
receiver
,
target_new
,
receiver_dist
,
angle_new
,
first_speed
)
)
{
S_cached_pass_route
.
push_back
(
PassRoute
(
DIRECT
,
receiver
,
target_new
,
first_speed
,
can_kick_by_one_step
(
world
,
first_speed
,
angle_new
)
)
);
}
// left side
target_new
=
world
.
ball
().
pos
();
angle_new
=
receiver_angle
;
angle_new
-=
kickable_angle_buf
;
target_new
+=
Vector2D
::
polar2vector
(
receiver_dist
,
angle_new
);
if
(
verify_direct_pass
(
world
,
receiver
,
target_new
,
receiver_dist
,
angle_new
,
first_speed
)
)
{
S_cached_pass_route
.
push_back
(
PassRoute
(
DIRECT
,
receiver
,
target_new
,
first_speed
,
can_kick_by_one_step
(
world
,
first_speed
,
angle_new
)
)
);
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"Pass Success direct unum=%d pos=(%.1f %.1f). first_speed= %.1f"
,
receiver
->
unum
(),
target_new
.
x
,
target_new
.
y
,
first_speed
);
#endif
}
else
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"Pass Failed direct unum=%d pos=(%.1f %.1f). first_speed= %.1f"
,
receiver
->
unum
(),
target_new
.
x
,
target_new
.
y
,
first_speed
);
#endif
}
}
/*-------------------------------------------------------------------*/
/*!
static method
*/
void
Force_Pass
::
create_lead_pass
(
const
WorldModel
&
world
,
const
PlayerObject
*
receiver
)
{
static
const
double
MAX_LEAD_PASS_DIST
=
0.7
*
inertia_final_distance
(
ServerParam
::
i
().
ballSpeedMax
(),
ServerParam
::
i
().
ballDecay
()
);
static
const
Rect2D
shrinked_pitch
(
Vector2D
(
-
ServerParam
::
i
().
pitchHalfLength
()
+
3.0
,
-
ServerParam
::
i
().
pitchHalfWidth
()
+
3.0
),
Size2D
(
ServerParam
::
i
().
pitchLength
()
-
6.0
,
ServerParam
::
i
().
pitchWidth
()
-
6.0
)
);
//static const double receiver_dash_speed = 0.9;
static
const
double
receiver_dash_speed
=
0.8
;
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"Create_lead_pass() to %d(%.1f %.1f)"
,
receiver
->
unum
(),
receiver
->
pos
().
x
,
receiver
->
pos
().
y
);
#endif
/////////////////////////////////////////////////////////////////
// too far
if
(
receiver
->
distFromSelf
()
>
MAX_LEAD_PASS_DIST
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ over max distance %.2f > %.2f"
,
receiver
->
distFromSelf
(),
MAX_LEAD_PASS_DIST
);
#endif
return
;
}
// too close
if
(
receiver
->
distFromSelf
()
<
2.0
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ too close %.2f"
,
receiver
->
distFromSelf
()
);
#endif
return
;
}
if
(
receiver
->
pos
().
x
<
world
.
self
().
pos
().
x
-
15.0
&&
receiver
->
pos
().
x
<
15.0
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ receiver is back cancel"
);
#endif
return
;
}
//
if
(
receiver
->
pos
().
x
<
-
10.0
&&
std
::
fabs
(
receiver
->
pos
().
y
-
world
.
self
().
pos
().
y
)
>
20.0
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ receiver is in our field. or Y diff is big"
);
#endif
return
;
}
const
Vector2D
receiver_rel
=
receiver
->
pos
()
-
world
.
ball
().
pos
();
const
double
receiver_dist
=
receiver_rel
.
r
();
const
AngleDeg
receiver_angle
=
receiver_rel
.
th
();
const
double
circum
=
2.0
*
receiver_dist
*
M_PI
;
const
double
angle_step_abs
=
std
::
max
(
5.0
,
360.0
*
(
2.0
/
circum
));
/// angle loop
double
total_add_angle_abs
;
int
count
;
for
(
total_add_angle_abs
=
angle_step_abs
,
count
=
0
;
total_add_angle_abs
<
31.0
&&
count
<
5
;
total_add_angle_abs
+=
angle_step_abs
,
++
count
)
{
/////////////////////////////////////////////////////////////
// estimate required first ball speed
const
double
dash_step
=
(
(
angle_step_abs
/
360.0
)
*
circum
)
/
receiver_dash_speed
+
2.0
;
double
end_speed
=
1.2
-
0.11
*
count
;
// Magic Number
double
first_speed
=
100.0
;
double
ball_steps_to_target
=
100.0
;
do
{
first_speed
=
calc_first_term_geom_series_last
(
end_speed
,
receiver_dist
,
ServerParam
::
i
().
ballDecay
()
);
//= required_first_speed( receiver_dist,
//ServerParam::i().ballDecay(),
//end_speed );
if
(
first_speed
<
ServerParam
::
i
().
ballSpeedMax
()
)
{
break
;
}
ball_steps_to_target
=
calc_length_geom_series
(
first_speed
,
receiver_dist
,
ServerParam
::
i
().
ballDecay
()
);
//= move_step_for_first( receiver_dist,
//first_speed,
//ServerParam::i().ballDecay() );
if
(
dash_step
<
ball_steps_to_target
)
{
break
;
}
end_speed
-=
0.1
;
}
while
(
end_speed
>
0.5
);
if
(
first_speed
>
ServerParam
::
i
().
ballSpeedMax
()
)
{
continue
;
}
/////////////////////////////////////////////////////////////
// angle plus minus loop
for
(
int
i
=
0
;
i
<
2
;
i
++
)
{
AngleDeg
target_angle
=
receiver_angle
;
if
(
i
==
0
)
{
target_angle
-=
total_add_angle_abs
;
}
else
{
target_angle
+=
total_add_angle_abs
;
}
// check dir confidence
int
max_count
=
100
,
ave_count
=
100
;
world
.
dirRangeCount
(
target_angle
,
20.0
,
&
max_count
,
NULL
,
&
ave_count
);
if
(
max_count
>
9
||
ave_count
>
3
)
{
continue
;
}
const
Vector2D
target_point
=
world
.
ball
().
pos
()
+
Vector2D
::
polar2vector
(
receiver_dist
,
target_angle
);
/////////////////////////////////////////////////////////////////
// ignore back pass
if
(
target_point
.
x
<
0.0
&&
target_point
.
x
<
world
.
self
().
pos
().
x
)
{
continue
;
}
if
(
target_point
.
x
<
0.0
&&
target_point
.
x
<
receiver
->
pos
().
x
-
3.0
)
{
continue
;
}
if
(
target_point
.
x
<
receiver
->
pos
().
x
-
6.0
)
{
continue
;
}
// out of pitch
if
(
!
shrinked_pitch
.
contains
(
target_point
)
)
{
continue
;
}
// not safety area
if
(
target_point
.
x
<
-
10.0
)
{
if
(
target_point
.
x
<
world
.
ourDefenseLineX
()
+
10.0
)
{
continue
;
}
else
if
(
target_point
.
x
>
world
.
self
().
pos
().
x
+
20.0
&&
fabs
(
target_point
.
y
-
world
.
self
().
pos
().
y
)
<
20.0
)
{
// safety clear ??
}
else
if
(
target_point
.
x
>
world
.
self
().
pos
().
x
+
5.0
// forward than me
&&
std
::
fabs
(
target_point
.
y
-
world
.
self
().
pos
().
y
)
<
20.0
)
// out side of me
{
// safety area
}
else
if
(
target_point
.
x
>
world
.
ourDefenseLineX
()
+
20.0
)
{
// safety area
}
else
{
// dangerous
continue
;
}
}
/////////////////////////////////////////////////////////////////
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ lead pass to (%.1f %.1f). first_speed= %.3f. angle = %.1f"
,
target_point
.
x
,
target_point
.
y
,
first_speed
,
target_angle
.
degree
()
);
#endif
// add lead pass route
// this methid is same as through pass verification method.
if
(
verify_through_pass
(
world
,
receiver
,
receiver
->
pos
(),
target_point
,
receiver_dist
,
target_angle
,
first_speed
,
ball_steps_to_target
)
)
{
S_cached_pass_route
.
push_back
(
PassRoute
(
LEAD
,
receiver
,
target_point
,
first_speed
,
can_kick_by_one_step
(
world
,
first_speed
,
target_angle
)
)
);
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"Pass Success lead unum=%d pos=(%.1f %.1f) angle=%.1f first_speed=%.1f"
,
receiver
->
unum
(),
target_point
.
x
,
target_point
.
y
,
target_angle
.
degree
(),
first_speed
);
#endif
}
#ifdef DEBUG
else
{
dlog
.
addText
(
Logger
::
PASS
,
"Pass Failed lead unum=%d pos=(%.1f %.1f) angle=%.1f first_speed=%.1f"
,
receiver
->
unum
(),
target_point
.
x
,
target_point
.
y
,
target_angle
.
degree
(),
first_speed
);
}
#endif
}
}
}
/*-------------------------------------------------------------------*/
/*!
static method
*/
void
Force_Pass
::
create_through_pass
(
const
WorldModel
&
world
,
const
PlayerObject
*
receiver
)
{
static
const
double
MAX_THROUGH_PASS_DIST
=
0.9
*
inertia_final_distance
(
ServerParam
::
i
().
ballSpeedMax
(),
ServerParam
::
i
().
ballDecay
()
);
////////////////////////////////////////////////////////////////
static
const
Rect2D
shrinked_pitch
(
Vector2D
(
-
ServerParam
::
i
().
pitchHalfLength
()
+
3.0
,
-
ServerParam
::
i
().
pitchHalfWidth
()
+
3.0
),
Size2D
(
ServerParam
::
i
().
pitchLength
()
-
6.0
,
ServerParam
::
i
().
pitchWidth
()
-
6.0
)
);
static
const
double
receiver_dash_speed
=
1.0
;
//static const double receiver_dash_speed = 0.85;
static
const
double
S_min_dash
=
5.0
;
static
const
double
S_max_dash
=
25.0
;
static
const
double
S_dash_range
=
S_max_dash
-
S_min_dash
;
static
const
double
S_dash_inc
=
4.0
;
static
const
int
S_dash_loop
=
static_cast
<
int
>
(
std
::
ceil
(
S_dash_range
/
S_dash_inc
)
)
+
1
;
static
const
AngleDeg
S_min_angle
=
-
20.0
;
static
const
AngleDeg
S_max_angle
=
20.0
;
static
const
double
S_angle_range
=
(
S_min_angle
-
S_max_angle
).
abs
();
static
const
double
S_angle_inc
=
10.0
;
static
const
int
S_angle_loop
=
static_cast
<
int
>
(
std
::
ceil
(
S_angle_range
/
S_angle_inc
)
)
+
1
;
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"Create_through_pass() to %d(%.1f %.1f)"
,
receiver
->
unum
(),
receiver
->
pos
().
x
,
receiver
->
pos
().
y
);
#endif
/////////////////////////////////////////////////////////////////
// check receiver position
if
(
receiver
->
pos
().
x
>
world
.
offsideLineX
()
-
0.5
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ receiver is offside"
);
#endif
return
;
}
if
(
receiver
->
pos
().
x
<
world
.
self
().
pos
().
x
-
10.0
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ receiver is back"
);
#endif
return
;
}
if
(
std
::
fabs
(
receiver
->
pos
().
y
-
world
.
self
().
pos
().
y
)
>
35.0
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ receiver Y diff is big"
);
#endif
return
;
}
if
(
world
.
ourDefenseLineX
()
<
0.0
&&
receiver
->
pos
().
x
<
world
.
ourDefenseLineX
()
-
15.0
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ receiver is near to defense line"
);
#endif
return
;
}
if
(
world
.
offsideLineX
()
<
30.0
&&
receiver
->
pos
().
x
<
world
.
offsideLineX
()
-
15.0
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ receiver is far from offside line"
);
#endif
return
;
}
if
(
receiver
->
angleFromSelf
().
abs
()
>
135.0
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ receiver angle is too back"
);
#endif
return
;
}
// angle loop
AngleDeg
dash_angle
=
S_min_angle
;
for
(
int
i
=
0
;
i
<
S_angle_loop
;
++
i
,
dash_angle
+=
S_angle_inc
)
{
const
Vector2D
base_dash
=
Vector2D
::
polar2vector
(
1.0
,
dash_angle
);
// dash dist loop
double
dash_dist
=
S_min_dash
;
for
(
int
j
=
0
;
j
<
S_dash_loop
;
++
j
,
dash_dist
+=
S_dash_inc
)
{
Vector2D
target_point
=
base_dash
;
target_point
*=
dash_dist
;
target_point
+=
receiver
->
pos
();
if
(
!
shrinked_pitch
.
contains
(
target_point
)
)
{
// out of pitch
continue
;
}
if
(
target_point
.
x
<
world
.
self
().
pos
().
x
+
3.0
)
{
continue
;
}
const
Vector2D
target_rel
=
target_point
-
world
.
ball
().
pos
();
const
double
target_dist
=
target_rel
.
r
();
const
AngleDeg
target_angle
=
target_rel
.
th
();
// check dir confidence
int
max_count
=
100
,
ave_count
=
100
;
world
.
dirRangeCount
(
target_angle
,
20.0
,
&
max_count
,
NULL
,
&
ave_count
);
if
(
max_count
>
9
||
ave_count
>
3
)
{
continue
;
}
if
(
target_dist
>
MAX_THROUGH_PASS_DIST
)
// dist range over
{
continue
;
}
if
(
target_dist
<
dash_dist
)
// I am closer than receiver
{
continue
;
}
const
double
dash_step
=
dash_dist
/
receiver_dash_speed
;
// + 5.0;//+2.0
double
end_speed
=
0.81
;
//0.65
double
first_speed
=
100.0
;
double
ball_steps_to_target
=
100.0
;
do
{
first_speed
=
calc_first_term_geom_series_last
(
end_speed
,
target_dist
,
ServerParam
::
i
().
ballDecay
()
);
//= required_first_speed(target_dist,
//ServerParam::i().ballDecay(),
//end_speed);
if
(
first_speed
>
ServerParam
::
i
().
ballSpeedMax
()
)
{
end_speed
-=
0.1
;
continue
;
}
ball_steps_to_target
=
calc_length_geom_series
(
first_speed
,
target_dist
,
ServerParam
::
i
().
ballDecay
()
);
//= move_step_for_first( target_dist,
//first_speed,
//ServerParam::i().ballDecay() );
//if ( ball_steps_to_target < dash_step )
if
(
dash_step
<
ball_steps_to_target
)
{
break
;
}
end_speed
-=
0.1
;
}
while
(
end_speed
>
0.5
);
if
(
first_speed
>
ServerParam
::
i
().
ballSpeedMax
()
||
dash_step
>
ball_steps_to_target
)
{
continue
;
}
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ throug pass to (%.1f %.1f). first_speed= %.3f"
,
target_point
.
x
,
target_point
.
y
,
first_speed
);
#endif
if
(
verify_through_pass
(
world
,
receiver
,
receiver
->
pos
(),
target_point
,
target_dist
,
target_angle
,
first_speed
,
ball_steps_to_target
)
)
{
S_cached_pass_route
.
push_back
(
PassRoute
(
THROUGH
,
receiver
,
target_point
,
first_speed
,
can_kick_by_one_step
(
world
,
first_speed
,
target_angle
)
)
);
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"Pass Success through pass unum=%d pos=(%.1f %.1f) angle=%.1f first_speed=%.1f dash_step=%.1f ball_step=%.1f"
,
receiver
->
unum
(),
target_point
.
x
,
target_point
.
y
,
target_angle
.
degree
(),
first_speed
,
dash_step
,
ball_steps_to_target
);
#endif
}
#ifdef DEBUG
else
{
dlog
.
addText
(
Logger
::
PASS
,
"Pass Failed through unum=%d pos=(%.1f %.1f) angle=%.1f first_speed=%.1f dash_step-%.1f ball_step=%.1f"
,
receiver
->
unum
(),
target_point
.
x
,
target_point
.
y
,
target_angle
.
degree
(),
first_speed
,
dash_step
,
ball_steps_to_target
);
}
#endif
}
}
}
/*-------------------------------------------------------------------*/
/*!
static method
*/
void
Force_Pass
::
create_forced_pass
(
const
WorldModel
&
world
,
const
PlayerObject
*
receiver
)
{
// set base target
Vector2D
base_player_pos
=
receiver
->
pos
();
if
(
receiver
->
velCount
()
<
3
)
{
Vector2D
fvel
=
receiver
->
vel
();
fvel
/=
ServerParam
::
i
().
defaultPlayerDecay
();
fvel
*=
std
::
min
(
receiver
->
velCount
()
+
1
,
2
);
base_player_pos
+=
fvel
;
}
const
Vector2D
receiver_rel
=
base_player_pos
-
world
.
ball
().
pos
();
const
double
receiver_dist
=
receiver_rel
.
r
();
const
AngleDeg
receiver_angle
=
receiver_rel
.
th
();
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ receiver. predict pos(%.2f %.2f) rel(%.2f %.2f)"
" dist=%.2f angle=%.1f"
,
base_player_pos
.
x
,
base_player_pos
.
y
,
receiver_rel
.
x
,
receiver_rel
.
y
,
receiver_dist
,
receiver_angle
.
degree
()
);
#endif
double
end_speed
=
1.5
;
double
first_speed
=
100.0
;
do
{
first_speed
=
calc_first_term_geom_series_last
(
end_speed
,
receiver_dist
,
ServerParam
::
i
().
ballDecay
()
);
//= required_first_speed( receiver_dist,
//ServerParam::i().ballDecay(),
//end_speed );
if
(
first_speed
<
ServerParam
::
i
().
ballSpeedMax
()
)
{
break
;
}
end_speed
-=
0.1
;
}
while
(
end_speed
>
0.8
);
// add strictly direct pass
S_cached_pass_route
.
push_back
(
PassRoute
(
DIRECT
,
receiver
,
base_player_pos
,
first_speed
,
can_kick_by_one_step
(
world
,
first_speed
,
receiver_angle
)
)
);
}
/*-------------------------------------------------------------------*/
/*!
static method
*/
bool
Force_Pass
::
verify_direct_pass
(
const
WorldModel
&
world
,
const
PlayerObject
*
/*receiver*/
,
const
Vector2D
&
target_point
,
const
double
&
target_dist
,
const
AngleDeg
&
target_angle
,
const
double
&
first_speed
)
{
static
const
double
player_dash_speed
=
1.0
;
const
Vector2D
first_vel
=
Vector2D
::
polar2vector
(
first_speed
,
target_angle
);
const
AngleDeg
minus_target_angle
=
-
target_angle
;
const
double
next_speed
=
first_speed
*
ServerParam
::
i
().
ballDecay
();
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"____ verify direct pass to(%.1f %.1f). first_speed=%.3f. angle=%.1f"
,
target_point
.
x
,
target_point
.
y
,
first_speed
,
target_angle
.
degree
()
);
#endif
const
PlayerPtrCont
::
const_iterator
o_end
=
world
.
opponentsFromSelf
().
end
();
for
(
PlayerPtrCont
::
const_iterator
it
=
world
.
opponentsFromSelf
().
begin
();
it
!=
o_end
;
++
it
)
{
if
(
(
*
it
)
->
posCount
()
>
10
)
continue
;
if
(
(
*
it
)
->
isGhost
()
&&
(
*
it
)
->
posCount
()
>=
4
)
continue
;
const
double
virtual_dash
=
player_dash_speed
*
0.8
*
std
::
min
(
5
,
(
*
it
)
->
posCount
()
);
// if ( (*it)->pos().dist( target_point ) - virtual_dash > target_dist + 2.0 )
// {
// #ifdef DEBUG
// dlog.addText( Logger::PASS,
// "______ opp%d(%.1f %.1f) is too far. not calculated.",
// (*it)->unum(),
// (*it)->pos().x, (*it)->pos().y );
// #endif
// continue;
// }
if
(
(
(
*
it
)
->
angleFromSelf
()
-
target_angle
).
abs
()
>
100.0
)
{
// #ifdef DEBUG
// dlog.addText( Logger::PASS,
// "______ opp%d(%.1f %.1f) is back of target dir. not calculated.",
// (*it)->unum(),
// (*it)->pos().x, (*it)->pos().y );
//#endif
continue
;
}
if
(
(
*
it
)
->
pos
().
dist2
(
target_point
)
<
3.0
*
3.0
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"______ opp%d(%.1f %.1f) is already on target point(%.1f %.1f)."
,
(
*
it
)
->
unum
(),
(
*
it
)
->
pos
().
x
,
(
*
it
)
->
pos
().
y
,
target_point
.
x
,
target_point
.
y
);
#endif
return
false
;
}
Vector2D
ball_to_opp
=
(
*
it
)
->
pos
();
ball_to_opp
-=
world
.
ball
().
pos
();
ball_to_opp
-=
first_vel
;
ball_to_opp
.
rotate
(
minus_target_angle
);
if
(
0.0
<
ball_to_opp
.
x
&&
ball_to_opp
.
x
<
target_dist
)
{
double
opp2line_dist
=
ball_to_opp
.
absY
();
opp2line_dist
-=
virtual_dash
;
opp2line_dist
-=
ServerParam
::
i
().
defaultKickableArea
();
opp2line_dist
-=
0.1
;
if
(
opp2line_dist
<
0.0
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"______ opp%d(%.1f %.1f) can reach pass line. rejected. vdash=%.1f"
,
(
*
it
)
->
unum
(),
(
*
it
)
->
pos
().
x
,
(
*
it
)
->
pos
().
y
,
virtual_dash
);
#endif
return
false
;
}
const
double
ball_steps_to_project
=
calc_length_geom_series
(
next_speed
,
ball_to_opp
.
x
,
ServerParam
::
i
().
ballDecay
()
);
//= move_step_for_first(ball_to_opp.x,
//next_speed,
//ServerParam::i().ballDecay());
if
(
ball_steps_to_project
<
0.0
||
opp2line_dist
/
player_dash_speed
<
ball_steps_to_project
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"______ opp%d(%.1f %.1f) can reach pass line."
" ball reach step to project= %.1f"
,
(
*
it
)
->
unum
(),
(
*
it
)
->
pos
().
x
,
(
*
it
)
->
pos
().
y
,
ball_steps_to_project
);
#endif
return
false
;
}
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"______ opp%d(%.1f %.1f) cannot intercept."
,
(
*
it
)
->
unum
(),
(
*
it
)
->
pos
().
x
,
(
*
it
)
->
pos
().
y
);
#endif
}
}
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ Success!"
);
#endif
return
true
;
}
/*-------------------------------------------------------------------*/
/*!
static method
*/
bool
Force_Pass
::
verify_through_pass
(
const
WorldModel
&
world
,
const
PlayerObject
*
/*receiver*/
,
const
Vector2D
&
receiver_pos
,
const
Vector2D
&
target_point
,
const
double
&
target_dist
,
const
AngleDeg
&
target_angle
,
const
double
&
first_speed
,
const
double
&
/*reach_step*/
)
{
static
const
double
player_dash_speed
=
1.0
;
const
Vector2D
first_vel
=
Vector2D
::
polar2vector
(
first_speed
,
target_angle
);
const
AngleDeg
minus_target_angle
=
-
target_angle
;
const
double
next_speed
=
first_speed
*
ServerParam
::
i
().
ballDecay
();
const
double
receiver_to_target
=
receiver_pos
.
dist
(
target_point
);
bool
very_aggressive
=
false
;
if
(
target_point
.
x
>
28.0
&&
target_point
.
x
>
world
.
ball
().
pos
().
x
+
20.0
)
{
very_aggressive
=
true
;
}
else
if
(
target_point
.
x
>
world
.
offsideLineX
()
+
15.0
&&
target_point
.
x
>
world
.
ball
().
pos
().
x
+
15.0
)
{
very_aggressive
=
true
;
}
else
if
(
target_point
.
x
>
38.0
&&
target_point
.
x
>
world
.
offsideLineX
()
&&
target_point
.
absY
()
<
14.0
)
{
very_aggressive
=
true
;
}
const
PlayerPtrCont
::
const_iterator
o_end
=
world
.
opponentsFromSelf
().
end
();
for
(
PlayerPtrCont
::
const_iterator
it
=
world
.
opponentsFromSelf
().
begin
();
it
!=
o_end
;
++
it
)
{
if
(
(
*
it
)
->
posCount
()
>
10
)
continue
;
if
(
(
*
it
)
->
goalie
()
)
{
if
(
target_point
.
absY
()
>
ServerParam
::
i
().
penaltyAreaWidth
()
-
3.0
||
target_point
.
x
<
ServerParam
::
i
().
theirPenaltyAreaLineX
()
+
2.0
)
{
continue
;
}
}
const
double
virtual_dash
=
player_dash_speed
*
std
::
min
(
2
,
(
*
it
)
->
posCount
()
);
const
double
opp_to_target
=
(
*
it
)
->
pos
().
dist
(
target_point
);
double
dist_rate
=
(
very_aggressive
?
0.8
:
1.0
);
double
dist_buf
=
(
very_aggressive
?
0.5
:
2.0
);
if
(
opp_to_target
-
virtual_dash
<
receiver_to_target
*
dist_rate
+
dist_buf
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"______ opp%d(%.1f %.1f) is closer than receiver."
,
(
*
it
)
->
unum
(),
(
*
it
)
->
pos
().
x
,
(
*
it
)
->
pos
().
y
);
#endif
return
false
;
}
Vector2D
ball_to_opp
=
(
*
it
)
->
pos
();
ball_to_opp
-=
world
.
ball
().
pos
();
ball_to_opp
-=
first_vel
;
ball_to_opp
.
rotate
(
minus_target_angle
);
if
(
0.0
<
ball_to_opp
.
x
&&
ball_to_opp
.
x
<
target_dist
)
{
double
opp2line_dist
=
ball_to_opp
.
absY
();
opp2line_dist
-=
virtual_dash
;
opp2line_dist
-=
ServerParam
::
i
().
defaultKickableArea
();
opp2line_dist
-=
0.1
;
if
(
opp2line_dist
<
0.0
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"______ opp%d(%.1f %.1f) is already on pass line."
,
(
*
it
)
->
unum
(),
(
*
it
)
->
pos
().
x
,
(
*
it
)
->
pos
().
y
);
#endif
return
false
;
}
const
double
ball_steps_to_project
=
calc_length_geom_series
(
next_speed
,
ball_to_opp
.
x
,
ServerParam
::
i
().
ballDecay
()
);
//= move_step_for_first( ball_to_opp.x,
//next_speed,
//ServerParam::i().ballDecay() );
if
(
ball_steps_to_project
<
0.0
||
opp2line_dist
/
player_dash_speed
<
ball_steps_to_project
)
{
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"______ opp%d(%.1f %.1f) can reach pass line."
" ball reach step to project= %.1f"
,
(
*
it
)
->
unum
(),
(
*
it
)
->
pos
().
x
,
(
*
it
)
->
pos
().
y
,
ball_steps_to_project
);
#endif
return
false
;
}
}
}
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"__ Success!"
);
#endif
return
true
;
}
/*-------------------------------------------------------------------*/
/*!
static method
*/
void
Force_Pass
::
evaluate_routes
(
const
WorldModel
&
world
)
{
const
AngleDeg
min_angle
=
-
45.0
;
const
AngleDeg
max_angle
=
45.0
;
const
std
::
vector
<
PassRoute
>::
iterator
it_end
=
S_cached_pass_route
.
end
();
for
(
std
::
vector
<
PassRoute
>::
iterator
it
=
S_cached_pass_route
.
begin
();
it
!=
it_end
;
++
it
)
{
//-----------------------------------------------------------
double
opp_dist_rate
=
1.0
;
{
double
opp_dist
=
100.0
;
world
.
getOpponentNearestTo
(
it
->
receive_point_
,
20
,
&
opp_dist
);
opp_dist_rate
=
std
::
pow
(
0.99
,
std
::
max
(
0.0
,
30.0
-
opp_dist
)
);
}
//-----------------------------------------------------------
double
x_diff_rate
=
1.0
;
{
double
x_diff
=
it
->
receive_point_
.
x
-
world
.
self
().
pos
().
x
;
x_diff_rate
=
std
::
pow
(
0.98
,
std
::
max
(
0.0
,
30.0
-
x_diff
)
);
}
//-----------------------------------------------------------
double
receiver_move_rate
=
1.0
;
//= std::pow( 0.995,
//it->receiver_->pos().dist( it->receive_point_ ) );
//-----------------------------------------------------------
double
pos_conf_rate
=
std
::
pow
(
0.98
,
it
->
receiver_
->
posCount
()
);
//-----------------------------------------------------------
double
dir_conf_rate
=
1.0
;
{
AngleDeg
pass_angle
=
(
it
->
receive_point_
-
world
.
self
().
pos
()
).
th
();
int
max_count
=
0
;
world
.
dirRangeCount
(
pass_angle
,
20.0
,
&
max_count
,
NULL
,
NULL
);
dir_conf_rate
=
std
::
pow
(
0.95
,
max_count
);
}
//-----------------------------------------------------------
double
offense_rate
=
std
::
pow
(
0.98
,
std
::
max
(
5.0
,
std
::
fabs
(
it
->
receive_point_
.
y
-
world
.
ball
().
pos
().
y
)
)
);
//-----------------------------------------------------------
const
Sector2D
sector
(
it
->
receive_point_
,
0.0
,
10.0
,
min_angle
,
max_angle
);
// opponent check with goalie
double
front_space_rate
=
1.0
;
if
(
world
.
existOpponentIn
(
sector
,
10
,
true
)
)
{
front_space_rate
=
0.95
;
}
//-----------------------------------------------------------
it
->
score_
=
1000.0
;
it
->
score_
*=
opp_dist_rate
;
it
->
score_
*=
x_diff_rate
;
it
->
score_
*=
receiver_move_rate
;
it
->
score_
*=
pos_conf_rate
;
it
->
score_
*=
dir_conf_rate
;
it
->
score_
*=
offense_rate
;
it
->
score_
*=
front_space_rate
;
if
(
it
->
one_step_kick_
)
{
it
->
score_
*=
1.2
;
}
#ifdef DEBUG
dlog
.
addText
(
Logger
::
PASS
,
"PASS Score %6.2f -- to%d(%.1f %.1f) recv_pos(%.1f %.1f) type %d "
" speed=%.2f"
,
it
->
score_
,
it
->
receiver_
->
unum
(),
it
->
receiver_
->
pos
().
x
,
it
->
receiver_
->
pos
().
y
,
it
->
receive_point_
.
x
,
it
->
receive_point_
.
y
,
it
->
type_
,
it
->
first_speed_
);
dlog
.
addText
(
Logger
::
PASS
,
"____ opp_dist=%.2f x_diff=%.2f pos_conf=%.2f"
" dir_conf=%.2f space=%.1f %s"
,
opp_dist_rate
,
x_diff_rate
,
pos_conf_rate
,
dir_conf_rate
,
front_space_rate
,
(
it
->
one_step_kick_
?
"one_step"
:
""
)
);
#endif
}
}
/*-------------------------------------------------------------------*/
/*!
static method
*/
bool
Force_Pass
::
can_kick_by_one_step
(
const
WorldModel
&
world
,
const
double
&
first_speed
,
const
AngleDeg
&
target_angle
)
{
Vector2D
required_accel
=
Vector2D
::
polar2vector
(
first_speed
,
target_angle
);
required_accel
-=
world
.
ball
().
vel
();
return
(
world
.
self
().
kickRate
()
*
ServerParam
::
i
().
maxPower
()
>
required_accel
.
r
()
);
}
src/bhv_force_pass.h
0 → 100644
View file @
f076b7d9
#ifndef BHV_FORCE_PASS_H
#define BHV_FORCE_PASS_H
#include <rcsc/player/player_object.h>
#include <rcsc/player/soccer_action.h>
#include <rcsc/player/world_model.h>
#include <rcsc/geom/vector_2d.h>
#include <rcsc/geom/angle_deg.h>
#include <functional>
#include <vector>
/* class WorldModel; */
/* class PlayerObject; */
/*!
\class Force_Pass
\brief advanced pass planning & behavior.
*/
class
Force_Pass
:
public
rcsc
::
BodyAction
{
public:
/*!
\enum PassType
\brief pass type id
*/
enum
PassType
{
DIRECT
=
1
,
LEAD
=
2
,
THROUGH
=
3
};
/*!
\struct PassRoute
\brief pass route information object, that contains type,
receiver info, receive point and ball first speed.
*/
struct
PassRoute
{
PassType
type_
;
//!< pass type id
const
rcsc
::
PlayerObject
*
receiver_
;
//!< pointer to the receiver player
rcsc
::
Vector2D
receive_point_
;
//!< estimated receive point
double
first_speed_
;
//!< ball first speed
bool
one_step_kick_
;
//!< true if ball reaches first speed only by one kick.
double
score_
;
//!< evaluated value of this pass
/*!
\brief construct with all member variables
\param type pass type id
\param receiver pointer to the receiver player
\param point pass receive point
\param speed ball first speed
\param one_step_kick true if ball reaches first speed only by one kick.
*/
PassRoute
(
PassType
type
,
const
rcsc
::
PlayerObject
*
receiver
,
const
rcsc
::
Vector2D
&
point
,
const
double
&
speed
,
const
bool
one_step_kick
)
:
type_
(
type
)
,
receiver_
(
receiver
)
,
receive_point_
(
point
)
,
first_speed_
(
speed
)
,
one_step_kick_
(
one_step_kick
)
,
score_
(
0.0
)
{
}
};
/*!
\class PassRouteScoreComp
\brief function object to evaluate the pass
*/
class
PassRouteScoreComp
:
public
std
::
binary_function
<
PassRoute
,
PassRoute
,
bool
>
{
public:
/*!
\brief compare operator
\param lhs left hand side argument
\param rhs right hand side argument
\return compared result
*/
result_type
operator
()(
const
first_argument_type
&
lhs
,
const
second_argument_type
&
rhs
)
const
{
return
lhs
.
score_
<
rhs
.
score_
;
}
};
private:
//! cached calculated pass data
static
std
::
vector
<
PassRoute
>
S_cached_pass_route
;
public:
/*!
\brief accessible from global.
*/
Force_Pass
()
{
}
/*!
\brief execute action
\param agent pointer to the agent itself
\return true if action is performed
*/
bool
execute
(
rcsc
::
PlayerAgent
*
agent
);
/*!
\brief calculate best pass route
\param world consr rerefence to the WorldModel
\param target_point receive target point is stored to this
\param first_speed ball first speed is stored to this
\param receiver receiver number
\return true if pass route is found.
*/
static
bool
get_best_pass
(
const
rcsc
::
WorldModel
&
world
,
rcsc
::
Vector2D
*
target_point
,
double
*
first_speed
,
int
*
receiver
);
static
bool
get_pass_to_player
(
const
rcsc
::
WorldModel
&
world
,
int
receiver
);
private:
static
void
create_routes
(
const
rcsc
::
WorldModel
&
world
);
static
void
create_routes_to_player
(
const
rcsc
::
WorldModel
&
world
,
const
rcsc
::
PlayerObject
*
teammate
);
static
void
create_direct_pass
(
const
rcsc
::
WorldModel
&
world
,
const
rcsc
::
PlayerObject
*
teammates
);
static
void
create_lead_pass
(
const
rcsc
::
WorldModel
&
world
,
const
rcsc
::
PlayerObject
*
teammates
);
static
void
create_through_pass
(
const
rcsc
::
WorldModel
&
world
,
const
rcsc
::
PlayerObject
*
teammates
);
static
void
create_forced_pass
(
const
rcsc
::
WorldModel
&
world
,
const
rcsc
::
PlayerObject
*
teammates
);
static
bool
verify_direct_pass
(
const
rcsc
::
WorldModel
&
world
,
const
rcsc
::
PlayerObject
*
receiver
,
const
rcsc
::
Vector2D
&
target_point
,
const
double
&
target_dist
,
const
rcsc
::
AngleDeg
&
target_angle
,
const
double
&
first_speed
);
static
bool
verify_through_pass
(
const
rcsc
::
WorldModel
&
world
,
const
rcsc
::
PlayerObject
*
receiver
,
const
rcsc
::
Vector2D
&
receiver_pos
,
const
rcsc
::
Vector2D
&
target_point
,
const
double
&
target_dist
,
const
rcsc
::
AngleDeg
&
target_angle
,
const
double
&
first_speed
,
const
double
&
reach_step
);
static
void
evaluate_routes
(
const
rcsc
::
WorldModel
&
world
);
static
bool
can_kick_by_one_step
(
const
rcsc
::
WorldModel
&
world
,
const
double
&
first_speed
,
const
rcsc
::
AngleDeg
&
target_angle
);
};
#endif
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment