File LGPAgent.hpp
File List > Agents > GP > LGPAgent.hpp
Go to the documentation of this file
#pragma once
#include <vector>
#include <string>
#include <iostream>
#include <random>
#include <algorithm>
#include "../../core/AgentBase.hpp"
#include "GPAgentSensors.hpp"
#include "./GPAgentBase.hpp"
namespace cowboys
{
const int LISTSIZE = 100;
class LGPAgent : public GPAgentBase
{
protected:
// A dictionary of actions and a dictionary of sensors
// A sensor is a function that takes in a grid and returns a value (e.g. distance to left wall)
std::vector<std::string> possibleInstructionsList = {};
std::vector<std::string> actionsList = {};
std::vector<std::string> operationsList = {"lessthan", "greaterthan", "equals"};
std::vector<std::string> sensorsNamesList = {"getLeft", "getRight", "getUp", "getDown"};
// A list that stores the results of executed instructions
std::vector<int> resultsList;
std::vector<std::tuple<std::string, int, int>> instructionsList = {};
size_t currentInstructionIndex = 0;
std::random_device rd;
std::mt19937 gen;
public:
LGPAgent(size_t id, const std::string &name) : GPAgentBase(id, name)
{
gen = std::mt19937(rd());
for (auto i = 0; i < LISTSIZE; i++)
{
resultsList.push_back(0);
}
}
bool Initialize() override
{
possibleInstructionsList = EncodeActions(action_map, sensorsNamesList, operationsList, actionsList);
GenerateRandomActionList();
return true;
}
void GenerateRandomActionList()
{
std::uniform_int_distribution<size_t> dist(0, possibleInstructionsList.size() - 1);
std::uniform_int_distribution<size_t> dist2(0, LISTSIZE - 1);
for (int i = 0; i < LISTSIZE; i++)
{
instructionsList.push_back(std::make_tuple(possibleInstructionsList[dist(gen)], dist2(gen), dist2(gen)));
}
}
static std::vector<std::string> EncodeActions(const std::unordered_map<std::string, size_t> &action_map, const std::vector<std::string> &sensorsNamesList,
const std::vector<std::string> &operationsList, std::vector<std::string> &actionsList)
{
std::vector<std::string> instructions;
for (const auto &[action_name, action_id] : action_map)
{
instructions.push_back(action_name);
actionsList.push_back(action_name);
}
for (const auto &sensor : operationsList)
{
instructions.push_back(sensor);
}
for (const auto &sensor : sensorsNamesList)
{
instructions.push_back(sensor);
}
return instructions;
}
void MutateAgent(double mutation_rate = 0.01) override
{
std::uniform_int_distribution<size_t> rnd_mutate(1, 100);
std::uniform_int_distribution<size_t> dist(0, possibleInstructionsList.size() - 1);
std::uniform_int_distribution<size_t> dist2(0, LISTSIZE - 1);
for (auto i = 0; i < LISTSIZE; i++)
{
if (rnd_mutate(gen) / 100.0 <= mutation_rate)
{
instructionsList[i] = std::make_tuple(possibleInstructionsList[dist(gen)], dist2(gen), dist2(gen));
}
}
resultsList.clear();
resultsList.resize(LISTSIZE);
currentInstructionIndex = 0;
}
const std::vector<std::tuple<std::string, int, int>> &GetInstructionsList(){ return instructionsList; }
void Configure(const LGPAgent &other) {
instructionsList = other.instructionsList;
possibleInstructionsList = other.possibleInstructionsList;
actionsList = other.actionsList;
operationsList = other.operationsList;
sensorsNamesList = other.sensorsNamesList;
resultsList = other.resultsList;
currentInstructionIndex = other.currentInstructionIndex;
}
void Copy(const GPAgentBase &other) override
{
assert(dynamic_cast<const LGPAgent *>(&other) != nullptr);
Configure(dynamic_cast<const LGPAgent &>(other));
}
size_t GetAction([[maybe_unused]] const cse491::WorldGrid &grid,
[[maybe_unused]] const cse491::type_options_t &type_options,
[[maybe_unused]] const cse491::item_map_t &item_set,
[[maybe_unused]] const cse491::agent_map_t &agent_set) override
{
std::string action;
std::string sensor;
std::string operation;
auto instruction = instructionsList[currentInstructionIndex];
int i = 0;
if (currentInstructionIndex != 0)
{
resultsList[currentInstructionIndex - 1] = action_result;
}
else
{
resultsList[LISTSIZE - 1] = action_result;
}
while (i < LISTSIZE * 2 && action.empty())
{
if (std::find(actionsList.begin(), actionsList.end(), std::get<0>(instruction)) != actionsList.end())
{
// the instruction is in the action list (provided by the world)
action = std::get<0>(instruction);
}
else if (std::find(sensorsNamesList.begin(), sensorsNamesList.end(), std::get<0>(instruction)) != sensorsNamesList.end())
{
// the instruction is in the sensor list (getLeft, getRight, getUp, getDown)
sensor = std::get<0>(instruction);
SensorDirection direction = Sensors::getSensorDirectionEnum(sensor);
int distance = Sensors::wallDistance(grid, *this, direction);
resultsList[currentInstructionIndex] = distance;
}
else
{
// the instruction is an operation (lessthan, greaterthan, equals)
operation = std::get<0>(instruction);
if (operation == "lessthan")
{
if (std::get<1>(instruction) < std::get<2>(instruction))
{
resultsList[currentInstructionIndex] = 1;
}
else
{
resultsList[currentInstructionIndex] = 0;
++currentInstructionIndex;
}
}
else if (operation == "greaterthan")
{
if (std::get<1>(instruction) > std::get<2>(instruction))
{
resultsList[currentInstructionIndex] = 1;
}
else
{
resultsList[currentInstructionIndex] = 0;
++currentInstructionIndex;
}
}
else if (operation == "equals")
{
if (std::get<1>(instruction) == std::get<2>(instruction))
{
resultsList[currentInstructionIndex] = 1;
}
else
{
resultsList[currentInstructionIndex] = 0;
++currentInstructionIndex;
}
}
}
++currentInstructionIndex;
if (currentInstructionIndex >= LISTSIZE)
{
currentInstructionIndex = 0;
}
++i;
instruction = instructionsList[currentInstructionIndex];
}
if (!action.empty())
{
return action_map[action];
}
return 0;
}
std::string Export() override {
std::string encodedLists = "";
for (auto instruction : instructionsList)
{
encodedLists += std::get<0>(instruction);
encodedLists += ".";
encodedLists += std::to_string(std::get<1>(instruction));
encodedLists += ".";
encodedLists += std::to_string(std::get<2>(instruction));
encodedLists += ",";
}
encodedLists += ";";
for (auto possInstruction : possibleInstructionsList)
{
encodedLists += possInstruction;
encodedLists += ".";
}
encodedLists += ";";
for (auto action : actionsList)
{
encodedLists += action;
encodedLists += ".";
}
return encodedLists;
}
void SerializeGP(tinyxml2::XMLDocument & doc, tinyxml2::XMLElement* parentElem, double fitness = -1) override
{
auto agentElem = doc.NewElement("LGPAgent");
parentElem->InsertEndChild(agentElem);
auto listElem = doc.NewElement("instruction list");
listElem->SetText(Export().c_str());
if (fitness != -1)
listElem->SetAttribute("fitness", fitness);
agentElem->InsertEndChild(listElem);
}
void Import(const std::string & encodedLists) override {
std::vector<std::tuple<std::string, int, int>> decodedInstructionsList = {};
std::string decodedInstruction;
size_t start_pos = 0;
size_t first_period_pos;
size_t second_period_pos;
size_t comma_pos = encodedLists.find(",");
// Load the instruction list
while (comma_pos != std::string::npos) {
decodedInstruction = encodedLists.substr(start_pos, comma_pos - start_pos);
first_period_pos = decodedInstruction.find(".");
second_period_pos = decodedInstruction.find(".", first_period_pos + 1);
decodedInstructionsList.push_back(std::make_tuple(decodedInstruction.substr(0, first_period_pos),
std::stoi(decodedInstruction.substr(first_period_pos+1, second_period_pos-first_period_pos+1)), std::stoi(decodedInstruction.substr(second_period_pos+1))));
start_pos = comma_pos + 1;
comma_pos = encodedLists.find(",", start_pos);
}
std::vector<std::string> decodedPossInstructionsList = {};
std::vector<std::string> decodedActionsList = {};
size_t first_semicolon_pos = encodedLists.find(";");
size_t second_semicolon_pos = encodedLists.find(";", first_semicolon_pos+1);
std::string unseparated_instruction_list = encodedLists.substr(first_semicolon_pos+1, second_semicolon_pos-first_semicolon_pos+1);
std::string unseparated_action_list = encodedLists.substr(second_semicolon_pos+1);
// Load the list of possible instructions
size_t period_pos = unseparated_instruction_list.find(".");
start_pos = 0;
while (period_pos != std::string::npos) {
decodedPossInstructionsList.push_back(unseparated_instruction_list.substr(start_pos, period_pos));
start_pos = period_pos + 1;
period_pos = encodedLists.find(".", start_pos);
}
// Load the list of actions
period_pos = unseparated_action_list.find(".");
start_pos = 0;
while (period_pos != std::string::npos) {
decodedActionsList.push_back(unseparated_action_list.substr(start_pos, period_pos));
start_pos = period_pos + 1;
period_pos = encodedLists.find(".", start_pos);
}
instructionsList = decodedInstructionsList;
possibleInstructionsList = decodedPossInstructionsList;
actionsList = decodedActionsList;
resultsList.clear();
resultsList.resize(LISTSIZE);
currentInstructionIndex = 0;
}
void PrintAgent() override {
for (auto i = 0; i < LISTSIZE; i++)
{
std::cout << std::get<0>(instructionsList[i]) << " ";
}
std::cout << std::endl;
}
};
}