#include "Strategy.hpp" Strategy::Strategy(const std::vector<std::string_view> & lines) { if (!util::doIfNameMatch(std::regex("Strategy : ((incremental)|(sequential))"), lines[0], [this](auto sm) {type = sm[1] == "sequential" ? Type::Sequential : Type::Incremental;})) util::myThrow(fmt::format("Invalid strategy identifier '{}'", lines[0])); for (unsigned int i = 1; i < lines.size(); i++) { auto splited = util::split(lines[i], ' '); std::pair<std::string, std::string> key; std::string value; int movement; if (splited.size() == 3) { key = std::pair<std::string,std::string>(splited[0], ""); value = splited[1]; movement = std::stoi(std::string(splited[2])); if (defaultCycle.empty()) initialState = splited[0]; defaultCycle.emplace_back(value); } else if (splited.size() == 4) { key = std::pair<std::string,std::string>(splited[0], splited[2]); value = splited[1]; movement = std::stoi(std::string(splited[3])); } else util::myThrow(fmt::format("Invalid strategy line '{}'", lines[i])); if (edges.count(key)) util::myThrow(fmt::format("Edge {} {} defined twice", key.first, key.second)); edges[key] = std::make_pair(value, movement); isDone[key.first] = false; } if (edges.empty()) util::myThrow("Strategy is empty"); defaultCycle.pop_back(); std::reverse(defaultCycle.begin(), defaultCycle.end()); originalDefaultCycle = defaultCycle; } std::pair<std::string, int> Strategy::getMovement(const Config & c, const std::string & transition) { std::string transitionPrefix(util::split(transition, ' ')[0]); if (c.stateIsDone()) isDone[c.getState()] = true; while (defaultCycle.size() && isDone[defaultCycle.back()]) defaultCycle.pop_back(); if (type == Type::Sequential) return getMovementSequential(c, transitionPrefix); return getMovementIncremental(c, transitionPrefix); } std::pair<std::string, int> Strategy::getMovementSequential(const Config & c, const std::string & transition) { auto foundSpecific = edges.find(std::make_pair(c.getState(), transition)); auto foundGeneric = edges.find(std::make_pair(c.getState(), "")); std::string target; int movement = -1; if (foundSpecific != edges.end()) { target = foundSpecific->second.first; movement = foundSpecific->second.second; } else if (foundGeneric != edges.end()) { target = foundGeneric->second.first; movement = foundGeneric->second.second; } if (target.empty()) util::myThrow(fmt::format("no suitable movement found for current state '{}' and transition '{}'", c.getState(), transition)); if (!c.stateIsDone()) return {c.getState(), c.canMoveWordIndex(movement) ? movement : 0}; if (!isDone[target]) return {target, -c.getWordIndex()}; return endMovement; } std::pair<std::string, int> Strategy::getMovementIncremental(const Config & c, const std::string & transition) { auto foundSpecific = edges.find(std::make_pair(c.getState(), transition)); auto foundGeneric = edges.find(std::make_pair(c.getState(), "")); std::string target; int movement = -1; if (foundSpecific != edges.end()) { target = foundSpecific->second.first; movement = foundSpecific->second.second; } else if (foundGeneric != edges.end()) { target = foundGeneric->second.first; movement = foundGeneric->second.second; } if (target.empty()) util::myThrow(fmt::format("no suitable movement found for current state '{}' and transition '{}'", c.getState(), transition)); if (!isDone[target]) return {target, c.canMoveWordIndex(movement) ? movement : 0}; if (defaultCycle.empty()) return endMovement; return {defaultCycle.back(), movement}; } const std::string Strategy::getInitialState() const { return initialState; } void Strategy::reset() { for (auto & it : isDone) it.second = false; defaultCycle = originalDefaultCycle; }