Commit 41b577db authored by Matthew Hausknecht's avatar Matthew Hausknecht

Encapsulated hfo interface in a namespace.

parent 5aa73777
......@@ -35,7 +35,7 @@ list(APPEND LINK_LIBS
)
add_executable(sample_coach ${SOURCE_DIR}/main_coach.cpp ${SOURCE_DIR}/sample_coach.cpp ${SOURCES})
add_executable(sample_player ${SOURCE_DIR}/main_player.cpp ${SOURCE_DIR}/sample_player.cpp ${SOURCES} ${SOURCE_DIR}/agent.cpp)
add_executable(sample_player ${SOURCE_DIR}/HFO.cpp ${SOURCE_DIR}/main_player.cpp ${SOURCE_DIR}/sample_player.cpp ${SOURCES})
add_executable(sample_trainer ${SOURCE_DIR}/main_trainer.cpp ${SOURCE_DIR}/sample_trainer.cpp ${SOURCES})
add_executable(agent ${SOURCE_DIR}/main_agent.cpp ${SOURCE_DIR}/agent.cpp ${SOURCES})
add_library(hfo-lib SHARED ${SOURCE_DIR}/HFO.hpp ${SOURCE_DIR}/HFO.cpp)
......
......@@ -4,23 +4,25 @@
#include <cstdlib>
using namespace std;
using namespace hfo;
// First Start the server: $> bin/start.py
// Before running this program, first Start HFO server:
// $./bin/start.py --offense-agents 1
int main() {
// Create the HFO environment
HFOEnvironment hfo;
// Connect the agent's server on the given port with the given
// feature set. See possible feature sets in src/HFO.hpp.
// Connect to the agent's server on port 6000 and request low-level
// feature set. See manual for more information on feature sets.
hfo.connectToAgentServer(6000, LOW_LEVEL_FEATURE_SET);
// Play 5 episodes
for (int episode=0; episode<5; episode++) {
hfo_status_t status = IN_GAME;
status_t status = IN_GAME;
while (status == IN_GAME) {
// Grab the vector of state features for the current state
// Get the vector of state features for the current state
const std::vector<float>& feature_vec = hfo.getState();
// Create a dash action
Action a = {DASH, 0., 0.};
Action a = {DASH, 0.0, 0.0};
// Perform the dash and recieve the current game status
status = hfo.act(a);
}
......
......@@ -11,8 +11,43 @@
#include <iostream>
#include <sstream>
bool HFOEnvironment::ParseHFOConfig(const std::string& message,
HFO_Config& config) {
using namespace hfo;
std::string HFOEnvironment::ActionToString(Action action) {
std::stringstream ss;
switch (action.action) {
case DASH:
ss << "Dash(" << action.arg1 << "," << action.arg2 << ")";
break;
case TURN:
ss << "Turn(" << action.arg1 << ")";
break;
case TACKLE:
ss << "Tackle(" << action.arg1 << ")";
break;
case KICK:
ss << "Kick(" << action.arg1 << "," << action.arg2 << ")";
break;
case MOVE:
ss << "Move";
break;
case SHOOT:
ss << "Shoot";
break;
case PASS:
ss << "Pass";
break;
case DRIBBLE:
ss << "Dribble";
break;
case QUIT:
ss << "Quit";
break;
}
return ss.str();
};
bool HFOEnvironment::ParseConfig(const std::string& message, Config& config) {
config.num_offense = -1;
config.num_defense = -1;
std::istringstream iss(message);
......@@ -56,19 +91,15 @@ bool HFOEnvironment::ParseHFOConfig(const std::string& message,
return true;
};
void error(const char *msg) {
perror(msg);
exit(0);
}
HFOEnvironment::HFOEnvironment() {}
HFOEnvironment::~HFOEnvironment() {
// Send a quit action and close the connection to the agent's server
action_t quit = QUIT;
if (send(sockfd, &quit, sizeof(int), 0) < 0) {
error("[Agent Client] ERROR sending from socket");
perror("[Agent Client] ERROR sending from socket");
}
close(sockfd);
exit(1);
}
void HFOEnvironment::connectToAgentServer(int server_port,
......@@ -77,12 +108,13 @@ void HFOEnvironment::connectToAgentServer(int server_port,
<< server_port << std::endl;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
error("ERROR opening socket");
perror("ERROR opening socket");
exit(1);
}
struct hostent *server = gethostbyname("localhost");
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
exit(1);
}
struct sockaddr_in serv_addr;
bzero((char *) &serv_addr, sizeof(serv_addr));
......@@ -99,14 +131,18 @@ void HFOEnvironment::connectToAgentServer(int server_port,
retry--;
}
if (status < 0) {
error("[Agent Client] ERROR Unable to communicate with server");
perror("[Agent Client] ERROR Unable to communicate with server");
close(sockfd);
exit(1);
}
std::cout << "[Agent Client] Connected" << std::endl;
handshakeAgentServer(feature_set);
// Get the initial game state
feature_vec.resize(numFeatures);
if (recv(sockfd, &(feature_vec.front()), numFeatures*sizeof(float), 0) < 0) {
error("[Agent Client] ERROR recieving state features from socket");
perror("[Agent Client] ERROR recieving state features from socket");
close(sockfd);
exit(1);
}
}
......@@ -114,35 +150,50 @@ void HFOEnvironment::handshakeAgentServer(feature_set_t feature_set) {
// Recieve float 123.2345
float f;
if (recv(sockfd, &f, sizeof(float), 0) < 0) {
error("[Agent Client] ERROR recv from socket");
perror("[Agent Client] ERROR recv from socket");
close(sockfd);
exit(1);
}
// Check that error is within bounds
if (abs(f - 123.2345) > 1e-4) {
error("[Agent Client] Handshake failed. Improper float recieved.");
perror("[Agent Client] Handshake failed. Improper float recieved.");
close(sockfd);
exit(1);
}
// Send float 5432.321
f = 5432.321;
if (send(sockfd, &f, sizeof(float), 0) < 0) {
error("[Agent Client] ERROR sending from socket");
perror("[Agent Client] ERROR sending from socket");
close(sockfd);
exit(1);
}
// Send the feature set request
if (send(sockfd, &feature_set, sizeof(int), 0) < 0) {
error("[Agent Client] ERROR sending from socket");
perror("[Agent Client] ERROR sending from socket");
close(sockfd);
exit(1);
}
// Recieve the number of features
if (recv(sockfd, &numFeatures, sizeof(int), 0) < 0) {
error("[Agent Client] ERROR recv from socket");
perror("[Agent Client] ERROR recv from socket");
close(sockfd);
exit(1);
}
if (send(sockfd, &numFeatures, sizeof(int), 0) < 0) {
error("[Agent Client] ERROR sending from socket");
perror("[Agent Client] ERROR sending from socket");
close(sockfd);
exit(1);
}
// Recieve the game status
hfo_status_t status;
if (recv(sockfd, &status, sizeof(hfo_status_t), 0) < 0) {
error("[Agent Client] ERROR recv from socket");
status_t status;
if (recv(sockfd, &status, sizeof(status_t), 0) < 0) {
perror("[Agent Client] ERROR recv from socket");
close(sockfd);
exit(1);
}
if (status != IN_GAME) {
std::cout << "[Agent Client] Handshake failed: status check." << std::endl;
close(sockfd);
exit(1);
}
std::cout << "[Agent Client] Handshake complete" << std::endl;
......@@ -152,19 +203,25 @@ const std::vector<float>& HFOEnvironment::getState() {
return feature_vec;
}
hfo_status_t HFOEnvironment::act(Action action) {
hfo_status_t game_status;
status_t HFOEnvironment::act(Action action) {
status_t game_status;
// Send the action
if (send(sockfd, &action, sizeof(Action), 0) < 0) {
error("[Agent Client] ERROR sending from socket");
perror("[Agent Client] ERROR sending from socket");
close(sockfd);
exit(1);
}
// Get the game status
if (recv(sockfd, &game_status, sizeof(hfo_status_t), 0) < 0) {
error("[Agent Client] ERROR recieving from socket");
if (recv(sockfd, &game_status, sizeof(status_t), 0) < 0) {
perror("[Agent Client] ERROR recieving from socket");
close(sockfd);
exit(1);
}
// Get the next game state
if (recv(sockfd, &(feature_vec.front()), numFeatures*sizeof(float), 0) < 0) {
error("[Agent Client] ERROR recieving state features from socket");
perror("[Agent Client] ERROR recieving state features from socket");
close(sockfd);
exit(1);
}
return game_status;
}
......@@ -4,6 +4,8 @@
#include <string>
#include <vector>
namespace hfo {
// For descriptions of the different feature sets see
// https://github.com/mhauskn/HFO/blob/master/doc/manual.pdf
enum feature_set_t
......@@ -26,25 +28,27 @@ enum action_t
QUIT // Special action to quit the game
};
// The current status of the HFO game
enum hfo_status_t
{
IN_GAME,
GOAL,
CAPTURED_BY_DEFENSE,
OUT_OF_BOUNDS,
OUT_OF_TIME
};
// 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
};
// Configuration of the HFO domain including the team names and player
// numbers for each team. This can be populated by ParseHFOConfig().
struct HFO_Config {
// 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
......@@ -53,15 +57,17 @@ struct HFO_Config {
std::vector<int> defense_nums; // Defensive player numbers
};
class HFOEnvironment {
public:
HFOEnvironment();
~HFOEnvironment();
// Parse a message sent from Trainer to construct an HFO config.
// Returns a bool indicating if the struct was correctly parsed.
static bool ParseHFOConfig(const std::string& message, HFO_Config& config);
// Returns a string representation of an action.
static std::string ActionToString(Action action);
// Parse a Trainer message to populate config. Returns a bool
// indicating if the struct was correctly parsed.
static bool ParseConfig(const std::string& message, Config& config);
// Connect to the server that controls the agent on the specified port.
void connectToAgentServer(int server_port=6000,
......@@ -71,7 +77,7 @@ class HFOEnvironment {
const std::vector<float>& getState();
// Take an action and recieve the resulting game status
hfo_status_t act(Action action);
status_t act(Action action);
protected:
int numFeatures; // The number of features in this domain
......@@ -83,4 +89,5 @@ class HFOEnvironment {
virtual void handshakeAgentServer(feature_set_t feature_set);
};
} // namespace hfo
#endif
......@@ -29,7 +29,6 @@
#endif
#include "agent.h"
#include "HFO.cpp"
#include "strategy.h"
#include "field_analyzer.h"
......@@ -108,21 +107,7 @@
#include <netinet/in.h>
using namespace rcsc;
// Debugging tools to check for proper feature normalization
float min_feat_val = 1e8;
float max_feat_val = -1e8;
// Minimium and feature values
#define FEAT_MIN -1.
#define FEAT_MAX 1.
#define LOG_FEATURE(val) \
if (val <= min_feat_val) \
min_feat_val = val; \
if (val >= max_feat_val) \
max_feat_val = val; \
std::cout << "FEATURE " << val << " [" << min_feat_val << ", " << max_feat_val << "]" << std::endl;
using namespace hfo;
Agent::Agent()
: PlayerAgent(),
......@@ -250,21 +235,25 @@ void Agent::startServer(int server_port) {
struct sockaddr_in serv_addr, cli_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
error("[Agent Server] ERROR opening socket");
perror("[Agent Server] ERROR opening socket");
exit(1);
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(server_port);
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
error("[Agent Server] ERROR on binding");
perror("[Agent Server] ERROR on binding");
exit(1);
}
listen(sockfd, 5);
socklen_t clilen = sizeof(cli_addr);
std::cout << "[Agent Server] Waiting for client to connect... " << std::endl;
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0) {
error("[Agent Server] ERROR on accept");
perror("[Agent Server] ERROR on accept");
close(sockfd);
exit(1);
}
std::cout << "[Agent Server] Connected" << std::endl;
server_running = true;
......@@ -274,20 +263,28 @@ void Agent::clientHandshake() {
// Send float 123.2345
float f = 123.2345;
if (send(newsockfd, &f, sizeof(float), 0) < 0) {
error("[Agent Server] ERROR sending from socket");
perror("[Agent Server] ERROR sending from socket");
close(sockfd);
exit(1);
}
// Recieve float 5432.321
if (recv(newsockfd, &f, sizeof(float), 0) < 0) {
error("[Agent Server] ERROR recv from socket");
perror("[Agent Server] ERROR recv from socket");
close(sockfd);
exit(1);
}
// Check that error is within bounds
if (abs(f - 5432.321) > 1e-4) {
error("[Agent Server] Handshake failed. Improper float recieved.");
perror("[Agent Server] Handshake failed. Improper float recieved.");
close(sockfd);
exit(1);
}
// Recieve the feature set to use
feature_set_t feature_set;
hfo::feature_set_t feature_set;
if (recv(newsockfd, &feature_set, sizeof(int), 0) < 0) {
error("[Agent Server] ERROR recv from socket");
perror("[Agent Server] PERROR recv from socket");
close(sockfd);
exit(1);
}
// Create the corresponding FeatureExtractor
if (feature_extractor != NULL) {
......@@ -299,15 +296,21 @@ void Agent::clientHandshake() {
int numFeatures = feature_extractor->getNumFeatures();
assert(numFeatures > 0);
if (send(newsockfd, &numFeatures, sizeof(int), 0) < 0) {
error("[Agent Server] ERROR sending from socket");
perror("[Agent Server] ERROR sending from socket");
close(sockfd);
exit(1);
}
// Check that client has recieved correctly
int client_response = -1;
if (recv(newsockfd, &client_response, sizeof(int), 0) < 0) {
error("[Agent Server] ERROR recv from socket");
perror("[Agent Server] ERROR recv from socket");
close(sockfd);
exit(1);
}
if (client_response != numFeatures) {
error("[Agent Server] Client incorrectly parsed the number of features.");
perror("[Agent Server] Client incorrectly parsed the number of features.");
close(sockfd);
exit(1);
}
std::cout << "[Agent Server] Handshake complete" << std::endl;
}
......@@ -332,9 +335,9 @@ FeatureExtractor* Agent::getFeatureExtractor(feature_set_t feature_set_indx,
}
}
hfo_status_t Agent::getGameStatus(const rcsc::AudioSensor& audio_sensor,
status_t Agent::getGameStatus(const rcsc::AudioSensor& audio_sensor,
long& lastTrainerMessageTime) {
hfo_status_t game_status = IN_GAME;
status_t game_status = IN_GAME;
if (audio_sensor.trainerMessageTime().cycle() > lastTrainerMessageTime) {
const std::string& message = audio_sensor.trainerMessage();
bool recognized_message = true;
......@@ -367,9 +370,11 @@ void Agent::actionImpl() {
}
// Update and send the game status
hfo_status_t game_status = getGameStatus(audioSensor(), lastTrainerMessageTime);
status_t game_status = getGameStatus(audioSensor(), lastTrainerMessageTime);
if (send(newsockfd, &game_status, sizeof(int), 0) < 0) {
error("[Agent Server] ERROR sending from socket");
perror("[Agent Server] ERROR sending from socket");
close(sockfd);
exit(1);
}
// Update and send the state features
......@@ -386,13 +391,16 @@ void Agent::actionImpl() {
if (send(newsockfd, &(features.front()),
features.size() * sizeof(float), 0) < 0) {
error("[Agent Server] ERROR sending state features from socket");
perror("[Agent Server] ERROR sending state features from socket");
exit(1);
}
// Get the action
Action action;
if (recv(newsockfd, &action, sizeof(Action), 0) < 0) {
error("[Agent Server] ERROR recv from socket");
perror("[Agent Server] ERROR recv from socket");
close(sockfd);
exit(1);
}
switch(action.action) {
case DASH:
......@@ -421,10 +429,12 @@ void Agent::actionImpl() {
break;
case QUIT:
std::cout << "[Agent Server] Got quit from agent." << std::endl;
close(sockfd);
exit(0);
default:
std::cerr << "[Agent Server] ERROR Unsupported Action: "
<< action.action << std::endl;
close(sockfd);
exit(1);
}
......
......@@ -43,11 +43,11 @@ public:
virtual FieldEvaluator::ConstPtr getFieldEvaluator() const;
// Get the current game status
static hfo_status_t getGameStatus(const rcsc::AudioSensor& audio_sensor,
static hfo::status_t getGameStatus(const rcsc::AudioSensor& audio_sensor,
long& lastTrainerMessageTime);
// Returns the feature extractor corresponding to the feature_set_t
static FeatureExtractor* getFeatureExtractor(feature_set_t feature_set,
static FeatureExtractor* getFeatureExtractor(hfo::feature_set_t feature_set,
int num_teammates,
int num_opponents,
bool playing_offense);
......
......@@ -233,7 +233,7 @@ bool SamplePlayer::getHFOConfig() {
const AudioSensor& audio_sensor = audioSensor();
if (audio_sensor.trainerMessageTime().cycle() > lastTrainerMessageTime) {
const std::string& message = audio_sensor.trainerMessage();
if (HFOEnvironment::ParseHFOConfig(message, hfo_config)) {
if (hfo::HFOEnvironment::ParseConfig(message, hfo_config)) {
lastTrainerMessageTime = audio_sensor.trainerMessageTime().cycle();
if (config().teamName().compare(hfo_config.offense_team_name) == 0) {
playing_offense = true;
......
......@@ -102,7 +102,7 @@ protected:
// Listens for a HFO Config message
bool getHFOConfig();
HFO_Config hfo_config;
hfo::Config hfo_config;
FeatureExtractor* feature_extractor;
long lastTrainerMessageTime;
int num_teammates, num_opponents;
......
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