Commit 97e92d12 authored by Matthew Hausknecht's avatar Matthew Hausknecht

Merge pull request #19 from sanmit/teams

Opponent binary support
parents 0104ff75 04941856
...@@ -62,10 +62,10 @@ cmake_install.cmake ...@@ -62,10 +62,10 @@ cmake_install.cmake
CMakeFiles/ CMakeFiles/
# Executeables # Executeables
bin/agent bin/teams/base/agent
bin/sample_coach bin/teams/base/sample_coach
bin/sample_player bin/teams/base/sample_player
bin/sample_trainer bin/teams/base/sample_trainer
bin/rcssserver bin/rcssserver
bin/soccerwindow2 bin/soccerwindow2
example/hfo_example_agent example/hfo_example_agent
...@@ -74,6 +74,7 @@ example/low_level_random_agent ...@@ -74,6 +74,7 @@ example/low_level_random_agent
example/mid_level_move_agent example/mid_level_move_agent
example/mid_level_kick_agent example/mid_level_kick_agent
example/mid_level_dribble_agent example/mid_level_dribble_agent
example/communication_agent
# Dependency directories # Dependency directories
librcsc-prefix/ librcsc-prefix/
......
...@@ -41,7 +41,7 @@ if(BUILD_SOCCERWINDOW) ...@@ -41,7 +41,7 @@ if(BUILD_SOCCERWINDOW)
INSTALL_COMMAND "") INSTALL_COMMAND "")
ExternalProject_Get_Property(soccerwindow2 BINARY_DIR) ExternalProject_Get_Property(soccerwindow2 BINARY_DIR)
set(SOCCERWINDOW2_BINARY_DIR ${BINARY_DIR}/bin) set(SOCCERWINDOW2_BINARY_DIR ${BINARY_DIR}/bin)
install(DIRECTORY ${SOCCERWINDOW2_BINARY_DIR} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/ USE_SOURCE_PERMISSIONS) install(DIRECTORY ${SOCCERWINDOW2_BINARY_DIR} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} USE_SOURCE_PERMISSIONS)
endif() endif()
set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
...@@ -82,6 +82,12 @@ add_executable(sample_coach ${SOURCE_DIR}/main_coach.cpp ${SOURCE_DIR}/sample_co ...@@ -82,6 +82,12 @@ add_executable(sample_coach ${SOURCE_DIR}/main_coach.cpp ${SOURCE_DIR}/sample_co
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)
add_executable(agent ${SOURCE_DIR}/HFO.cpp ${SOURCE_DIR}/main_agent.cpp ${SOURCE_DIR}/agent.cpp) add_executable(agent ${SOURCE_DIR}/HFO.cpp ${SOURCE_DIR}/main_agent.cpp ${SOURCE_DIR}/agent.cpp)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/teams/base)
set_target_properties(sample_coach PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/teams/base)
set_target_properties(sample_player PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/teams/base)
set_target_properties(sample_trainer PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/teams/base)
set_target_properties(agent PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/teams/base)
add_library(hfo-lib SHARED ${SOURCE_DIR}/HFO.hpp ${SOURCE_DIR}/HFO.cpp) 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)
...@@ -126,8 +132,6 @@ add_executable(communication_agent ${CMAKE_CURRENT_SOURCE_DIR}/example/communica ...@@ -126,8 +132,6 @@ add_executable(communication_agent ${CMAKE_CURRENT_SOURCE_DIR}/example/communica
set_target_properties(communication_agent PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/example) set_target_properties(communication_agent PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/example)
target_link_libraries(communication_agent hfo-lib) target_link_libraries(communication_agent hfo-lib)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/example DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/ USE_SOURCE_PERMISSIONS) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/example DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} USE_SOURCE_PERMISSIONS)
install(DIRECTORY ${RCSSSERVER_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/bin DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} USE_SOURCE_PERMISSIONS)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/teams DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin USE_SOURCE_PERMISSIONS)
install(DIRECTORY ${RCSSSERVER_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/bin DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/ USE_SOURCE_PERMISSIONS)
...@@ -28,12 +28,14 @@ def launch(cmd, name = 'Unknown', necessary = True, supressOutput = True): ...@@ -28,12 +28,14 @@ def launch(cmd, name = 'Unknown', necessary = True, supressOutput = True):
necProcesses.append([p,name]) necProcesses.append([p,name])
return p return p
def main(args, team1='left', team2='right'): def main(args):
"""Sets up the teams, launches the server and monitor, starts the trainer. """Sets up the teams, launches the server and monitor, starts the trainer.
""" """
if args.logging and not os.path.exists(args.logDir): if args.logging and not os.path.exists(args.logDir):
os.makedirs(args.logDir) os.makedirs(args.logDir)
num_agents = args.offenseAgents + args.defenseAgents num_agents = args.offenseAgents + args.defenseAgents
team1 = args.offenseTeam
team2 = args.defenseTeam
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 + num_agents
coach_port = args.port + num_agents + 1 coach_port = args.port + num_agents + 1
...@@ -118,6 +120,10 @@ def parseArgs(): ...@@ -118,6 +120,10 @@ def parseArgs():
help='Number of offensive uncontrolled players. Default: 0.') help='Number of offensive uncontrolled players. Default: 0.')
p.add_argument('--defense-npcs', dest='defenseNPCs', type=int, default=0, p.add_argument('--defense-npcs', dest='defenseNPCs', type=int, default=0,
help='Number of defensive uncontrolled players. Default: 0.') help='Number of defensive uncontrolled players. Default: 0.')
p.add_argument('--offense-team', dest='offenseTeam', type=str, default='base',
help='Team name to pull offensive NPCs from. Options: {base, helios} Default: base.')
p.add_argument('--defense-team', dest='defenseTeam', type=str, default='base',
help='Team name to pull defensive NPCs from. Options: {base, helios} Default: base')
p.add_argument('--no-sync', dest='sync', action='store_false', default=True, p.add_argument('--no-sync', dest='sync', action='store_false', default=True,
help='Run server in non-sync mode.') help='Run server in non-sync mode.')
p.add_argument('--port', dest='port', type=int, default=6000, p.add_argument('--port', dest='port', type=int, default=6000,
......
#!/usr/bin/env python #!/usr/bin/env python
# encoding: utf-8 # encoding: utf-8
import sys, numpy, time, os, subprocess import sys, numpy, time, os, subprocess, teams
from Communicator import ClientCommunicator, TimeoutError from Communicator import ClientCommunicator, TimeoutError
class DoneError(Exception): class DoneError(Exception):
...@@ -51,36 +51,6 @@ class Trainer(object): ...@@ -51,36 +51,6 @@ class Trainer(object):
self._connectedPlayers = [] self._connectedPlayers = []
self.initMsgHandlers() self.initMsgHandlers()
def launch_npc(self, player_num, play_offense, wait_until_join=True):
"""Launches a player using sample_player binary
Returns a Popen process object
"""
print 'Launch npc %s-%d'%(self._offenseTeamName if play_offense
else self._defenseTeamName, player_num)
if play_offense:
team_name = self._offenseTeamName
else:
team_name = self._defenseTeamName
binary_dir = os.path.dirname(os.path.realpath(__file__))
config_dir = os.path.join(binary_dir, '../config/formations-dt')
player_conf = os.path.join(binary_dir, '../config/player.conf')
player_cmd = os.path.join(binary_dir, 'sample_player')
player_cmd += ' -t %s -p %i --config_dir %s ' \
' --log_dir %s --player-config %s' \
%(team_name, self._serverPort, config_dir,
self._logDir, player_conf)
if self._record:
player_cmd += ' --record'
if player_num == 1:
player_cmd += ' -g'
kwargs = {'stdout':open('/dev/null', 'w'),
'stderr':open('/dev/null', 'w')}
p = subprocess.Popen(player_cmd.split(' '), shell = False, **kwargs)
if wait_until_join:
self.waitOnPlayer(player_num, play_offense)
return p
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):
"""Launches a learning agent using the agent binary """Launches a learning agent using the agent binary
...@@ -105,9 +75,9 @@ class Trainer(object): ...@@ -105,9 +75,9 @@ class Trainer(object):
self._agentNumInt.append(internal_player_num) self._agentNumInt.append(internal_player_num)
numTeammates = self._numDefense - 1 numTeammates = self._numDefense - 1
numOpponents = self._numOffense numOpponents = self._numOffense
binary_dir = os.path.dirname(os.path.realpath(__file__)) 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') player_conf = os.path.join(binary_dir, '/config/player.conf')
agent_cmd = os.path.join(binary_dir, 'agent') agent_cmd = os.path.join(binary_dir, 'agent')
agent_cmd += ' -t %s -p %i --numTeammates %i --numOpponents %i' \ agent_cmd += ' -t %s -p %i --numTeammates %i --numOpponents %i' \
' --playingOffense %i --serverPort %i --log_dir %s' \ ' --playingOffense %i --serverPort %i --log_dir %s' \
...@@ -127,45 +97,46 @@ class Trainer(object): ...@@ -127,45 +97,46 @@ class Trainer(object):
self.waitOnPlayer(agent_ext_num, play_offense) self.waitOnPlayer(agent_ext_num, play_offense)
return p return p
def getDefensiveRoster(self, team_name):
"""Returns a list of player numbers on a given team that are thought
to prefer defense. This map is not set in stone as the players on
some teams can adapt and change their roles.
"""
if team_name == 'Borregos':
return [9,10,8,11,7,4,6,2,3,5]
elif team_name == 'WrightEagle':
return [5,2,8,9,10,6,3,11,4,7]
else:
return [2,3,4,5,6,7,8,11,9,10]
def getOffensiveRoster(self, team_name):
"""Returns a list of player numbers on a given team that are thought
to prefer offense. This map is not set in stone as the players on
some teams can adapt and change their roles.
"""
if team_name == 'Borregos':
return [2,4,6,5,3,7,9,10,8,11]
elif team_name == 'WrightEagle':
return [11,4,7,3,6,10,8,9,2,5]
else:
return [11,7,8,9,10,6,3,2,4,5]
def addTeam(self, team_name): def addTeam(self, team_name):
""" Adds a team to the team list""" """ Adds a team to the team list"""
self._teams.append(team_name) # Check whether team name valid, and map to a format acceptable to third party binary
nameMap = {'base':'base', 'helios':'HELIOS'}
if team_name not in nameMap.keys():
print 'Invalid team name: ', team_name
sys.exit(1)
# Create side specific team
if len(self._teams) == 0:
self._teams.append(nameMap[team_name] + '_left')
elif len(self._teams) == 1:
self._teams.append(nameMap[team_name] + '_right')
else:
print 'Too many teams added!'
sys.exit(1)
def createTeam(self, name):
teamDir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'teams')
if 'HELIOS' in name:
print 'Creating team HELIOS'
return teams.Helios(name, os.path.join(teamDir, 'helios', 'helios-13Eindhoven'), os.path.join(teamDir, 'helios', 'local', 'lib'), 'helios_player', host='localhost', port=self._serverPort)
elif 'base' in name:
print 'Creating team Agent2d (base)'
return teams.Agent2d(name, os.path.join(teamDir, 'base'), None, 'sample_player', self._logDir, self._record, host='localhost', port=self._serverPort)
else:
print 'Invalid team found'
sys.exit(1)
def setTeams(self): def getTeams(self):
""" Sets the offensive and defensive teams and player rosters. """ """ Sets the offensive and defensive teams and player rosters. """
self._offenseTeamInd = 0 self._offenseTeamInd = 0
self._offenseTeamName = self._teams[self._offenseTeamInd] self._offenseTeamName = self._teams[self._offenseTeamInd]
self._defenseTeamName = self._teams[1-self._offenseTeamInd] self._defenseTeamName = self._teams[1-self._offenseTeamInd]
offensive_roster = self.getOffensiveRoster(self._offenseTeamName) # set up offense
defensive_roster = self.getDefensiveRoster(self._defenseTeamName) offenseTeam = self.createTeam(self._offenseTeamName)
self._offenseOrder = [1] + offensive_roster # 1 for goalie self._offenseOrder = [1] + offenseTeam._offense_order # 1 for goalie
self._defenseOrder = [1] + defensive_roster # 1 for goalie # set up defense
defenseTeam = self.createTeam(self._defenseTeamName)
self._defenseOrder = [1] + defenseTeam._defense_order # 1 for goalie
return (offenseTeam, defenseTeam)
def teamToInd(self, team_name): def teamToInd(self, team_name):
""" Returns the index of a given team. """ """ Returns the index of a given team. """
...@@ -429,7 +400,7 @@ class Trainer(object): ...@@ -429,7 +400,7 @@ class Trainer(object):
def run(self, necProcesses): def run(self, necProcesses):
""" Run the trainer """ """ Run the trainer """
try: try:
self.setTeams() (offenseTeam, defenseTeam) = self.getTeams()
offense_unums = self._offenseOrder[1: self._numOffense + 1] offense_unums = self._offenseOrder[1: self._numOffense + 1]
sorted_offense_agent_unums = sorted(self._offenseOrder[1:self._offenseAgents+1]) sorted_offense_agent_unums = sorted(self._offenseOrder[1:self._offenseAgents+1])
defense_unums = self._defenseOrder[: self._numDefense] defense_unums = self._defenseOrder[: self._numDefense]
...@@ -446,7 +417,8 @@ class Trainer(object): ...@@ -446,7 +417,8 @@ class Trainer(object):
necProcesses.append([agent, 'offense_agent_' + str(agent_num)]) necProcesses.append([agent, 'offense_agent_' + str(agent_num)])
agent_num += 1 agent_num += 1
else: else:
player = self.launch_npc(player_num, play_offense=True) player = offenseTeam.launch_npc(player_num)
self.waitOnPlayer(player_num, True)
if player_num in offense_unums: if player_num in offense_unums:
self._npcPopen.append(player) self._npcPopen.append(player)
necProcesses.append([player, 'offense_npc_' + str(player_num)]) necProcesses.append([player, 'offense_npc_' + str(player_num)])
...@@ -464,7 +436,8 @@ class Trainer(object): ...@@ -464,7 +436,8 @@ class Trainer(object):
necProcesses.append([agent, 'defense_agent_' + str(agent_num)]) necProcesses.append([agent, 'defense_agent_' + str(agent_num)])
agent_num += 1 agent_num += 1
else: else:
player = self.launch_npc(player_num, play_offense=False) player = defenseTeam.launch_npc(player_num)
self.waitOnPlayer(player_num, False)
if player_num in defense_unums: if player_num in defense_unums:
self._npcPopen.append(player) self._npcPopen.append(player)
necProcesses.append([player, 'defense_npc_' + str(player_num)]) necProcesses.append([player, 'defense_npc_' + str(player_num)])
......
...@@ -8,8 +8,8 @@ echo " Copyright 2007-2012. Hidehisa Akiyama and Hiroki Shimora" ...@@ -8,8 +8,8 @@ echo " Copyright 2007-2012. Hidehisa Akiyama and Hiroki Shimora"
echo " All rights reserved." echo " All rights reserved."
echo "******************************************************************" echo "******************************************************************"
BINARY_DIR=`dirname $0` BINARY_DIR=`dirname $0`/teams/base
CONFIG_DIR=$BINARY_DIR/../config CONFIG_DIR=$BINARY_DIR/config
player="${BINARY_DIR}/sample_player" player="${BINARY_DIR}/sample_player"
coach="${BINARY_DIR}/sample_coach" coach="${BINARY_DIR}/sample_coach"
......
#!/bin/bash #!/bin/bash
BINARY_DIR=`dirname $0` #"$( cd "$( dirname "$0" )" && pwd )" BINARY_DIR=`dirname $0`/teams/base #"$( cd "$( dirname "$0" )" && pwd )"
CONFIG_DIR=$BINARY_DIR/../config CONFIG_DIR=$BINARY_DIR/config
player="${BINARY_DIR}/agent" player="${BINARY_DIR}/agent"
coach="${BINARY_DIR}/sample_coach" coach="${BINARY_DIR}/sample_coach"
......
#!/usr/bin/env python
# encoding: utf-8
import os, subprocess
class Team(object):
""" Abstract class. Handles launching players from 3rd party binaries.
"""
def __init__(self, name, binaryPath, libDir, options, offenseOrder, defenseOrder):
"""
Creates a team
name: name of the team
binaryPath: absolute path of the executable
libDir: library dependencies directory
options: team-specific parameters for executable in string format
offenseOrder: order to prioritize offensive unums (do not include 0)
defenseOrder: order to prioritize defensive unums (do not include 0)
"""
self._name = name
self._binary_path = binaryPath
self._lib_dir = libDir
self._options = options
self._offense_order = offenseOrder
self._defense_order = defenseOrder
def launch_npc(self, player_num):
"""
Abstract method that should be overrided by subclasses. Launches an npc with player number player_num.
The method that overrides this should call start_npc_process. See examples below.
"""
pass
def start_npc_proc(self, launchOpts=None):
"""Launches a player using the team-specific binary
launchOpts should be used to append player specific options
(e.g., helios uses '-g' to signify launching a goalie )
Returns a Popen process object
"""
player_cmd = self._binary_path
player_cmd += ' %s' % (self._options)
if launchOpts != None:
player_cmd += ' %s' % (launchOpts)
kwargs = {'stdout':open('/dev/null', 'w'),
'stderr':open('/dev/null', 'w')}
env = dict(os.environ)
if self._lib_dir != None:
env['LD_LIBRARY_PATH'] = self._lib_dir
p = subprocess.Popen(player_cmd.split(' '), env=env, shell = False, **kwargs)
return p
class Agent2d(Team):
def __init__(self, name, baseDir, libDir, binaryName, logDir, record, host='localhost', port=6000):
binaryPath = os.path.join(baseDir, binaryName)
options = '-t %s -p %i --config_dir %s/config/formations-dt --log_dir %s --player-config %s/config/player.conf' % (name, port, baseDir, logDir, baseDir)
if record:
options += ' --record'
offenseOrder = [11,7,8,9,10,6,3,2,4,5]
defenseOrder = [2,3,4,5,6,7,8,11,9,10]
super(Agent2d, self).__init__(name, binaryPath, libDir, options, offenseOrder, defenseOrder)
def launch_npc(self, player_num):
launchOpts = None
if player_num == 1:
launchOpts = '-g'
print 'Launch npc %s-%d' % (self._name, player_num)
return self.start_npc_proc(launchOpts)
class Helios(Team):
def __init__(self, name, baseDir, libDir, binaryName, host='localhost', port=6000):
binaryPath = os.path.join(baseDir, binaryName)
options = '--player-config %s/player.conf -h %s -t %s --formation-conf-dir %s/data/formations --role-conf %s/data/role.conf --ball-table %s/data/ball_table.dat --chain-search-method BestFirstSearch --evaluator-name Default --max-chain-length 4 --max-evaluate-size 1000 --sirm-evaluator-param-dir %s/data/sirm_evaluator/ --goalie-position-dir %s/data/goalie_position/ --intercept-conf-dir %s/data/intercept_probability/ --opponent-data-dir %s/data/opponent_data/ -p %d' % (baseDir, host, name, baseDir, baseDir, baseDir, baseDir, baseDir, baseDir, baseDir, port)
offenseOrder = [11,7,8,9,10,6,3,2,4,5]
defenseOrder = [2,3,4,5,6,7,8,11,9,10]
super(Helios, self).__init__(name, binaryPath, libDir, options, offenseOrder, defenseOrder)
def launch_npc(self, player_num):
launchOpts = None
if player_num == 1:
launchOpts = '-g'
print 'Launch npc %s-%d' % (self._name, player_num)
return self.start_npc_proc(launchOpts)
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