Commit b146090a authored by Matthew Hausknecht's avatar Matthew Hausknecht

Major overhaul - agents now connect directly to server.

parent 45572095
...@@ -85,7 +85,7 @@ set(PLAYER_CPP bhv_basic_move.cpp bhv_basic_offensive_kick.cpp ...@@ -85,7 +85,7 @@ set(PLAYER_CPP bhv_basic_move.cpp bhv_basic_offensive_kick.cpp
role_side_back.cpp role_side_forward.cpp role_side_half.cpp role_side_back.cpp role_side_forward.cpp role_side_half.cpp
role_keepaway_keeper.cpp role_keepaway_taker.cpp role_keepaway_keeper.cpp role_keepaway_taker.cpp
sample_communication.cpp keepaway_communication.cpp sample_communication.cpp keepaway_communication.cpp
sample_field_evaluator.cpp sample_player.cpp strategy.cpp) sample_field_evaluator.cpp sample_player.cpp strategy.cpp agent.cpp)
foreach(src ${PLAYER_CPP}) foreach(src ${PLAYER_CPP})
list(APPEND PLAYER_SOURCES ${SOURCE_DIR}/${src}) list(APPEND PLAYER_SOURCES ${SOURCE_DIR}/${src})
...@@ -95,7 +95,7 @@ file(GLOB CHAIN_ACTION_SOURCES ${SOURCE_DIR}/chain_action/*.cpp) ...@@ -95,7 +95,7 @@ file(GLOB CHAIN_ACTION_SOURCES ${SOURCE_DIR}/chain_action/*.cpp)
list(APPEND LINK_LIBS rcsc_agent rcsc_geom rcsc_param rcsc_ann list(APPEND LINK_LIBS rcsc_agent rcsc_geom rcsc_param rcsc_ann
rcsc_net rcsc_gz rcsc_time rcsc_rcg) rcsc_net rcsc_gz rcsc_time rcsc_rcg)
add_library(player_chain_action STATIC ${PLAYER_SOURCES} ${CHAIN_ACTION_SOURCES}) add_library(player_chain_action SHARED ${PLAYER_SOURCES} ${CHAIN_ACTION_SOURCES})
add_executable(sample_coach ${SOURCE_DIR}/main_coach.cpp ${SOURCE_DIR}/sample_coach.cpp) add_executable(sample_coach ${SOURCE_DIR}/main_coach.cpp ${SOURCE_DIR}/sample_coach.cpp)
add_executable(sample_player ${SOURCE_DIR}/HFO.cpp ${SOURCE_DIR}/main_player.cpp ${SOURCE_DIR}/sample_player.cpp ${SOURCE_DIR}/agent.cpp) add_executable(sample_player ${SOURCE_DIR}/HFO.cpp ${SOURCE_DIR}/main_player.cpp ${SOURCE_DIR}/sample_player.cpp ${SOURCE_DIR}/agent.cpp)
add_executable(sample_trainer ${SOURCE_DIR}/main_trainer.cpp ${SOURCE_DIR}/sample_trainer.cpp) add_executable(sample_trainer ${SOURCE_DIR}/main_trainer.cpp ${SOURCE_DIR}/sample_trainer.cpp)
...@@ -110,18 +110,25 @@ add_library(hfo-lib SHARED ${SOURCE_DIR}/HFO.hpp ${SOURCE_DIR}/HFO.cpp) ...@@ -110,18 +110,25 @@ add_library(hfo-lib SHARED ${SOURCE_DIR}/HFO.hpp ${SOURCE_DIR}/HFO.cpp)
set_target_properties(hfo-lib PROPERTIES OUTPUT_NAME hfo) set_target_properties(hfo-lib PROPERTIES OUTPUT_NAME hfo)
set_target_properties(hfo-lib PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib) set_target_properties(hfo-lib PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib)
add_library(hfo-c-lib SHARED ${CMAKE_CURRENT_SOURCE_DIR}/hfo/hfo_c_wrapper.cpp ${SOURCE_DIR}/HFO.cpp)
set_target_properties(hfo-c-lib PROPERTIES OUTPUT_NAME hfo_c)
set_target_properties(hfo-c-lib PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/hfo)
add_dependencies(player_chain_action librcsc) add_dependencies(player_chain_action librcsc)
add_dependencies(sample_coach librcsc) add_dependencies(sample_coach librcsc)
add_dependencies(sample_player librcsc) add_dependencies(sample_player librcsc)
add_dependencies(sample_trainer librcsc) add_dependencies(sample_trainer librcsc)
add_dependencies(agent librcsc) add_dependencies(agent librcsc)
add_dependencies(hfo-lib librcsc) add_dependencies(hfo-lib player_chain_action)
add_dependencies(hfo-c-lib player_chain_action)
target_link_libraries(player_chain_action ${LINK_LIBS}) target_link_libraries(player_chain_action ${LINK_LIBS})
target_link_libraries(sample_coach ${LINK_LIBS}) target_link_libraries(sample_coach ${LINK_LIBS})
target_link_libraries(sample_player ${LINK_LIBS} player_chain_action) target_link_libraries(sample_player ${LINK_LIBS} player_chain_action)
target_link_libraries(sample_trainer ${LINK_LIBS}) target_link_libraries(sample_trainer ${LINK_LIBS})
target_link_libraries(agent ${LINK_LIBS} player_chain_action) target_link_libraries(agent ${LINK_LIBS} player_chain_action)
target_link_libraries(hfo-lib ${LINK_LIBS} player_chain_action)
target_link_libraries(hfo-c-lib ${LINK_LIBS} player_chain_action)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib) link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib)
add_executable(hfo_example_agent ${CMAKE_CURRENT_SOURCE_DIR}/example/hfo_example_agent.cpp) add_executable(hfo_example_agent ${CMAKE_CURRENT_SOURCE_DIR}/example/hfo_example_agent.cpp)
......
...@@ -35,9 +35,9 @@ def main(args): ...@@ -35,9 +35,9 @@ def main(args):
os.makedirs(args.logDir) os.makedirs(args.logDir)
num_agents = args.offenseAgents + args.defenseAgents num_agents = args.offenseAgents + args.defenseAgents
binary_dir = os.path.dirname(os.path.realpath(__file__)) binary_dir = os.path.dirname(os.path.realpath(__file__))
server_port = args.port + num_agents server_port = args.port
coach_port = args.port + num_agents + 1 coach_port = args.port + 1
olcoach_port = args.port + num_agents + 2 olcoach_port = args.port + 2
serverCommand = os.path.join(binary_dir, SERVER_BIN) serverCommand = os.path.join(binary_dir, SERVER_BIN)
serverOptions = ' server::port=%i server::coach_port=%i ' \ serverOptions = ' server::port=%i server::coach_port=%i ' \
'server::olcoach_port=%i server::coach=1 ' \ 'server::olcoach_port=%i server::coach=1 ' \
......
...@@ -47,7 +47,7 @@ class Trainer(object): ...@@ -47,7 +47,7 @@ class Trainer(object):
self._done = False # Are we finished? self._done = False # Are we finished?
self._agentPopen = [] # Agent's processes self._agentPopen = [] # Agent's processes
self._npcPopen = [] # NPC's processes self._npcPopen = [] # NPC's processes
self._connectedPlayers = [] self._connectedPlayers = [] # List of connected players
self.initMsgHandlers() self.initMsgHandlers()
def launch_agent(self, agent_num, agent_ext_num, play_offense, port, wait_until_join=True): def launch_agent(self, agent_num, agent_ext_num, play_offense, port, wait_until_join=True):
...@@ -55,8 +55,6 @@ class Trainer(object): ...@@ -55,8 +55,6 @@ class Trainer(object):
Returns a Popen process object Returns a Popen process object
""" """
print 'Launch agent %s-%d'%(self._offenseTeamName if play_offense
else self._defenseTeamName, agent_num)
if play_offense: if play_offense:
assert self._numOffense > 0 assert self._numOffense > 0
team_name = self._offenseTeamName team_name = self._offenseTeamName
...@@ -64,37 +62,24 @@ class Trainer(object): ...@@ -64,37 +62,24 @@ class Trainer(object):
# First offense number is reserved for inactive offensive goalie # First offense number is reserved for inactive offensive goalie
internal_player_num = agent_num + 1 internal_player_num = agent_num + 1
self._agentNumInt.append(internal_player_num) self._agentNumInt.append(internal_player_num)
numTeammates = self._numOffense - 1
numOpponents = self._numDefense
else: else:
assert self._numDefense > 0 assert self._numDefense > 0
team_name = self._defenseTeamName team_name = self._defenseTeamName
self._agentTeams.append(team_name) self._agentTeams.append(team_name)
internal_player_num = agent_num internal_player_num = agent_num
self._agentNumInt.append(internal_player_num) self._agentNumInt.append(internal_player_num)
numTeammates = self._numDefense - 1 binary_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)),
numOpponents = self._numOffense 'teams', 'base')
binary_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'teams', 'base')
config_dir = os.path.join(binary_dir, 'config/formations-dt') config_dir = os.path.join(binary_dir, 'config/formations-dt')
player_conf = os.path.join(binary_dir, '/config/player.conf') print("Waiting for player-controlled agent %s-%d: config_dir=%s, "\
agent_cmd = os.path.join(binary_dir, 'agent') "uniform_number=%d, server_port=%d, server_addr=%s, team_name=%s, "\
agent_cmd += ' -t %s -p %i --numTeammates %i --numOpponents %i' \ "play_goalie=%r"
' --playingOffense %i --serverPort %i --log_dir %s' \ % (self._offenseTeamName if play_offense else self._defenseTeamName,
' --player-config %s --config_dir %s' \ agent_num, config_dir, agent_ext_num, self._serverPort, "localhost",
%(team_name, self._serverPort, numTeammates, team_name, agent_ext_num==1))
numOpponents, play_offense, port, self._logDir,
player_conf, config_dir)
if agent_ext_num == 1:
agent_cmd += ' -g'
if self._record:
agent_cmd += ' --record'
# Comment next two lines to show output from agent.cpp and the server
kwargs = {'stdout':open('/dev/null', 'w'),
'stderr':open('/dev/null', 'w')}
p = subprocess.Popen(agent_cmd.split(' '), shell = False, **kwargs)
if wait_until_join: if wait_until_join:
self.waitOnPlayer(agent_ext_num, play_offense) self.waitOnPlayer(agent_ext_num, play_offense)
return p return None
def createTeam(self, requested_team_name, play_offense): def createTeam(self, requested_team_name, play_offense):
""" Given a team name, returns the team object. """ """ Given a team name, returns the team object. """
...@@ -198,6 +183,7 @@ class Trainer(object): ...@@ -198,6 +183,7 @@ class Trainer(object):
(self._numGoals, self._numTrials, self._frame, event) (self._numGoals, self._numTrials, self._frame, event)
self._numFrames += self._frame - self._lastTrialStart self._numFrames += self._frame - self._lastTrialStart
self._lastTrialStart = self._frame self._lastTrialStart = self._frame
self.getConnectedPlayers()
def _hear(self, body): def _hear(self, body):
""" Handle a hear message. """ """ Handle a hear message. """
...@@ -319,46 +305,37 @@ class Trainer(object): ...@@ -319,46 +305,37 @@ class Trainer(object):
def disconnectPlayer(self, player, player_num, on_offense): def disconnectPlayer(self, player, player_num, on_offense):
"""Wait on a launched player to disconnect from the server. """ """Wait on a launched player to disconnect from the server. """
# print 'Disconnect %s-%d'%(self._offenseTeamName if on_offense
# else self._defenseTeamName, player_num)
team_name = self._offenseTeamName if on_offense else self._defenseTeamName team_name = self._offenseTeamName if on_offense else self._defenseTeamName
self.send('(disconnect_player %s %d)'%(team_name, player_num)) self.send('(disconnect_player %s %d)'%(team_name, player_num))
player.kill() player.kill()
def waitOnPlayer(self, player_num, on_offense): def getConnectedPlayers(self):
"""Wait on a launched player to connect and be reported by the """ Get the list of connected players. Populates self._connectedPlayers. """
server. self._gotLook = False
"""
self.send('(look)') self.send('(look)')
partial = ['ok','look'] partial = ['ok','look']
self._numPlayers = 0
def f(body): def f(body):
self._gotLook = True
del self._connectedPlayers[:] del self._connectedPlayers[:]
for i in xrange(4, len(body)): for i in xrange(4, len(body)):
_,team,num = body[i][0][:3] _,team,num = body[i][0][:3]
if (team, num) not in self._connectedPlayers: if (team, num) not in self._connectedPlayers:
self._connectedPlayers.append((team,num)) self._connectedPlayers.append((team,num))
self.registerMsgHandler(f,*partial,quiet=True) self.registerMsgHandler(f,*partial,quiet=True)
team_name = self._offenseTeamName if on_offense else self._defenseTeamName while not self._gotLook:
while (team_name, str(player_num)) not in self._connectedPlayers:
self.listenAndProcess() self.listenAndProcess()
self.send('(look)') self.send('(look)')
self.ignoreMsg(*partial,quiet=True) self.ignoreMsg(*partial,quiet=True)
def checkIfAllPlayersConnected(self): def waitOnPlayer(self, player_num, on_offense):
""" Returns true if all players are connected. """ """ Wait on a launched player to connect and be reported by the server. """
print 'Checking all players are connected' team_name = self._offenseTeamName if on_offense else self._defenseTeamName
self.send('(look)') while (team_name, str(player_num)) not in self._connectedPlayers:
partial = ['ok','look'] self.getConnectedPlayers()
self._numPlayers = 0
def f(x): def allPlayersConnected(self):
self._numPlayers = len(x) - 4 # -4 for time, ball, goal_l, and goal_r """ Returns true all players are connected. """
self.send('(look)') return len(self._connectedPlayers) == self._numOffense + self._numDefense
self.registerMsgHandler(f,*partial,quiet=True)
while self._numPlayers != self._numOffense + self._numDefense:
self.listenAndProcess()
self.ignoreMsg(*partial,quiet=True)
def startGame(self): def startGame(self):
""" Starts a game of HFO. """ """ Starts a game of HFO. """
...@@ -382,7 +359,7 @@ class Trainer(object): ...@@ -382,7 +359,7 @@ class Trainer(object):
""" """
for p,name in necProcesses: for p,name in necProcesses:
if p.poll() is not None: if p is not None and p.poll() is not None:
print 'Something necessary closed (%s), exiting' % name print 'Something necessary closed (%s), exiting' % name
return False return False
return True return True
...@@ -434,15 +411,9 @@ class Trainer(object): ...@@ -434,15 +411,9 @@ class Trainer(object):
else: else:
self.disconnectPlayer(player, player_num, on_offense=False) self.disconnectPlayer(player, player_num, on_offense=False)
self.checkIfAllPlayersConnected() print 'Checking all players connected'
while not self.allPlayersConnected():
if self._numAgents > 0: self.getConnectedPlayers()
print 'Agents awaiting your connections'
necOff = set([(self._offenseTeamName,str(x)) for x in sorted_offense_agent_unums])
necDef = set([(self._defenseTeamName,str(x)) for x in sorted_defense_agent_unums])
necAgents = necOff.union(necDef)
while self.checkLive(necProcesses) and self._agentReady != necAgents:
self.listenAndProcess()
# Broadcast the HFO configuration # Broadcast the HFO configuration
offense_nums = ' '.join([str(self.convertToExtPlayer(self._offenseTeamName, i)) offense_nums = ' '.join([str(self.convertToExtPlayer(self._offenseTeamName, i))
...@@ -456,7 +427,7 @@ class Trainer(object): ...@@ -456,7 +427,7 @@ class Trainer(object):
offense_nums, defense_nums)) offense_nums, defense_nums))
print 'Starting game' print 'Starting game'
self.startGame() self.startGame()
while self.checkLive(necProcesses) and not self._done: while self.allPlayersConnected() and self.checkLive(necProcesses) and not self._done:
prevFrame = self._frame prevFrame = self._frame
self.listenAndProcess() self.listenAndProcess()
except TimeoutError: except TimeoutError:
......
...@@ -5,44 +5,72 @@ ...@@ -5,44 +5,72 @@
#include <stdio.h> #include <stdio.h>
#include <math.h> #include <math.h>
#include <iostream> #include <iostream>
using namespace std; using namespace std;
using namespace hfo; using namespace hfo;
// Before running this program, first Start HFO server: // This agent is intended to be run as a part of the passing_agents.sh script
// $./bin/HFO --offense-agents 1
// Server Connection Options. See printouts from bin/HFO.
feature_set_t features = HIGH_LEVEL_FEATURE_SET;
string config_dir = "bin/teams/base/config/formations-dt";
int unum = 11;
int port = 6001;
string server_addr = "localhost";
string team_name = "base_left";
bool goalie = false;
#define PI 3.14159265 #define PI 3.14159265
int main(int argc, char** argv) { int main(int argc, char** argv) {
int port = 6000; if (argc > 2) {
if (argc > 1) { unum = atoi(argv[1]);
port = atoi(argv[1]); port = atoi(argv[2]);
} }
// Create the HFO environment // Create the HFO environment
HFOEnvironment hfo; HFOEnvironment hfo;
// Connect to the agent's server on port 6000 and request low-level // Connect to the server and request feature set. See manual for
// feature set. See manual for more information on feature sets. // more information on feature sets.
hfo.connectToAgentServer(port, HIGH_LEVEL_FEATURE_SET); hfo.connectToServer(features, config_dir, unum, port, server_addr,
// Play 5 episodes team_name, goalie);
for (int episode=0; ; episode++) { for (int episode=0; episode<10; episode++) {
int step = 0; int agent_on_ball = 7;
status_t status = IN_GAME; status_t status = IN_GAME;
while (status == IN_GAME) { while (status == IN_GAME) {
// Get the vector of state features for the current state // Get the vector of state features for the current state
const vector<float>& feature_vec = hfo.getState(); const vector<float>& feature_vec = hfo.getState();
// Get any incoming communication // Get any incoming communication
std::string msg = hfo.hear(); std::string msg = hfo.hear();
// Do something with incoming communication if (!msg.empty()) {
cout << "HEARD: " << msg.c_str() << endl; cout << "Agent-" << unum << " HEARD: " << msg.c_str() << endl;
float target_x = sin((step % 360) * PI/180); if (msg == "Pass") {
float target_y = cos((step % 360) * PI/180); agent_on_ball = unum;
hfo.act(DRIBBLE_TO, target_x, target_y); }
}
// Do something with outgoing communication float x_pos = feature_vec[0];
hfo.say("Message"); float y_pos = feature_vec[1];
float target_x = 0;
float target_y = unum == 11 ? .3 : -.3;
bool in_position = (pow(x_pos-target_x, 2) + pow(y_pos-target_y,2)) < .0005;
bool able_to_kick = feature_vec[5] > 0;
if (agent_on_ball == unum && in_position && able_to_kick) {
int teammate_unum = unum == 11 ? 7 : 11;
float teammate_x_pos = 0;
float teammate_y_pos = -target_y;
hfo.act(KICK_TO, teammate_x_pos, teammate_y_pos, 2.0);
hfo.say("Pass");
agent_on_ball = teammate_unum;
} else {
float dist_to_ball = feature_vec[3];
float dist_to_teammate = feature_vec[13];
action_t action = unum == agent_on_ball ? DRIBBLE_TO : MOVE_TO;
hfo.act(action, target_x, target_y);
}
// Advance the environment and get the game status // Advance the environment and get the game status
status = hfo.step(); status = hfo.step();
step+=2;
} }
// Check what the outcome of the episode was
cout << "Episode " << episode << " ended with status: "
<< StatusToString(status) << std::endl;;
} }
hfo.act(QUIT); hfo.act(QUIT);
}; };
#!/usr/bin/env python #!/usr/bin/env python
# encoding: utf-8 # encoding: utf-8
import sys # Before running this program, first Start HFO server:
# $> ./bin/HFO --offense-agents 1
# First Start the server: $> bin/start.py import sys
from hfo import *
if __name__ == '__main__': if __name__ == '__main__':
port = 6000
if len(sys.argv) > 1:
port = int(sys.argv[1])
try:
from hfo import *
except:
print 'Failed to import hfo. To install hfo, in the HFO directory'\
' run: \"pip install .\"'
exit()
# Create the HFO Environment # Create the HFO Environment
hfo_env = hfo.HFOEnvironment() hfo = hfo.HFOEnvironment()
# Connect to the agent server on port 6000 with the specified # Connect to the server with the specified
# feature set. See feature sets in hfo.py/hfo.hpp. # feature set. See feature sets in hfo.py/hfo.hpp.
hfo_env.connectToAgentServer(port, HFO_Features.HIGH_LEVEL_FEATURE_SET) hfo.connectToServer(HIGH_LEVEL_FEATURE_SET,
# Play 5 episodes 'bin/teams/base/config/formations-dt', 11, 6000,
for episode in xrange(5): 'localhost', 'base_left', False)
status = HFO_Status.IN_GAME for episode in xrange(10):
status = IN_GAME
while status == HFO_Status.IN_GAME: while status == IN_GAME:
# Grab the state features from the environment # Grab the state features from the environment
features = hfo_env.getState() features = hfo.getState()
# Get any incoming communication # Get any incoming communication
msg = hfo_env.hear() msg = hfo.hear()
# Do something with incoming communication # Do something with incoming communication
print 'Heard: ', msg print 'Heard: ', msg
# Take an action and get the current game status # Take an action and get the current game status
hfo_env.act(HFO_Actions.DASH, 20.0, 0) hfo.act(DASH, 20.0, 0)
# Do something with outgoing communication # Do something with outgoing communication
hfo_env.say('Message') hfo.say('Message')
status = hfo_env.step() status = hfo.step()
print 'Episode', episode, 'ended with', hfo.statusToString(status)
print 'Episode', episode, 'ended with',
# Check what the outcome of the episode was
if status == HFO_Status.GOAL:
print 'goal', hfo.playerOnBall().unum
elif status == HFO_Status.CAPTURED_BY_DEFENSE:
print 'captured by defense', hfo.playerOnBall().unum
elif status == HFO_Status.OUT_OF_BOUNDS:
print 'out of bounds'
elif status == HFO_Status.OUT_OF_TIME:
print 'out of time'
else:
print 'Unknown status', status
exit()
# Cleanup when finished
hfo_env.cleanup()
#!/usr/bin/env python #!/usr/bin/env python
# encoding: utf-8 # encoding: utf-8
# First Start the server: $> bin/start.py # Before running this program, first Start HFO server:
import random, threading, argparse # $> ./bin/HFO --offense-agents 1
try:
from hfo import *
except:
print 'Failed to import hfo. To install hfo, in the HFO directory'\
' run: \"pip install .\"'
exit()
def get_random_action(): import random
"""Returns a random high-level action. Pass is omitted for simplicity.""" from hfo import *
high_lv_actions = [HFO_Actions.SHOOT, HFO_Actions.DRIBBLE]
return random.choice(high_lv_actions)
def play_hfo(num):
""" Method called by a thread to play 5 games of HFO """
hfo_env = hfo.HFOEnvironment()
hfo_env.connectToAgentServer(6000 + num, HFO_Features.HIGH_LEVEL_FEATURE_SET)
try:
for episode in xrange(5):
status = HFO_Status.IN_GAME
while status == HFO_Status.IN_GAME:
state = hfo_env.getState()
if state[5] == 1: #state[5] is 1 when player has the ball
hfo_env.act(get_random_action())
else:
hfo_env.act(HFO_Actions.MOVE)
status = hfo_env.step()
except:
pass
finally:
print "Agent " + str(num) + " exiting."
hfo_env.cleanup()
def main(): def main():
parser = argparse.ArgumentParser() # Create the HFO Environment
parser.add_argument('num_agents', type=int, help='Number of agents to start. '\ hfo = HFOEnvironment()
'NOTE: server must be started with this number of agents.') # Connect to the server with the specified
args = parser.parse_args() # feature set. See feature sets in hfo.py/hfo.hpp.
for i in xrange(args.num_agents): hfo.connectToServer(HIGH_LEVEL_FEATURE_SET,
t = threading.Thread(target=play_hfo, args=(i,)) 'bin/teams/base/config/formations-dt', 11, 6000,
t.start() 'localhost', 'base_left', False)
for episode in xrange(10):
status = IN_GAME
while status == IN_GAME:
state = hfo.getState()
if state[5] == 1: # State[5] is 1 when the player can kick the ball
hfo.act(random.choice([SHOOT, DRIBBLE]))
else:
hfo.act(MOVE)
status = hfo.step()
print 'Episode', episode, 'ended with', hfo.statusToString(status)
if __name__ == '__main__': if __name__ == '__main__':
main() main()
...@@ -7,14 +7,24 @@ using namespace std; ...@@ -7,14 +7,24 @@ using namespace std;
using namespace hfo; using namespace hfo;
// Before running this program, first Start HFO server: // Before running this program, first Start HFO server:
// $./bin/start.py --offense-agents 1 // $> ./bin/HFO --offense-agents 1
// Server Connection Options. See printouts from bin/HFO.
feature_set_t features = LOW_LEVEL_FEATURE_SET;
string config_dir = "bin/teams/base/config/formations-dt";
int unum = 11;
int port = 6001;
string server_addr = "localhost";
string team_name = "base_left";
bool goalie = false;
int main() { int main() {
// Create the HFO environment // Create the HFO environment
HFOEnvironment hfo; HFOEnvironment hfo;
// Connect to the agent's server on port 6000 and request low-level // Connect to the server and request low-level feature set. See
// feature set. See manual for more information on feature sets. // manual for more information on feature sets.
hfo.connectToAgentServer(6000, LOW_LEVEL_FEATURE_SET); hfo.connectToServer(features, config_dir, unum, port, server_addr,
team_name, goalie);
// Play 5 episodes // Play 5 episodes
for (int episode=0; episode<5; episode++) { for (int episode=0; episode<5; episode++) {
status_t status = IN_GAME; status_t status = IN_GAME;
...@@ -27,23 +37,8 @@ int main() { ...@@ -27,23 +37,8 @@ int main() {
status = hfo.step(); status = hfo.step();
} }
// Check what the outcome of the episode was // Check what the outcome of the episode was
cout << "Episode " << episode << " ended with status: "; cout << "Episode " << episode << " ended with status: "
switch (status) { << StatusToString(status) << std::endl;;
case GOAL:
cout << "goal" << endl;
break;
case CAPTURED_BY_DEFENSE:
cout << "captured by defense" << endl;
break;
case OUT_OF_BOUNDS:
cout << "out of bounds" << endl;
break;
case OUT_OF_TIME:
cout << "out of time" << endl;
break;
default:
cout << "Unknown status " << status << endl;
exit(1);
}
} }
hfo.act(QUIT);
}; };
#!/usr/bin/env python #!/usr/bin/env python
# encoding: utf-8 # encoding: utf-8
import sys # Before running this program, first Start HFO server:
# $> ./bin/HFO --offense-agents 1
from hfo import *
# First Start the server: $> bin/start.py
if __name__ == '__main__': if __name__ == '__main__':
port = 6000
if len(sys.argv) > 1:
port = int(sys.argv[1])
try:
from hfo import *
except:
print 'Failed to import hfo. To install hfo, in the HFO directory'\
' run: \"pip install .\"'
exit()
# Create the HFO Environment # Create the HFO Environment
hfo = hfo.HFOEnvironment() hfo = HFOEnvironment()
# Connect to the agent server on port 6000 with the specified # Connect to the server with the specified
# feature set. See feature sets in hfo.py/hfo.hpp. # feature set. See feature sets in hfo.py/hfo.hpp.
hfo.connectToAgentServer(port, HFO_Features.HIGH_LEVEL_FEATURE_SET) hfo.connectToServer(LOW_LEVEL_FEATURE_SET,
# Play 100 episodes 'bin/teams/base/config/formations-dt', 11, 6000,
for episode in xrange(100): 'localhost', 'base_left', False)
status = HFO_Status.IN_GAME for episode in xrange(10):
while status == HFO_Status.IN_GAME: status = IN_GAME
while status == IN_GAME:
# Grab the state features from the environment # Grab the state features from the environment
features = hfo.getState() features = hfo.getState()
# Take an action and get the current game status # Take an action and get the current game status
hfo.act(HFO_Actions.DASH, 20.0, 0) hfo.act(DASH, 20.0, 0)
status = hfo.step() status = hfo.step()
print 'Episode', episode, 'ended with', print 'Episode', episode, 'ended with', hfo.statusToString(status)
# Check what the outcome of the episode was
if status == HFO_Status.GOAL:
print 'goal', hfo.playerOnBall().unum
elif status == HFO_Status.CAPTURED_BY_DEFENSE:
print 'captured by defense', hfo.playerOnBall().unum
elif status == HFO_Status.OUT_OF_BOUNDS:
print 'out of bounds'
elif status == HFO_Status.OUT_OF_TIME:
print 'out of time'
else:
print 'Unknown status', status
exit()
# Cleanup when finished
hfo.cleanup()
...@@ -9,6 +9,15 @@ using namespace hfo; ...@@ -9,6 +9,15 @@ using namespace hfo;
// Before running this program, first Start HFO server: // Before running this program, first Start HFO server:
// $./bin/HFO --offense-agents 1 // $./bin/HFO --offense-agents 1
// Server Connection Options. See printouts from bin/HFO.
feature_set_t features = HIGH_LEVEL_FEATURE_SET;
string config_dir = "bin/teams/base/config/formations-dt";
int unum = 11;
int port = 6001;
string server_addr = "localhost";
string team_name = "base_left";
bool goalie = false;
// Returns a random high-level action // Returns a random high-level action
action_t get_random_high_lv_action() { action_t get_random_high_lv_action() {
action_t action_indx = (action_t) ((rand() % 5) + MOVE); action_t action_indx = (action_t) ((rand() % 5) + MOVE);
...@@ -16,17 +25,13 @@ action_t get_random_high_lv_action() { ...@@ -16,17 +25,13 @@ action_t get_random_high_lv_action() {
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
int port = 6000;
if (argc > 1) {
port = atoi(argv[1]);
}
// Create the HFO environment // Create the HFO environment
HFOEnvironment hfo; HFOEnvironment hfo;
// Connect to the agent's server on port 6000 and request low-level // Connect to the server and request high-level feature set. See
// feature set. See manual for more information on feature sets. // manual for more information on feature sets.
hfo.connectToAgentServer(port, HIGH_LEVEL_FEATURE_SET); hfo.connectToServer(features, config_dir, unum, port, server_addr,
// Play 5 episodes team_name, goalie);
for (int episode=0; ; episode++) { for (int episode=0; episode<10; episode++) {
status_t status = IN_GAME; status_t status = IN_GAME;
while (status == IN_GAME) { while (status == IN_GAME) {
// Get the vector of state features for the current state // Get the vector of state features for the current state
...@@ -36,26 +41,9 @@ int main(int argc, char** argv) { ...@@ -36,26 +41,9 @@ int main(int argc, char** argv) {
// Advance the environment and get the game status // Advance the environment and get the game status
status = hfo.step(); status = hfo.step();
} }
// Check what the outcome of the episode was // Check what the outcome of the episode was
cout << "Episode " << episode << " ended with status: "; cout << "Episode " << episode << " ended with status: "
switch (status) { << StatusToString(status) << std::endl;
case GOAL:
cout << "goal " << hfo.playerOnBall().unum << endl;
break;
case CAPTURED_BY_DEFENSE:
cout << "captured by defense " << hfo.playerOnBall().unum << endl;
break;
case OUT_OF_BOUNDS:
cout << "out of bounds" << endl;
break;
case OUT_OF_TIME:
cout << "out of time" << endl;
break;
default:
cout << "Unknown status " << status << endl;
exit(1);
}
} }
hfo.act(QUIT); hfo.act(QUIT);
}; };
...@@ -9,6 +9,15 @@ using namespace hfo; ...@@ -9,6 +9,15 @@ using namespace hfo;
// Before running this program, first Start HFO server: // Before running this program, first Start HFO server:
// $./bin/HFO --offense-agents 1 // $./bin/HFO --offense-agents 1
// Server Connection Options. See printouts from bin/HFO.
feature_set_t features = LOW_LEVEL_FEATURE_SET;
string config_dir = "bin/teams/base/config/formations-dt";
int unum = 11;
int port = 6001;
string server_addr = "localhost";
string team_name = "base_left";
bool goalie = false;
float arg1, arg2; float arg1, arg2;
// Returns a random low-level action // Returns a random low-level action
...@@ -40,16 +49,12 @@ action_t get_random_low_lv_action() { ...@@ -40,16 +49,12 @@ action_t get_random_low_lv_action() {
} }
int main(int argc, char** argv) { int main(int argc, char** argv) {
int port = 6000;
if (argc > 1) {
port = atoi(argv[1]);
}
// Create the HFO environment // Create the HFO environment
HFOEnvironment hfo; HFOEnvironment hfo;
// Connect to the agent's server on port 6000 and request low-level // Connect to the server and request low-level feature set. See
// feature set. See manual for more information on feature sets. // manual for more information on feature sets.
hfo.connectToAgentServer(port, LOW_LEVEL_FEATURE_SET); hfo.connectToServer(features, config_dir, unum, port, server_addr,
// Play 5 episodes team_name, goalie);
for (int episode=0; ; episode++) { for (int episode=0; ; episode++) {
status_t status = IN_GAME; status_t status = IN_GAME;
while (status == IN_GAME) { while (status == IN_GAME) {
...@@ -57,8 +62,9 @@ int main(int argc, char** argv) { ...@@ -57,8 +62,9 @@ int main(int argc, char** argv) {
const vector<float>& feature_vec = hfo.getState(); const vector<float>& feature_vec = hfo.getState();
// Perform the action and recieve the current game status // Perform the action and recieve the current game status
hfo.act(get_random_low_lv_action(), arg1, arg2); hfo.act(get_random_low_lv_action(), arg1, arg2);
// Advance the environment and recieve current game status
status = hfo.step(); status = hfo.step();
} }
} }
hfo.act(QUIT);
}; };
...@@ -7,23 +7,29 @@ ...@@ -7,23 +7,29 @@
using namespace std; using namespace std;
using namespace hfo; using namespace hfo;
#define PI 3.14159265
// This agent demonstrates the use of the DRIBBLE_TO action. Before // This agent demonstrates the use of the DRIBBLE_TO action. Before
// running this program, first Start HFO server: $./bin/HFO // running this program, first Start HFO server:
// --offense-agents 1 // $./bin/HFO --offense-agents 1
#define PI 3.14159265 // Server Connection Options. See printouts from bin/HFO.
feature_set_t features = HIGH_LEVEL_FEATURE_SET;
string config_dir = "bin/teams/base/config/formations-dt";
int unum = 11;
int port = 6001;
string server_addr = "localhost";
string team_name = "base_left";
bool goalie = false;
int main(int argc, char** argv) { int main(int argc, char** argv) {
int port = 6000;
if (argc > 1) {
port = atoi(argv[1]);
}
// Create the HFO environment // Create the HFO environment
HFOEnvironment hfo; HFOEnvironment hfo;
// Connect to the agent's server on port 6000 and request low-level // Connect to the server and request low-level feature set. See
// feature set. See manual for more information on feature sets. // manual for more information on feature sets.
hfo.connectToAgentServer(port, HIGH_LEVEL_FEATURE_SET); hfo.connectToServer(features, config_dir, unum, port, server_addr,
for (int episode=0; ; episode++) { team_name, goalie);
for (int episode=0; episode<10; episode++) {
status_t status = IN_GAME; status_t status = IN_GAME;
int step = 0; int step = 0;
while (status == IN_GAME) { while (status == IN_GAME) {
...@@ -37,6 +43,9 @@ int main(int argc, char** argv) { ...@@ -37,6 +43,9 @@ int main(int argc, char** argv) {
status = hfo.step(); status = hfo.step();
step += 2; step += 2;
} }
// Check what the outcome of the episode was
cout << "Episode " << episode << " ended with status: "
<< StatusToString(status) << std::endl;;
} }
hfo.act(QUIT); hfo.act(QUIT);
}; };
...@@ -11,17 +11,23 @@ using namespace hfo; ...@@ -11,17 +11,23 @@ using namespace hfo;
// running this program, first Start HFO server: $./bin/HFO // running this program, first Start HFO server: $./bin/HFO
// --offense-agents 1 // --offense-agents 1
// Server Connection Options. See printouts from bin/HFO.
feature_set_t features = HIGH_LEVEL_FEATURE_SET;
string config_dir = "bin/teams/base/config/formations-dt";
int unum = 11;
int port = 6001;
string server_addr = "localhost";
string team_name = "base_left";
bool goalie = false;
int main(int argc, char** argv) { int main(int argc, char** argv) {
int port = 6000;
if (argc > 1) {
port = atoi(argv[1]);
}
// Create the HFO environment // Create the HFO environment
HFOEnvironment hfo; HFOEnvironment hfo;
// Connect to the agent's server on port 6000 and request low-level // Connect to the server and request low-level feature set. See
// feature set. See manual for more information on feature sets. // manual for more information on feature sets.
hfo.connectToAgentServer(port, HIGH_LEVEL_FEATURE_SET); hfo.connectToServer(features, config_dir, unum, port, server_addr,
for (int episode=0; ; episode++) { team_name, goalie);
for (int episode=0; episode < 10; episode++) {
status_t status = IN_GAME; status_t status = IN_GAME;
while (status == IN_GAME) { while (status == IN_GAME) {
// Get the vector of state features for the current state // Get the vector of state features for the current state
...@@ -47,24 +53,8 @@ int main(int argc, char** argv) { ...@@ -47,24 +53,8 @@ int main(int argc, char** argv) {
status = hfo.step(); status = hfo.step();
} }
// Check what the outcome of the episode was // Check what the outcome of the episode was
cout << "Episode " << episode << " ended with status: "; cout << "Episode " << episode << " ended with status: "
switch (status) { << StatusToString(status) << std::endl;;
case GOAL:
cout << "goal " << hfo.playerOnBall().unum << endl;
break;
case CAPTURED_BY_DEFENSE:
cout << "captured by defense " << hfo.playerOnBall().unum << endl;
break;
case OUT_OF_BOUNDS:
cout << "out of bounds" << endl;
break;
case OUT_OF_TIME:
cout << "out of time" << endl;
break;
default:
cout << "Unknown status " << status << endl;
exit(1);
}
} }
hfo.act(QUIT); hfo.act(QUIT);
}; };
...@@ -9,19 +9,26 @@ using namespace hfo; ...@@ -9,19 +9,26 @@ using namespace hfo;
// This agent demonstrates the use of the MOVE_TO action to visit the // This agent demonstrates the use of the MOVE_TO action to visit the
// corners of the play field. Before running this program, first Start // corners of the play field. Before running this program, first Start
// HFO server: $./bin/HFO --offense-agents 1 // HFO server: $./bin/HFO --offense-agents 1
// Server Connection Options. See printouts from bin/HFO.
feature_set_t features = HIGH_LEVEL_FEATURE_SET;
string config_dir = "bin/teams/base/config/formations-dt";
int unum = 11;
int port = 6001;
string server_addr = "localhost";
string team_name = "base_left";
bool goalie = false;
int main(int argc, char** argv) { int main(int argc, char** argv) {
int port = 6000;
if (argc > 1) {
port = atoi(argv[1]);
}
// Create the HFO environment // Create the HFO environment
HFOEnvironment hfo; HFOEnvironment hfo;
// Connect to the agent's server on port 6000 and request low-level // Connect to the server and request feature set. See manual for
// feature set. See manual for more information on feature sets. // more information on feature sets.
hfo.connectToAgentServer(port, HIGH_LEVEL_FEATURE_SET); hfo.connectToServer(features, config_dir, unum, port, server_addr,
float target_x = 1.0; team_name, goalie);
float target_y = 1.0; float target_x = .82;
for (int episode=0; ; episode++) { float target_y = .9;
for (int episode = 0; episode < 10; episode++) {
status_t status = IN_GAME; status_t status = IN_GAME;
if (episode % 2 != 0) { if (episode % 2 != 0) {
target_x *= -1; target_x *= -1;
...@@ -37,6 +44,9 @@ int main(int argc, char** argv) { ...@@ -37,6 +44,9 @@ int main(int argc, char** argv) {
// Advance the environment and get the game status // Advance the environment and get the game status
status = hfo.step(); status = hfo.step();
} }
// Check what the outcome of the episode was
cout << "Episode " << episode << " ended with status: "
<< StatusToString(status) << std::endl;;
} }
hfo.act(QUIT); hfo.act(QUIT);
}; };
#!/bin/bash
./bin/HFO --offense-agents=2 --no-sync &
sleep 1
./example/communication_agent 7 6000 &
sleep 1
./example/communication_agent 11 6000 &
# The magic line
# $$ holds the PID for this script
# Negation means kill by process group id instead of PID
trap "kill -TERM -$$" SIGINT
wait
from hfo import * from .hfo import *
This diff is collapsed.
#include "hfo_c_wrapper.h"
#ifndef __HFO_C_WRAPPER_H__
#define __HFO_C_WRAPPER_H__
#include <vector>
#include <HFO.hpp>
#include <common.hpp>
extern "C" {
hfo::HFOEnvironment* HFO_new() { return new hfo::HFOEnvironment(); }
void HFO_del(hfo::HFOEnvironment *hfo) { delete hfo; }
void connectToServer(hfo::HFOEnvironment *hfo,
hfo::feature_set_t feature_set,
char* config_dir,
int uniform_number,
int server_port,
char* server_addr,
char* team_name,
bool play_goalie) {
return hfo->connectToServer(feature_set, config_dir, uniform_number,
server_port, server_addr, team_name,
play_goalie);
}
int getStateSize(hfo::HFOEnvironment *hfo) { return hfo->getState().size(); }
void getState(hfo::HFOEnvironment *hfo, float *state_data) {
const float* state_features = hfo->getState().data();
memcpy(state_data, state_features, getStateSize(hfo) * sizeof(float));
}
void act(hfo::HFOEnvironment *hfo, hfo::action_t action, float* params) {
int n_params = NumParams(action);
std::vector<float> p(n_params);
for (int i=0; i<n_params; ++i) {
p[i] = params[i];
}
hfo->act(action, p);
}
void say(hfo::HFOEnvironment *hfo, const char *message) { hfo->say(message); }
const char* hear(hfo::HFOEnvironment *hfo) { return hfo->hear().c_str(); }
hfo::Player playerOnBall(hfo::HFOEnvironment *hfo) { return hfo->playerOnBall(); }
hfo::status_t step(hfo::HFOEnvironment *hfo) { return hfo->step(); }
int numParams(const hfo::action_t action) { return NumParams(action); }
const char* actionToString(const hfo::action_t action) {
return ActionToString(action).c_str();
}
const char* statusToString(const hfo::status_t status) {
return StatusToString(status).c_str();
}
}
#endif
import os from distutils.core import setup, Extension
import setuptools import os.path, sys
setuptools.setup( hfo_c_lib = 'hfo/libhfo_c.so'
name='hfo', if not os.path.isfile(hfo_c_lib):
version='0.1.2', print('ERROR: Unable to find required library: %s.'%(hfo_c_lib))
packages=setuptools.find_packages(), sys.exit()
module1 = Extension('hfo.hfo_c_wrapper',
libraries = ['hfo_c'],
include_dirs = ['src','src/chain_action','build/librcsc-prefix/src/librcsc'],
library_dirs = ['hfo'],
extra_compile_args=['-D__STDC_CONSTANT_MACROS'],
sources=['hfo/hfo_c_wrapper.cpp'])
setup(name = 'hfo',
version='0.1.5',
author='Matthew Hausknecht', author='Matthew Hausknecht',
author_email='matthew.hausknecht@gmail.com', author_email='matthew.hausknecht@gmail.com',
description='Half Field Offense in 2D RoboCup Soccer.', description='Half Field Offense in 2D RoboCup Soccer.',
license='MIT', license='MIT',
ext_modules = [module1],
keywords=('Robocup ' keywords=('Robocup '
'Half-field-offense ' 'Half-field-offense '
), ),
...@@ -18,4 +28,7 @@ setuptools.setup( ...@@ -18,4 +28,7 @@ setuptools.setup(
'License :: OSI Approved :: MIT License', 'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent', 'Operating System :: OS Independent',
], ],
) # packages=find_packages(),
packages=['hfo'],
package_dir={'hfo': 'hfo'},
package_data={'hfo': ['libhfo_c.so']})
This diff is collapsed.
...@@ -3,101 +3,45 @@ ...@@ -3,101 +3,45 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <rcsc/common/basic_client.h>
#include <rcsc/player/player_config.h>
#include <rcsc/player/world_model.h>
#include "agent.h"
#include "common.hpp"
namespace hfo { namespace hfo {
// For descriptions of the different feature sets see
// https://github.com/mhauskn/HFO/blob/master/doc/manual.pdf
enum feature_set_t
{
LOW_LEVEL_FEATURE_SET,
HIGH_LEVEL_FEATURE_SET
};
// The actions available to the agent
enum action_t
{
DASH, // [Low-Level] Dash(power [0,100], direction [-180,180])
TURN, // [Low-Level] Turn(direction [-180,180])
TACKLE, // [Low-Level] Tackle(direction [-180,180])
KICK, // [Low-Level] Kick(power [0,100], direction [-180,180])
KICK_TO, // [Mid-Level] Kick_To(target_x [-1,1], target_y [-1,1], speed [0,3])
MOVE_TO, // [Mid-Level] Move(target_x [-1,1], target_y [-1,1])
DRIBBLE_TO, // [Mid-Level] Dribble(target_x [-1,1], target_y [-1,1])
INTERCEPT, // [Mid-Level] Intercept(): Intercept the ball
MOVE, // [High-Level] Move(): Reposition player according to strategy
SHOOT, // [High-Level] Shoot(): Shoot the ball
PASS, // [High-Level] Pass(teammate_unum [0,11]): Pass to the most open teammate
DRIBBLE, // [High-Level] Dribble(): Offensive dribble
CATCH, // [High-Level] Catch(): Catch the ball (Goalie only!)
NOOP, // Do nothing
QUIT // Special action to quit the game
};
// An Action consists of the discreet action as well as required
// arguments (parameters).
struct Action {
action_t action;
float arg1;
float arg2;
};
// Status of a HFO game
enum status_t
{
IN_GAME, // Game is currently active
GOAL, // A goal has been scored by the offense
CAPTURED_BY_DEFENSE, // The defense has captured the ball
OUT_OF_BOUNDS, // Ball has gone out of bounds
OUT_OF_TIME // Trial has ended due to time limit
};
enum SideID {
RIGHT = -1,
NEUTRAL = 0,
LEFT = 1
};
// Configuration of the HFO domain including the team names and player
// numbers for each team. This struct is populated by ParseConfig().
struct Config {
std::string offense_team_name;
std::string defense_team_name;
int num_offense; // Number of offensive players
int num_defense; // Number of defensive players
std::vector<int> offense_nums; // Offensive player numbers
std::vector<int> defense_nums; // Defensive player numbers
};
struct Player {
SideID side;
int unum;
};
class HFOEnvironment { class HFOEnvironment {
public: public:
HFOEnvironment(); HFOEnvironment() {};
~HFOEnvironment(); virtual ~HFOEnvironment() {};
// Returns a string representation of an action. /**
static std::string ActionToString(Action action); * Connect to the server on the specified port. The
* following information is provided by the ./bin/HFO
// Get the number of parameters needed for a action. *
static int NumParams(action_t action); * feature_set: High or low level state features
* config_dir: Config directory. Typically HFO/bin/teams/base/config/
// Parse a Trainer message to populate config. Returns a bool * uniform_number: player's uniform number.
// indicating if the struct was correctly parsed. * server_port: port to connect to server on
static bool ParseConfig(const std::string& message, Config& config); * server_addr: address of server
* team_name: Name of team to join.
// Connect to the server that controls the agent on the specified port. * play_goalie: is this player the goalie
void connectToAgentServer(int server_port=6000, */
feature_set_t feature_set=HIGH_LEVEL_FEATURE_SET); void connectToServer(feature_set_t feature_set=HIGH_LEVEL_FEATURE_SET,
std::string config_dir="bin/teams/base/config/formations-dt",
int uniform_number=11,
int server_port=6000,
std::string server_addr="localhost",
std::string team_name="base_left",
bool play_goalie=false);
// Get the current state of the domain. Returns a reference to feature_vec. // Get the current state of the domain. Returns a reference to feature_vec.
const std::vector<float>& getState(); const std::vector<float>& getState();
// Specify action type to take followed by parameters for that action // Specify action type to take followed by parameters for that action
virtual void act(action_t action, ...); virtual void act(action_t action, ...);
virtual void act(action_t action, const std::vector<float>& params);
// Send/receive communication from other agents // Send/receive communication from other agents
virtual void say(const std::string& message); virtual void say(const std::string& message);
...@@ -111,17 +55,8 @@ class HFOEnvironment { ...@@ -111,17 +55,8 @@ class HFOEnvironment {
virtual status_t step(); virtual status_t step();
protected: protected:
int numFeatures; // The number of features in this domain rcsc::BasicClient client;
int sockfd; // Socket file desriptor for connection to agent server Agent agent;
std::vector<float> feature_vec; // Holds the features
action_t requested_action; // Action requested
std::vector<float> action_params; // Action parameters
std::string say_msg, hear_msg; // Messages to hear/say
Player player_on_ball;
// Handshake with the agent server to ensure data is being correctly
// passed. Also sets the number of features to expect.
virtual void handshakeAgentServer(feature_set_t feature_set);
}; };
} // namespace hfo } // namespace hfo
......
This diff is collapsed.
// -*-c++-*-
/*
*Copyright:
Copyright (C) Hidehisa AKIYAMA
This code is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this code; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*EndCopyright:
*/
/////////////////////////////////////////////////////////////////////
#ifndef AGENT_H #ifndef AGENT_H
#define AGENT_H #define AGENT_H
#include "action_generator.h" #include "action_generator.h"
#include "field_evaluator.h" #include "field_evaluator.h"
#include "communication.h" #include "communication.h"
#include "HFO.hpp"
#include "feature_extractor.h" #include "feature_extractor.h"
#include "common.hpp"
#include <rcsc/player/player_agent.h> #include <rcsc/player/player_agent.h>
#include <vector> #include <vector>
...@@ -42,10 +16,6 @@ public: ...@@ -42,10 +16,6 @@ public:
virtual ~Agent(); virtual ~Agent();
virtual FieldEvaluator::ConstPtr getFieldEvaluator() const; virtual FieldEvaluator::ConstPtr getFieldEvaluator() const;
// Get the current game status, and the side and uniform number of the player holding the ball
static std::vector<int> getGameStatus(const rcsc::AudioSensor& audio_sensor,
long& lastTrainerMessageTime);
// Returns the feature extractor corresponding to the feature_set_t // Returns the feature extractor corresponding to the feature_set_t
static FeatureExtractor* getFeatureExtractor(hfo::feature_set_t feature_set, static FeatureExtractor* getFeatureExtractor(hfo::feature_set_t feature_set,
int num_teammates, int num_teammates,
...@@ -70,26 +40,38 @@ protected: ...@@ -70,26 +40,38 @@ protected:
virtual FieldEvaluator::ConstPtr createFieldEvaluator() const; virtual FieldEvaluator::ConstPtr createFieldEvaluator() const;
virtual ActionGenerator::ConstPtr createActionGenerator() const; virtual ActionGenerator::ConstPtr createActionGenerator() const;
// Start the server and listen for a connection.
void startServer(int server_port=6008);
void listenForConnection();
// Transmit information to the client and ensure it can recieve.
void clientHandshake();
protected: protected:
FeatureExtractor* feature_extractor; hfo::feature_set_t feature_set; // Requested feature set
FeatureExtractor* feature_extractor; // Extracts the features
long lastTrainerMessageTime; // Last time the trainer sent a message long lastTrainerMessageTime; // Last time the trainer sent a message
long lastTeammateMessageTime; // Last time a teammate sent a message long lastTeammateMessageTime; // Last time a teammate sent a message
int server_port; // Port to start the server on long lastDecisionTime; // Last time we made a decision
bool client_connected; // Has the client connected and handshake? hfo::status_t game_status; // Current status of the game
int sockfd, newsockfd; // Server sockets hfo::Player player_on_ball; // Player in posession of the ball
int num_teammates, num_opponents; std::vector<float> state; // Vector of current state features
bool playing_offense; std::string say_msg, hear_msg; // Messages to/from teammates
hfo::action_t action; // Currently requested action
std::vector<float> params; // Parameters of current action
public:
inline const std::vector<float>& getState() { return state; }
inline hfo::status_t getGameStatus() { return game_status; }
inline const hfo::Player& getPlayerOnBall() { return player_on_ball; }
inline const std::string& getHearMsg() { return hear_msg; }
inline long cycle() { return world().time().cycle(); }
inline long getLastDecisionTime() { return lastDecisionTime; }
inline void setFeatureSet(hfo::feature_set_t fset) { feature_set = fset; }
inline std::vector<float>* mutable_params() { return &params; }
inline void setAction(hfo::action_t a) { action = a; }
inline void setSayMsg(const std::string& message) { say_msg = message; }
private: private:
bool doPreprocess(); bool doPreprocess();
bool doSmartKick();
bool doShoot(); bool doShoot();
bool doPass(); bool doPass();
bool doPassTo(int receiver);
bool doDribble(); bool doDribble();
bool doMove(); bool doMove();
bool doForceKick(); bool doForceKick();
......
#ifndef __COMMON_HPP__
#define __COMMON_HPP__
#include <sstream>
namespace hfo {
// For descriptions of the different feature sets see
// https://github.com/mhauskn/HFO/blob/master/doc/manual.pdf
enum feature_set_t
{
LOW_LEVEL_FEATURE_SET,
HIGH_LEVEL_FEATURE_SET
};
// The actions available to the agent
enum action_t
{
DASH, // [Low-Level] Dash(power [0,100], direction [-180,180])
TURN, // [Low-Level] Turn(direction [-180,180])
TACKLE, // [Low-Level] Tackle(direction [-180,180])
KICK, // [Low-Level] Kick(power [0,100], direction [-180,180])
KICK_TO, // [Mid-Level] Kick_To(target_x [-1,1], target_y [-1,1], speed [0,3])
MOVE_TO, // [Mid-Level] Move(target_x [-1,1], target_y [-1,1])
DRIBBLE_TO, // [Mid-Level] Dribble(target_x [-1,1], target_y [-1,1])
INTERCEPT, // [Mid-Level] Intercept(): Intercept the ball
MOVE, // [High-Level] Move(): Reposition player according to strategy
SHOOT, // [High-Level] Shoot(): Shoot the ball
PASS, // [High-Level] Pass(teammate_unum [0,11]): Pass to the most open teammate
DRIBBLE, // [High-Level] Dribble(): Offensive dribble
CATCH, // [High-Level] Catch(): Catch the ball (Goalie only!)
NOOP, // Do nothing
QUIT // Special action to quit the game
};
// Status of a HFO game
enum status_t
{
IN_GAME, // Game is currently active
GOAL, // A goal has been scored by the offense
CAPTURED_BY_DEFENSE, // The defense has captured the ball
OUT_OF_BOUNDS, // Ball has gone out of bounds
OUT_OF_TIME, // Trial has ended due to time limit
SERVER_DOWN // Server is not alive
};
// Configuration of the HFO domain including the team names and player
// numbers for each team. This struct is populated by ParseConfig().
struct Config {
std::string offense_team_name;
std::string defense_team_name;
int num_offense; // Number of offensive players
int num_defense; // Number of defensive players
std::vector<int> offense_nums; // Offensive player numbers
std::vector<int> defense_nums; // Defensive player numbers
};
enum SideID {
RIGHT = -1,
NEUTRAL = 0,
LEFT = 1
};
// A Player is described by its uniform number and side
struct Player {
SideID side;
int unum;
};
/**
* Returns the number of parameters required for each action.
*/
inline int NumParams(const action_t action) {
switch (action) {
case DASH:
return 2;
case TURN:
return 1;
case TACKLE:
return 1;
case KICK:
return 2;
case KICK_TO:
return 3;
case MOVE_TO:
return 2;
case DRIBBLE_TO:
return 2;
case INTERCEPT:
return 0;
case MOVE:
return 0;
case SHOOT:
return 0;
case PASS:
return 1;
case DRIBBLE:
return 0;
case CATCH:
return 0;
case NOOP:
return 0;
case QUIT:
return 0;
}
std::cerr << "Unrecognized Action: " << action << std::endl;
return -1;
};
/**
* Returns a string representation of an action.
*/
inline std::string ActionToString(action_t action) {
switch (action) {
case DASH:
return "Dash";
case TURN:
return "Turn";
case TACKLE:
return "Tackle";
case KICK:
return "Kick";
case KICK_TO:
return "KickTo";
case MOVE_TO:
return "MoveTo";
case DRIBBLE_TO:
return "DribbleTo";
case INTERCEPT:
return "Intercept";
case MOVE:
return "Move";
case SHOOT:
return "Shoot";
case PASS:
return "Pass";
case DRIBBLE:
return "Dribble";
case CATCH:
return "Catch";
case NOOP:
return "No-op";
case QUIT:
return "Quit";
default:
return "Unknown";
}
};
/**
* Returns a string representation of a game_status.
*/
inline std::string StatusToString(status_t status) {
switch (status) {
case IN_GAME:
return "InGame";
case GOAL:
return "Goal";
case CAPTURED_BY_DEFENSE:
return "CapturedByDefense";
case OUT_OF_BOUNDS:
return "OutOfBounds";
case OUT_OF_TIME:
return "OutOfTime";
case SERVER_DOWN:
return "ServerDown";
default:
return "Unknown";
}
};
/**
* Parse a Trainer message to populate config. Returns a bool
* indicating if the struct was correctly parsed.
*/
inline bool ParseConfig(const std::string& message, Config& config) {
config.num_offense = -1;
config.num_defense = -1;
std::istringstream iss(message);
std::string header = "HFO_SETUP";
std::string key, val;
iss >> key;
if (header.compare(key) != 0) {
std::cerr << "Got unexpected message header: " << header;
return false;
}
while (iss >> key) {
if (key.compare("offense_name") == 0) {
iss >> config.offense_team_name;
} else if (key.compare("defense_name") == 0) {
iss >> config.defense_team_name;
} else if (key.compare("num_offense") == 0) {
iss >> val;
config.num_offense = strtol(val.c_str(), NULL, 0);
} else if (key.compare("num_defense") == 0) {
iss >> val;
config.num_defense = strtol(val.c_str(), NULL, 0);
} else if (key.compare("offense_nums") == 0) {
assert(config.num_offense >= 0);
for (int i=0; i<config.num_offense; ++i) {
iss >> val;
config.offense_nums.push_back(strtol(val.c_str(), NULL, 0));
}
} else if (key.compare("defense_nums") == 0) {
assert(config.num_defense >= 0);
for (int i=0; i<config.num_defense; ++i) {
iss >> val;
config.defense_nums.push_back(strtol(val.c_str(), NULL, 0));
}
} else {
std::cerr << "Unrecognized key: " << key << std::endl;
return false;
}
}
assert(config.offense_nums.size() == config.num_offense);
assert(config.defense_nums.size() == config.num_defense);
return true;
};
/**
* Parse a trainer message to extract the player on the ball
*/
inline bool ParsePlayerOnBall(const std::string& message, Player& player) {
if (message.find("GOAL") != std::string::npos){
player.unum = atoi((message.substr(message.find("-")+1)).c_str());
player.side = LEFT;
} else if (message.find("CAPTURED_BY_DEFENSE") != std::string::npos) {
player.unum = atoi((message.substr(message.find("-")+1)).c_str());
player.side = RIGHT;
} else if (message.find("IN_GAME") != std::string::npos){
switch (message.at(message.find("-")+1)){
case 'L':
player.side = LEFT;
break;
case 'R':
player.side = RIGHT;
break;
case 'U':
player.side = NEUTRAL;
break;
}
player.unum = atoi((message.substr(message.find("-")+2)).c_str());
} else {
return false;
}
return true;
};
/**
* Parse a trainer message to extract the game status
*/
inline bool ParseGameStatus(const std::string& message, status_t& status) {
status = IN_GAME;
if (message.find("GOAL") != std::string::npos){
status = GOAL;
} else if (message.find("CAPTURED_BY_DEFENSE") != std::string::npos) {
status = CAPTURED_BY_DEFENSE;
} else if (message.compare("OUT_OF_BOUNDS") == 0) {
status = OUT_OF_BOUNDS;
} else if (message.compare("OUT_OF_TIME") == 0) {
status = OUT_OF_TIME;
} else if (message.find("IN_GAME") != std::string::npos){
status = IN_GAME;
} else {
return false;
}
return true;
};
}
#endif
...@@ -233,7 +233,7 @@ bool SamplePlayer::getHFOConfig() { ...@@ -233,7 +233,7 @@ bool SamplePlayer::getHFOConfig() {
const AudioSensor& audio_sensor = audioSensor(); const AudioSensor& audio_sensor = audioSensor();
if (audio_sensor.trainerMessageTime().cycle() > lastTrainerMessageTime) { if (audio_sensor.trainerMessageTime().cycle() > lastTrainerMessageTime) {
const std::string& message = audio_sensor.trainerMessage(); const std::string& message = audio_sensor.trainerMessage();
if (hfo::HFOEnvironment::ParseConfig(message, hfo_config)) { if (hfo::ParseConfig(message, hfo_config)) {
lastTrainerMessageTime = audio_sensor.trainerMessageTime().cycle(); lastTrainerMessageTime = audio_sensor.trainerMessageTime().cycle();
if (config().teamName().compare(hfo_config.offense_team_name) == 0) { if (config().teamName().compare(hfo_config.offense_team_name) == 0) {
playing_offense = true; playing_offense = true;
...@@ -269,10 +269,15 @@ SamplePlayer::actionImpl() ...@@ -269,10 +269,15 @@ SamplePlayer::actionImpl()
hfo::LOW_LEVEL_FEATURE_SET, num_teammates, num_opponents, playing_offense); hfo::LOW_LEVEL_FEATURE_SET, num_teammates, num_opponents, playing_offense);
} }
} else { } else {
std::vector<int> game_status = Agent::getGameStatus( if (audioSensor().trainerMessageTime().cycle() > lastTrainerMessageTime) {
audioSensor(), lastTrainerMessageTime); const std::string& message = audioSensor().trainerMessage();
elog.addText(Logger::WORLD, "GameStatus %d", game_status[0]); hfo::status_t game_status;
if (hfo::ParseGameStatus(message, game_status)) {
elog.addText(Logger::WORLD, "GameStatus %d", game_status);
elog.flush(); elog.flush();
}
lastTrainerMessageTime = audioSensor().trainerMessageTime().cycle();
}
feature_extractor->ExtractFeatures(this->world()); feature_extractor->ExtractFeatures(this->world());
feature_extractor->LogFeatures(); feature_extractor->LogFeatures();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment