HFO.cpp 7.34 KB
Newer Older
1 2 3 4 5 6 7 8
#include "HFO.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
9
#include <assert.h>
10 11
#include <netdb.h>
#include <iostream>
12 13
#include <sstream>

14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
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();
};

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
int HFOEnvironment::NumParams(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 NOOP:
     return 0;
   case QUIT:
     return 0;
 }
 std::cerr << "Unrecognized Action: " << action;
 return -1;
}

85
bool HFOEnvironment::ParseConfig(const std::string& message, Config& config) {
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
  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;
};
128 129 130

HFOEnvironment::HFOEnvironment() {}
HFOEnvironment::~HFOEnvironment() {
131 132 133
  // 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) {
134
    perror("[Agent Client] ERROR sending from socket");
135
  }
136
  close(sockfd);
137
  exit(1);
138 139
}

140 141
void HFOEnvironment::connectToAgentServer(int server_port,
                                          feature_set_t feature_set) {
142 143 144 145
  std::cout << "[Agent Client] Connecting to Agent Server on port "
            << server_port << std::endl;
  sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if (sockfd < 0) {
146 147
    perror("ERROR opening socket");
    exit(1);
148 149 150 151
  }
  struct hostent *server = gethostbyname("localhost");
  if (server == NULL) {
    fprintf(stderr,"ERROR, no such host\n");
152
    exit(1);
153 154 155 156 157 158 159 160 161
  }
  struct sockaddr_in serv_addr;
  bzero((char *) &serv_addr, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  bcopy((char *)server->h_addr,
        (char *)&serv_addr.sin_addr.s_addr,
        server->h_length);
  serv_addr.sin_port = htons(server_port);
  int status = -1;
162 163
  int retry = 10;
  while (status < 0 && retry > 0) {
164 165
    status = connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr));
    sleep(1);
166 167 168
    retry--;
  }
  if (status < 0) {
169 170 171
    perror("[Agent Client] ERROR Unable to communicate with server");
    close(sockfd);
    exit(1);
172 173
  }
  std::cout << "[Agent Client] Connected" << std::endl;
174
  handshakeAgentServer(feature_set);
175 176 177
  // Get the initial game state
  feature_vec.resize(numFeatures);
  if (recv(sockfd, &(feature_vec.front()), numFeatures*sizeof(float), 0) < 0) {
178 179 180
    perror("[Agent Client] ERROR recieving state features from socket");
    close(sockfd);
    exit(1);
181
  }
182 183
}

184
void HFOEnvironment::handshakeAgentServer(feature_set_t feature_set) {
185 186 187
  // Recieve float 123.2345
  float f;
  if (recv(sockfd, &f, sizeof(float), 0) < 0) {
188 189 190
    perror("[Agent Client] ERROR recv from socket");
    close(sockfd);
    exit(1);
191 192 193
  }
  // Check that error is within bounds
  if (abs(f - 123.2345) > 1e-4) {
194 195 196
    perror("[Agent Client] Handshake failed. Improper float recieved.");
    close(sockfd);
    exit(1);
197 198 199 200
  }
  // Send float 5432.321
  f = 5432.321;
  if (send(sockfd, &f, sizeof(float), 0) < 0) {
201 202 203
    perror("[Agent Client] ERROR sending from socket");
    close(sockfd);
    exit(1);
204
  }
205 206
  // Send the feature set request
  if (send(sockfd, &feature_set, sizeof(int), 0) < 0) {
207 208 209
    perror("[Agent Client] ERROR sending from socket");
    close(sockfd);
    exit(1);
210
  }
211 212
  // Recieve the number of features
  if (recv(sockfd, &numFeatures, sizeof(int), 0) < 0) {
213 214 215
    perror("[Agent Client] ERROR recv from socket");
    close(sockfd);
    exit(1);
216 217
  }
  if (send(sockfd, &numFeatures, sizeof(int), 0) < 0) {
218 219 220
    perror("[Agent Client] ERROR sending from socket");
    close(sockfd);
    exit(1);
221
  }
222
  // Recieve the game status
223 224 225 226 227
  status_t status;
  if (recv(sockfd, &status, sizeof(status_t), 0) < 0) {
    perror("[Agent Client] ERROR recv from socket");
    close(sockfd);
    exit(1);
228 229 230
  }
  if (status != IN_GAME) {
    std::cout << "[Agent Client] Handshake failed: status check." << std::endl;
231
    close(sockfd);
232 233
    exit(1);
  }
234 235 236 237 238 239 240
  std::cout << "[Agent Client] Handshake complete" << std::endl;
}

const std::vector<float>& HFOEnvironment::getState() {
  return feature_vec;
}

241
status_t HFOEnvironment::act(action_t action, ...) {
242
  status_t game_status;
243 244
  // Send the action_type
  if (send(sockfd, &action, sizeof(action_t), 0) < 0) {
245 246 247
    perror("[Agent Client] ERROR sending from socket");
    close(sockfd);
    exit(1);
248
  }
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
  // Send the arguments
  int n_args = NumParams(action);
  if (n_args > 0) {
    float params[n_args];
    va_list vl;
    va_start(vl, n_args);
    for (int i = 0; i < n_args; ++i) {
      params[i] = va_arg(vl, double);
    }
    va_end(vl);
    // Send the arguments
    if (send(sockfd, &params, sizeof(float) * n_args, 0) < 0) {
      perror("[Agent Client] ERROR sending from socket");
      close(sockfd);
      exit(1);
    }
  }
266
  // Get the game status
267 268 269 270
  if (recv(sockfd, &game_status, sizeof(status_t), 0) < 0) {
    perror("[Agent Client] ERROR recieving from socket");
    close(sockfd);
    exit(1);
271
  }
272 273
  // Get the next game state
  if (recv(sockfd, &(feature_vec.front()), numFeatures*sizeof(float), 0) < 0) {
274 275 276
    perror("[Agent Client] ERROR recieving state features from socket");
    close(sockfd);
    exit(1);
277
  }
278
  return game_status;
279
}