sp
1 year ago
commit
85d0cbc81f
15 changed files with 2937 additions and 0 deletions
-
34.gitignore
-
22CMakeLists.txt
-
171main.cpp
-
8util/CMakeLists.txt
-
229util/Grid.cpp
-
63util/Grid.h
-
102util/MinigridGrammar.h
-
32util/OptionParser.cpp
-
13util/OptionParser.h
-
681util/PrismModulesPrinter.cpp
-
91util/PrismModulesPrinter.h
-
15util/PrismPrinter.h
-
83util/cell.cpp
-
62util/cell.h
-
1331util/popl.hpp
@ -0,0 +1,34 @@ |
|||||
|
# Prerequisites |
||||
|
*.d |
||||
|
|
||||
|
# Compiled Object files |
||||
|
*.slo |
||||
|
*.lo |
||||
|
*.o |
||||
|
*.obj |
||||
|
|
||||
|
# Precompiled Headers |
||||
|
*.gch |
||||
|
*.pch |
||||
|
|
||||
|
# Compiled Dynamic libraries |
||||
|
*.so |
||||
|
*.dylib |
||||
|
*.dll |
||||
|
|
||||
|
# Fortran module files |
||||
|
*.mod |
||||
|
*.smod |
||||
|
|
||||
|
# Compiled Static libraries |
||||
|
*.lai |
||||
|
*.la |
||||
|
*.a |
||||
|
*.lib |
||||
|
|
||||
|
# Executables |
||||
|
*.exe |
||||
|
*.out |
||||
|
*.app |
||||
|
|
||||
|
build/* |
@ -0,0 +1,22 @@ |
|||||
|
include(util/CMakeLists.txt) |
||||
|
|
||||
|
set(CMAKE_CXX_STANDARD 20) |
||||
|
|
||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'") |
||||
|
add_definitions(-DLOG_DEBUG) |
||||
|
|
||||
|
cmake_minimum_required(VERSION 3.0...3.22) |
||||
|
|
||||
|
set(CMAKE_BUILD_TYPE Debug) |
||||
|
|
||||
|
project( |
||||
|
Minigrid2PRISM |
||||
|
VERSION 0.1 |
||||
|
LANGUAGES CXX) |
||||
|
|
||||
|
add_executable(main |
||||
|
${SRCS} |
||||
|
main.cpp |
||||
|
) |
||||
|
|
||||
|
target_link_libraries(main pthread) |
@ -0,0 +1,171 @@ |
|||||
|
#include "util/OptionParser.h"
|
||||
|
#include "util/MinigridGrammar.h"
|
||||
|
#include "util/Grid.h"
|
||||
|
|
||||
|
#include <iostream>
|
||||
|
#include <fstream>
|
||||
|
#include <filesystem>
|
||||
|
#include <sstream>
|
||||
|
|
||||
|
std::vector<std::string> parseCommaSeparatedString(std::string const& str) { |
||||
|
std::vector<std::string> result; |
||||
|
std::stringstream stream(str); |
||||
|
while(stream.good()) { |
||||
|
std::string substr; |
||||
|
getline(stream, substr, ','); |
||||
|
substr.at(0) = std::toupper(substr.at(0)); |
||||
|
result.push_back(substr); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
struct printer { |
||||
|
typedef boost::spirit::utf8_string string; |
||||
|
|
||||
|
void element(string const& tag, string const& value, int depth) const { |
||||
|
for (int i = 0; i < (depth*4); ++i) std::cout << ' '; |
||||
|
|
||||
|
std::cout << "tag: " << tag; |
||||
|
if (value != "") std::cout << ", value: " << value; |
||||
|
std::cout << std::endl; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
void print_info(boost::spirit::info const& what) { |
||||
|
using boost::spirit::basic_info_walker; |
||||
|
|
||||
|
printer pr; |
||||
|
basic_info_walker<printer> walker(pr, what.tag, 0); |
||||
|
boost::apply_visitor(walker, what.value); |
||||
|
} |
||||
|
|
||||
|
int main(int argc, char* argv[]) { |
||||
|
popl::OptionParser optionParser("Allowed options"); |
||||
|
|
||||
|
auto helpOption = optionParser.add<popl::Switch>("h", "help", "Print this help message."); |
||||
|
auto inputFilename = optionParser.add<popl::Value<std::string>>("i", "input-file", "Filename of the input file."); |
||||
|
auto outputFilename = optionParser.add<popl::Value<std::string>>("o", "output-file", "Filename for the output file."); |
||||
|
|
||||
|
auto agentsToBeConsidered = optionParser.add<popl::Value<std::string>, popl::Attribute::optional>("a", "agents", "Which parsed agents should be considered in the output. WIP."); |
||||
|
auto viewForAgents = optionParser.add<popl::Value<std::string>, popl::Attribute::optional>("v", "view", "Agents for which the 'view'('direction') variable should be included. WIP."); |
||||
|
|
||||
|
auto probabilisticBehaviourAgents = optionParser.add<popl::Value<std::string>, popl::Attribute::optional>("p", "prob-beh", "Agents for which we want to include probabilistic actions"); |
||||
|
auto probabilities = optionParser.add<popl::Value<std::string>, popl::Attribute::optional>("q", "probs", "The probabilities for which probabilistic actions should be added. WIP"); |
||||
|
|
||||
|
auto enforceOneWays = optionParser.add<popl::Switch>("f", "force-oneways", "Enforce encoding of oneways. This entails that slippery tiles do not allow turning and have prob 1 to shift the agent by one and makes turning impossible if in a one tile wide section of the grid."); |
||||
|
|
||||
|
try { |
||||
|
optionParser.parse(argc, argv); |
||||
|
|
||||
|
if(helpOption->count() > 0) { |
||||
|
std::cout << optionParser << std::endl; |
||||
|
return EXIT_SUCCESS; |
||||
|
} |
||||
|
} catch (const popl::invalid_option &e) { |
||||
|
return io::printPoplException(e); |
||||
|
} catch (const std::exception &e) { |
||||
|
std::cerr << "Exception: " << e.what() << "\n"; |
||||
|
return EXIT_FAILURE; |
||||
|
} |
||||
|
|
||||
|
GridOptions gridOptions = { {}, {} }; |
||||
|
if(agentsToBeConsidered->is_set()) { |
||||
|
gridOptions.agentsToBeConsidered = parseCommaSeparatedString(agentsToBeConsidered->value(0)); |
||||
|
} |
||||
|
if(viewForAgents->is_set()) { |
||||
|
gridOptions.agentsWithView = parseCommaSeparatedString(viewForAgents->value(0)); |
||||
|
} |
||||
|
if(enforceOneWays->is_set()) { |
||||
|
gridOptions.enforceOneWays = true; |
||||
|
} |
||||
|
if(probabilisticBehaviourAgents->is_set()) { |
||||
|
gridOptions.agentsWithProbabilisticBehaviour = parseCommaSeparatedString(probabilisticBehaviourAgents->value(0)); |
||||
|
for(auto const& a : gridOptions.agentsWithProbabilisticBehaviour) { |
||||
|
std::cout << a << std::endl; |
||||
|
} |
||||
|
if(probabilities->is_set()) { |
||||
|
std::vector<std::string> parsedStrings = parseCommaSeparatedString(probabilities->value(0)); |
||||
|
|
||||
|
std::transform(parsedStrings.begin(), parsedStrings.end(), std::back_inserter(gridOptions.probabilitiesForActions), [](const std::string& string) { |
||||
|
return std::stof(string); |
||||
|
}); |
||||
|
for(auto const& a : gridOptions.probabilitiesForActions) { |
||||
|
std::cout << a << std::endl; |
||||
|
} |
||||
|
} else { |
||||
|
throw std::logic_error{ "When adding agents with probabilistic behaviour, you also need to specify a list of probabilities via --probs." }; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
std::fstream file {outputFilename->value(0), file.trunc | file.out}; |
||||
|
std::fstream infile {inputFilename->value(0), infile.in}; |
||||
|
std::string line, content, background, rewards; |
||||
|
std::cout << "\n"; |
||||
|
bool parsingBackground = false; |
||||
|
bool parsingStateRewards = false; |
||||
|
while (std::getline(infile, line) && !line.empty()) { |
||||
|
if(line.at(0) == '-' && line.at(line.size() - 1) == '-' && parsingBackground) { |
||||
|
parsingStateRewards = true; |
||||
|
parsingBackground = false; |
||||
|
continue; |
||||
|
} else if(line.at(0) == '-' && line.at(line.size() - 1) == '-') { |
||||
|
parsingBackground = true; |
||||
|
continue; |
||||
|
} |
||||
|
if(!parsingBackground && !parsingStateRewards) { |
||||
|
std::cout << "Reading :\t" << line << "\n"; |
||||
|
content += line + "\n"; |
||||
|
} else if (parsingBackground) { |
||||
|
std::cout << "Background:\t" << line << "\n"; |
||||
|
background += line + "\n"; |
||||
|
} else if(parsingStateRewards) { |
||||
|
rewards += line + "\n"; |
||||
|
} |
||||
|
} |
||||
|
std::cout << "\n"; |
||||
|
|
||||
|
|
||||
|
pos_iterator_t contentFirst(content.begin()); |
||||
|
pos_iterator_t contentIter = contentFirst; |
||||
|
pos_iterator_t contentLast(content.end()); |
||||
|
MinigridParser<pos_iterator_t> contentParser(contentFirst); |
||||
|
pos_iterator_t backgroundFirst(background.begin()); |
||||
|
pos_iterator_t backgroundIter = backgroundFirst; |
||||
|
pos_iterator_t backgroundLast(background.end()); |
||||
|
MinigridParser<pos_iterator_t> backgroundParser(backgroundFirst); |
||||
|
|
||||
|
cells contentCells; |
||||
|
cells backgroundCells; |
||||
|
std::map<coordinates, float> stateRewards; |
||||
|
try { |
||||
|
bool ok = phrase_parse(contentIter, contentLast, contentParser, qi::space, contentCells); |
||||
|
// TODO if(background is not empty) {
|
||||
|
ok &= phrase_parse(backgroundIter, backgroundLast, backgroundParser, qi::space, backgroundCells); |
||||
|
// TODO }
|
||||
|
|
||||
|
boost::escaped_list_separator<char> seps('\\', ';', '\n'); |
||||
|
Tokenizer csvParser(rewards, seps); |
||||
|
for(auto iter = csvParser.begin(); iter != csvParser.end(); ++iter) { |
||||
|
int x = std::stoi(*iter); |
||||
|
int y = std::stoi(*(++iter)); |
||||
|
float reward = std::stof(*(++iter)); |
||||
|
stateRewards[std::make_pair(x,y)] = reward; |
||||
|
} |
||||
|
if(ok) { |
||||
|
Grid grid(contentCells, backgroundCells, gridOptions, stateRewards); |
||||
|
//grid.printToPrism(std::cout, prism::ModelType::MDP);
|
||||
|
grid.printToPrism(file, prism::ModelType::MDP); |
||||
|
} |
||||
|
} catch(qi::expectation_failure<pos_iterator_t> const& e) { |
||||
|
std::cout << "expected: "; print_info(e.what_); |
||||
|
std::cout << "got: \"" << std::string(e.first, e.last) << '"' << std::endl; |
||||
|
std::cout << "Expectation failure: " << e.what() << " at '" << std::string(e.first,e.last) << "'\n"; |
||||
|
} catch(const std::exception& e) { |
||||
|
std::cerr << "Exception '" << typeid(e).name() << "' caught:" << std::endl; |
||||
|
std::cerr << "\t" << e.what() << std::endl; |
||||
|
std::exit(EXIT_FAILURE); |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
list(APPEND SRCS |
||||
|
${CMAKE_CURRENT_LIST_DIR}/cell.cpp |
||||
|
${CMAKE_CURRENT_LIST_DIR}/MinigridGrammar.h |
||||
|
${CMAKE_CURRENT_LIST_DIR}/Grid.cpp |
||||
|
${CMAKE_CURRENT_LIST_DIR}/PrismModulesPrinter.cpp |
||||
|
${CMAKE_CURRENT_LIST_DIR}/popl.hpp |
||||
|
${CMAKE_CURRENT_LIST_DIR}/OptionParser.cpp |
||||
|
) |
@ -0,0 +1,229 @@ |
|||||
|
#include "Grid.h"
|
||||
|
|
||||
|
#include <algorithm>
|
||||
|
|
||||
|
Grid::Grid(cells gridCells, cells background, const GridOptions &gridOptions, const std::map<coordinates, float> &stateRewards) |
||||
|
: allGridCells(gridCells), background(background), gridOptions(gridOptions), stateRewards(stateRewards) |
||||
|
{ |
||||
|
cell max = allGridCells.at(allGridCells.size() - 1); |
||||
|
maxBoundaries = std::make_pair(max.row - 1, max.column - 1); |
||||
|
std::copy_if(gridCells.begin(), gridCells.end(), std::back_inserter(walls), [](cell c) { |
||||
|
return c.type == Type::Wall; |
||||
|
}); |
||||
|
std::copy_if(gridCells.begin(), gridCells.end(), std::back_inserter(lava), [](cell c) { |
||||
|
return c.type == Type::Lava; |
||||
|
}); |
||||
|
std::copy_if(gridCells.begin(), gridCells.end(), std::back_inserter(floor), [](cell c) { |
||||
|
return c.type == Type::Floor; |
||||
|
}); |
||||
|
std::copy_if(background.begin(), background.end(), std::back_inserter(slipperyNorth), [](cell c) { |
||||
|
return c.type == Type::SlipperyNorth; |
||||
|
}); |
||||
|
std::copy_if(background.begin(), background.end(), std::back_inserter(slipperyEast), [](cell c) { |
||||
|
return c.type == Type::SlipperyEast; |
||||
|
}); |
||||
|
std::copy_if(background.begin(), background.end(), std::back_inserter(slipperySouth), [](cell c) { |
||||
|
return c.type == Type::SlipperySouth; |
||||
|
}); |
||||
|
std::copy_if(background.begin(), background.end(), std::back_inserter(slipperyWest), [](cell c) { |
||||
|
return c.type == Type::SlipperyWest; |
||||
|
}); |
||||
|
std::copy_if(gridCells.begin(), gridCells.end(), std::back_inserter(lockedDoors), [](cell c) { |
||||
|
return c.type == Type::LockedDoor; |
||||
|
}); |
||||
|
std::copy_if(gridCells.begin(), gridCells.end(), std::back_inserter(goals), [](cell c) { |
||||
|
return c.type == Type::Goal; |
||||
|
}); |
||||
|
std::copy_if(gridCells.begin(), gridCells.end(), std::back_inserter(keys), [](cell c) { |
||||
|
return c.type == Type::Key; |
||||
|
}); |
||||
|
std::copy_if(gridCells.begin(), gridCells.end(), std::back_inserter(boxes), [](cell c) { |
||||
|
return c.type == Type::Box; |
||||
|
}); |
||||
|
agent = *std::find_if(gridCells.begin(), gridCells.end(), [](cell c) { |
||||
|
return c.type == Type::Agent; |
||||
|
}); |
||||
|
std::copy_if(gridCells.begin(), gridCells.end(), std::back_inserter(adversaries), [](cell c) { |
||||
|
return c.type == Type::Adversary; |
||||
|
}); |
||||
|
agentNameAndPositionMap.insert({ "Agent", agent.getCoordinates() }); |
||||
|
for(auto const& adversary : adversaries) { |
||||
|
std::string color = adversary.getColor(); |
||||
|
color.at(0) = std::toupper(color.at(0)); |
||||
|
try { |
||||
|
if(gridOptions.agentsToBeConsidered.size() != 0 && std::find(gridOptions.agentsToBeConsidered.begin(), gridOptions.agentsToBeConsidered.end(), color) == gridOptions.agentsToBeConsidered.end()) continue; |
||||
|
auto success = agentNameAndPositionMap.insert({ color, adversary.getCoordinates() }); |
||||
|
if(!success.second) { |
||||
|
throw std::logic_error("Agent with " + color + " already present\n"); |
||||
|
} |
||||
|
} catch(const std::logic_error& e) { |
||||
|
std::cerr << "Expected agents colors to be different. Agent with color : '" << color << "' already present." << std::endl; |
||||
|
throw; |
||||
|
} |
||||
|
} |
||||
|
for(auto const& color : allColors) { |
||||
|
cells cellsOfColor; |
||||
|
std::copy_if(background.begin(), background.end(), std::back_inserter(cellsOfColor), [&color](cell c) { |
||||
|
return c.type == Type::Floor && c.color == color; |
||||
|
}); |
||||
|
if(cellsOfColor.size() > 0) { |
||||
|
backgroundTiles.emplace(color, cellsOfColor); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
std::ostream& operator<<(std::ostream& os, const Grid& grid) { |
||||
|
int lastRow = 1; |
||||
|
for(auto const& cell : grid.allGridCells) { |
||||
|
if(lastRow != cell.row) |
||||
|
os << std::endl; |
||||
|
os << static_cast<char>(cell.type) << static_cast<char>(cell.color); |
||||
|
lastRow = cell.row; |
||||
|
} |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
cells Grid::getGridCells() { |
||||
|
return allGridCells; |
||||
|
} |
||||
|
|
||||
|
bool Grid::isBlocked(coordinates p) { |
||||
|
return isWall(p) || isLockedDoor(p) || isKey(p); |
||||
|
} |
||||
|
|
||||
|
bool Grid::isWall(coordinates p) { |
||||
|
return std::find_if(walls.begin(), walls.end(), |
||||
|
[p](cell cell) { |
||||
|
return cell.row == p.first && cell.column == p.second; |
||||
|
}) != walls.end(); |
||||
|
} |
||||
|
|
||||
|
bool Grid::isLockedDoor(coordinates p) { |
||||
|
return std::find_if(lockedDoors.begin(), lockedDoors.end(), |
||||
|
[p](cell cell) { |
||||
|
return cell.row == p.first && cell.column == p.second; |
||||
|
}) != lockedDoors.end(); |
||||
|
} |
||||
|
|
||||
|
bool Grid::isKey(coordinates p) { |
||||
|
return std::find_if(keys.begin(), keys.end(), |
||||
|
[p](cell cell) { |
||||
|
return cell.row == p.first && cell.column == p.second; |
||||
|
}) != keys.end(); |
||||
|
} |
||||
|
|
||||
|
bool Grid::isBox(coordinates p) { |
||||
|
return std::find_if(boxes.begin(), boxes.end(), |
||||
|
[p](cell cell) { |
||||
|
return cell.row == p.first && cell.column == p.second; |
||||
|
}) != boxes.end(); |
||||
|
} |
||||
|
|
||||
|
void Grid::printToPrism(std::ostream& os, const prism::ModelType& modelType) { |
||||
|
cells northRestriction; |
||||
|
cells eastRestriction; |
||||
|
cells southRestriction; |
||||
|
cells westRestriction; |
||||
|
cells walkable = floor; |
||||
|
walkable.insert(walkable.end(), goals.begin(), goals.end()); |
||||
|
walkable.insert(walkable.end(), boxes.begin(), boxes.end()); |
||||
|
walkable.push_back(agent); |
||||
|
walkable.insert(walkable.end(), adversaries.begin(), adversaries.end()); |
||||
|
walkable.insert(walkable.end(), lava.begin(), lava.end()); |
||||
|
for(auto const& c : walkable) { |
||||
|
if(isBlocked(c.getNorth())) northRestriction.push_back(c); |
||||
|
if(isBlocked(c.getEast())) eastRestriction.push_back(c); |
||||
|
if(isBlocked(c.getSouth())) southRestriction.push_back(c); |
||||
|
if(isBlocked(c.getWest())) westRestriction.push_back(c); |
||||
|
} |
||||
|
|
||||
|
prism::PrismModulesPrinter printer(modelType, agentNameAndPositionMap.size(), gridOptions.enforceOneWays); |
||||
|
printer.printModel(os, modelType); |
||||
|
if(modelType == prism::ModelType::SMG) { |
||||
|
printer.printGlobalMoveVariable(os, agentNameAndPositionMap.size()); |
||||
|
} |
||||
|
for(auto const &backgroundTilesOfColor : backgroundTiles) { |
||||
|
for(auto agentNameAndPosition = agentNameAndPositionMap.begin(); agentNameAndPosition != agentNameAndPositionMap.end(); ++agentNameAndPosition) { |
||||
|
printer.printBackgroundLabels(os, agentNameAndPosition->first, backgroundTilesOfColor); |
||||
|
} |
||||
|
} |
||||
|
cells noTurnFloor; |
||||
|
if(gridOptions.enforceOneWays) { |
||||
|
for(auto const& c : floor) { |
||||
|
cell east = c.getEast(allGridCells); |
||||
|
cell south = c.getSouth(allGridCells); |
||||
|
cell west = c.getWest(allGridCells); |
||||
|
cell north = c.getNorth(allGridCells); |
||||
|
if( (east.type == Type::Wall && west.type == Type::Wall) or |
||||
|
(north.type == Type::Wall && south.type == Type::Wall) ) { |
||||
|
noTurnFloor.push_back(c); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for(auto agentNameAndPosition = agentNameAndPositionMap.begin(); agentNameAndPosition != agentNameAndPositionMap.end(); ++agentNameAndPosition) { |
||||
|
printer.printFormulas(os, agentNameAndPosition->first, northRestriction, eastRestriction, southRestriction, westRestriction, { slipperyNorth, slipperyEast, slipperySouth, slipperyWest }, lava, walls, noTurnFloor, slipperyNorth, slipperyEast, slipperySouth, slipperyWest); |
||||
|
printer.printGoalLabel(os, agentNameAndPosition->first, goals); |
||||
|
printer.printKeysLabels(os, agentNameAndPosition->first, keys); |
||||
|
} |
||||
|
|
||||
|
std::vector<AgentName> agentNames; |
||||
|
std::transform(agentNameAndPositionMap.begin(), |
||||
|
agentNameAndPositionMap.end(), |
||||
|
std::back_inserter(agentNames), |
||||
|
[](const std::map<AgentNameAndPosition::first_type,AgentNameAndPosition::second_type>::value_type &pair){return pair.first;}); |
||||
|
if(modelType == prism::ModelType::SMG) { |
||||
|
printer.printCrashLabel(os, agentNames); |
||||
|
} |
||||
|
size_t agentIndex = 0; |
||||
|
for(auto agentNameAndPosition = agentNameAndPositionMap.begin(); agentNameAndPosition != agentNameAndPositionMap.end(); ++agentNameAndPosition, agentIndex++) { |
||||
|
AgentName agentName = agentNameAndPosition->first; |
||||
|
bool agentWithView = std::find(gridOptions.agentsWithView.begin(), gridOptions.agentsWithView.end(), agentName) != gridOptions.agentsWithView.end(); |
||||
|
bool agentWithProbabilisticBehaviour = std::find(gridOptions.agentsWithProbabilisticBehaviour.begin(), gridOptions.agentsWithProbabilisticBehaviour.end(), agentName) != gridOptions.agentsWithProbabilisticBehaviour.end(); |
||||
|
std::set<std::string> slipperyActions; |
||||
|
printer.printInitStruct(os, agentName); |
||||
|
if(agentWithProbabilisticBehaviour) printer.printModule(os, agentName, agentIndex, maxBoundaries, agentNameAndPosition->second, keys, backgroundTiles, agentWithView, gridOptions.probabilitiesForActions); |
||||
|
else printer.printModule(os, agentName, agentIndex, maxBoundaries, agentNameAndPosition->second, keys, backgroundTiles, agentWithView); |
||||
|
for(auto const& c : slipperyNorth) { |
||||
|
printer.printSlipperyMove(os, agentName, agentIndex, c.getCoordinates(), slipperyActions, getWalkableDirOf8Neighborhood(c), prism::PrismModulesPrinter::SlipperyType::North); |
||||
|
if(!gridOptions.enforceOneWays) printer.printSlipperyTurn(os, agentName, agentIndex, c.getCoordinates(), slipperyActions, getWalkableDirOf8Neighborhood(c), prism::PrismModulesPrinter::SlipperyType::North); |
||||
|
|
||||
|
} |
||||
|
for(auto const& c : slipperyEast) { |
||||
|
printer.printSlipperyMove(os, agentName, agentIndex, c.getCoordinates(), slipperyActions, getWalkableDirOf8Neighborhood(c), prism::PrismModulesPrinter::SlipperyType::East); |
||||
|
if(!gridOptions.enforceOneWays) printer.printSlipperyTurn(os, agentName, agentIndex, c.getCoordinates(), slipperyActions, getWalkableDirOf8Neighborhood(c), prism::PrismModulesPrinter::SlipperyType::East); |
||||
|
} |
||||
|
for(auto const& c : slipperySouth) { |
||||
|
printer.printSlipperyMove(os, agentName, agentIndex, c.getCoordinates(), slipperyActions, getWalkableDirOf8Neighborhood(c), prism::PrismModulesPrinter::SlipperyType::South); |
||||
|
if(!gridOptions.enforceOneWays) printer.printSlipperyTurn(os, agentName, agentIndex, c.getCoordinates(), slipperyActions, getWalkableDirOf8Neighborhood(c), prism::PrismModulesPrinter::SlipperyType::South); |
||||
|
} |
||||
|
for(auto const& c : slipperyWest) { |
||||
|
printer.printSlipperyMove(os, agentName, agentIndex, c.getCoordinates(), slipperyActions, getWalkableDirOf8Neighborhood(c), prism::PrismModulesPrinter::SlipperyType::West); |
||||
|
if(!gridOptions.enforceOneWays) printer.printSlipperyTurn(os, agentName, agentIndex, c.getCoordinates(), slipperyActions, getWalkableDirOf8Neighborhood(c), prism::PrismModulesPrinter::SlipperyType::West); |
||||
|
} |
||||
|
|
||||
|
printer.printEndmodule(os); |
||||
|
if(modelType == prism::ModelType::SMG) { |
||||
|
if(agentWithProbabilisticBehaviour) printer.printPlayerStruct(os, agentNameAndPosition->first, agentWithView, gridOptions.probabilitiesForActions, slipperyActions); |
||||
|
else printer.printPlayerStruct(os, agentNameAndPosition->first, agentWithView, {}, slipperyActions); |
||||
|
} |
||||
|
//if(!stateRewards.empty()) {
|
||||
|
printer.printRewards(os, agentName, stateRewards, lava, goals, backgroundTiles); |
||||
|
//}
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
std::array<bool, 8> Grid::getWalkableDirOf8Neighborhood(cell c) /* const */ { |
||||
|
return (std::array<bool, 8>) |
||||
|
{ |
||||
|
!isBlocked(c.getNorth()), |
||||
|
!isBlocked(c.getNorth(allGridCells).getEast()), |
||||
|
!isBlocked(c.getEast()), |
||||
|
!isBlocked(c.getSouth(allGridCells).getEast()), |
||||
|
!isBlocked(c.getSouth()), |
||||
|
!isBlocked(c.getSouth(allGridCells).getWest()), |
||||
|
!isBlocked(c.getWest()), |
||||
|
!isBlocked(c.getNorth(allGridCells).getWest()) |
||||
|
}; |
||||
|
} |
@ -0,0 +1,63 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <iostream> |
||||
|
#include <fstream> |
||||
|
#include <map> |
||||
|
#include <utility> |
||||
|
|
||||
|
#include "MinigridGrammar.h" |
||||
|
#include "PrismModulesPrinter.h" |
||||
|
|
||||
|
struct GridOptions { |
||||
|
std::vector<AgentName> agentsToBeConsidered; |
||||
|
std::vector<AgentName> agentsWithView; |
||||
|
std::vector<AgentName> agentsWithProbabilisticBehaviour; |
||||
|
std::vector<float> probabilitiesForActions; |
||||
|
bool enforceOneWays; |
||||
|
}; |
||||
|
|
||||
|
class Grid { |
||||
|
public: |
||||
|
Grid(cells gridCells, cells background, const GridOptions &gridOptions, const std::map<coordinates, float> &stateRewards = {}); |
||||
|
|
||||
|
cells getGridCells(); |
||||
|
|
||||
|
bool isBlocked(coordinates p); |
||||
|
bool isWall(coordinates p); |
||||
|
bool isLockedDoor(coordinates p); |
||||
|
bool isKey(coordinates p); |
||||
|
bool isBox(coordinates p); |
||||
|
void printToPrism(std::ostream &os, const prism::ModelType& modelType); |
||||
|
|
||||
|
std::array<bool, 8> getWalkableDirOf8Neighborhood(cell c); |
||||
|
|
||||
|
friend std::ostream& operator<<(std::ostream& os, const Grid &grid); |
||||
|
|
||||
|
private: |
||||
|
GridOptions gridOptions; |
||||
|
|
||||
|
cells allGridCells; |
||||
|
cells background; |
||||
|
coordinates maxBoundaries; |
||||
|
|
||||
|
cell agent; |
||||
|
cells adversaries; |
||||
|
AgentNameAndPositionMap agentNameAndPositionMap; |
||||
|
|
||||
|
cells walls; |
||||
|
cells floor; |
||||
|
cells slipperyNorth; |
||||
|
cells slipperyEast; |
||||
|
cells slipperySouth; |
||||
|
cells slipperyWest; |
||||
|
cells lockedDoors; |
||||
|
cells boxes; |
||||
|
cells lava; |
||||
|
|
||||
|
cells goals; |
||||
|
cells keys; |
||||
|
|
||||
|
std::map<Color, cells> backgroundTiles; |
||||
|
|
||||
|
std::map<coordinates, float> stateRewards; |
||||
|
}; |
@ -0,0 +1,102 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include "cell.h" |
||||
|
|
||||
|
#include <vector> |
||||
|
|
||||
|
#include <boost/tokenizer.hpp> |
||||
|
#include <boost/fusion/adapted/struct.hpp> |
||||
|
#include <boost/spirit/include/qi.hpp> |
||||
|
#include <boost/spirit/include/phoenix.hpp> |
||||
|
#include <boost/spirit/include/phoenix_operator.hpp> |
||||
|
#include <boost/variant/recursive_wrapper.hpp> |
||||
|
#include <boost/spirit/include/support_line_pos_iterator.hpp> |
||||
|
|
||||
|
namespace qi = boost::spirit::qi; |
||||
|
namespace phoenix = boost::phoenix; |
||||
|
|
||||
|
typedef boost::spirit::line_pos_iterator<std::string::const_iterator> pos_iterator_t; |
||||
|
|
||||
|
typedef std::vector<cell> row; |
||||
|
typedef std::vector<cell> cells; |
||||
|
|
||||
|
BOOST_FUSION_ADAPT_STRUCT( |
||||
|
cell, |
||||
|
(Type, type) |
||||
|
(Color, color) |
||||
|
) |
||||
|
|
||||
|
template<typename It> |
||||
|
struct annotation_f { |
||||
|
typedef void result_type; |
||||
|
|
||||
|
annotation_f(It first) : first(first) {} |
||||
|
It const first; |
||||
|
|
||||
|
template<typename Val, typename First, typename Last> |
||||
|
void operator()(Val& v, First f, Last l) const { |
||||
|
do_annotate(v, f, l, first); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
void static do_annotate(cell& c, It f, It l, It first) { |
||||
|
c.row = get_line(f) - 1; |
||||
|
c.column = get_column(first, f) / 2; |
||||
|
} |
||||
|
static void do_annotate(...) { std::cerr << "(not having LocationInfo)\n"; } |
||||
|
}; |
||||
|
|
||||
|
template <typename It> |
||||
|
struct MinigridParser : qi::grammar<It, row()> |
||||
|
{ |
||||
|
MinigridParser(It first) : MinigridParser::base_type(row_), annotate(first) |
||||
|
{ |
||||
|
using namespace qi; |
||||
|
type_.add |
||||
|
("W", Type::Wall) |
||||
|
(" ", Type::Floor) |
||||
|
("D", Type::Door) |
||||
|
("L", Type::LockedDoor) |
||||
|
("K", Type::Key) |
||||
|
("A", Type::Ball) |
||||
|
("B", Type::Box) |
||||
|
("G", Type::Goal) |
||||
|
("V", Type::Lava) |
||||
|
("n", Type::SlipperyNorth) |
||||
|
("e", Type::SlipperyEast) |
||||
|
("s", Type::SlipperySouth) |
||||
|
("w", Type::SlipperyWest) |
||||
|
("X", Type::Agent) |
||||
|
("Z", Type::Adversary); |
||||
|
color_.add |
||||
|
("R", Color::Red) |
||||
|
("G", Color::Green) |
||||
|
("B", Color::Blue) |
||||
|
("P", Color::Purple) |
||||
|
("Y", Color::Yellow) |
||||
|
(" ", Color::None); |
||||
|
|
||||
|
cell_ = type_ > color_; |
||||
|
|
||||
|
row_ = (cell_ % -qi::char_("\n")); |
||||
|
|
||||
|
auto set_location_info = annotate(_val, _1, _3); |
||||
|
on_success(cell_, set_location_info); |
||||
|
|
||||
|
BOOST_SPIRIT_DEBUG_NODE(type_); |
||||
|
BOOST_SPIRIT_DEBUG_NODE(color_); |
||||
|
BOOST_SPIRIT_DEBUG_NODE(cell_); |
||||
|
} |
||||
|
|
||||
|
private: |
||||
|
phoenix::function<annotation_f<It>> annotate; |
||||
|
|
||||
|
qi::symbols<char, Type> type_; |
||||
|
qi::symbols<char, Color> color_; |
||||
|
|
||||
|
qi::rule<It, cell()> cell_; |
||||
|
qi::rule<It, row()> row_; |
||||
|
}; |
||||
|
|
||||
|
typedef boost::tokenizer< boost::escaped_list_separator<char> , std::string::const_iterator, std::string> Tokenizer; |
||||
|
//std::ostream& operator<<(std::ostream& os, const row& r); |
@ -0,0 +1,32 @@ |
|||||
|
#include <iostream>
|
||||
|
|
||||
|
#include "popl.hpp"
|
||||
|
#include "OptionParser.h"
|
||||
|
|
||||
|
namespace io { |
||||
|
int printPoplException(const popl::invalid_option &e) { |
||||
|
std::cerr << "Invalid Option Exception: " << e.what() << "\n"; |
||||
|
std::cerr << "error: "; |
||||
|
if (e.error() == popl::invalid_option::Error::missing_argument) { |
||||
|
std::cerr << "missing_argument\n"; |
||||
|
} else if (e.error() == popl::invalid_option::Error::invalid_argument) { |
||||
|
std::cerr << "invalid_argument\n"; |
||||
|
} else if (e.error() == popl::invalid_option::Error::too_many_arguments) { |
||||
|
std::cerr << "too_many_arguments\n"; |
||||
|
} else if (e.error() == popl::invalid_option::Error::missing_option) { |
||||
|
std::cerr << "missing_option\n"; |
||||
|
} |
||||
|
|
||||
|
if (e.error() == popl::invalid_option::Error::missing_option) { |
||||
|
std::string option_name(e.option()->name(popl::OptionName::short_name, true)); |
||||
|
if (option_name.empty()) |
||||
|
option_name = e.option()->name(popl::OptionName::long_name, true); |
||||
|
std::cerr << "option: " << option_name << "\n"; |
||||
|
} |
||||
|
else { |
||||
|
std::cerr << "option: " << e.option()->name(e.what_name()) << "\n"; |
||||
|
std::cerr << "value: " << e.value() << "\n"; |
||||
|
} |
||||
|
return EXIT_FAILURE; |
||||
|
} |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <iostream> |
||||
|
|
||||
|
#include "popl.hpp" |
||||
|
|
||||
|
#define INPUT_ERROR 1 |
||||
|
#define INPUT_OK 0 |
||||
|
|
||||
|
namespace io { |
||||
|
int printPoplException(const popl::invalid_option &e); |
||||
|
|
||||
|
} |
@ -0,0 +1,681 @@ |
|||||
|
#include "PrismModulesPrinter.h"
|
||||
|
|
||||
|
#include <map>
|
||||
|
#include <string>
|
||||
|
|
||||
|
namespace prism { |
||||
|
|
||||
|
PrismModulesPrinter::PrismModulesPrinter(const ModelType &modelType, const size_t &numberOfPlayer, const bool enforceOneWays) |
||||
|
: modelType(modelType), numberOfPlayer(numberOfPlayer), enforceOneWays(enforceOneWays) { |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printModel(std::ostream &os, const ModelType &modelType) { |
||||
|
switch(modelType) { |
||||
|
case(ModelType::MDP): |
||||
|
os << "mdp"; |
||||
|
break; |
||||
|
case(ModelType::SMG): |
||||
|
os << "smg"; |
||||
|
break; |
||||
|
} |
||||
|
os << "\n\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printBackgroundLabels(std::ostream &os, const AgentName &agentName, const std::pair<Color, cells> &backgroundTiles) { |
||||
|
if(backgroundTiles.second.size() == 0) return os; |
||||
|
|
||||
|
bool first = true; |
||||
|
std::string color = getColor(backgroundTiles.first); |
||||
|
color.at(0) = std::toupper(color.at(0)); |
||||
|
os << "formula " << agentName << "On" << color << " = "; |
||||
|
for(auto const& cell : backgroundTiles.second) { |
||||
|
if(first) first = false; else os << " | "; |
||||
|
os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")"; |
||||
|
} |
||||
|
os << ";\n"; |
||||
|
os << "label \"" << agentName << "On" << color << "\" = " << agentName << "On" << color << ";\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printRestrictionFormula(std::ostream& os, const AgentName &agentName, const std::string &direction, const cells &cells) { |
||||
|
bool first = true; |
||||
|
os << "formula " << agentName << "CannotMove" << direction << " = " ; |
||||
|
for(auto const& cell : cells) { |
||||
|
if(first) first = false; |
||||
|
else os << " | "; |
||||
|
os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")"; |
||||
|
} |
||||
|
os << ";\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printIsOnSlipperyFormula(std::ostream& os, const AgentName &agentName, const std::vector<std::reference_wrapper<cells>> &slipperyCollection, const cells &slipperyNorth, const cells &slipperyEast, const cells &slipperySouth, const cells &slipperyWest) { |
||||
|
if(std::find_if(slipperyCollection.cbegin(), slipperyCollection.cend(), [=](const std::reference_wrapper<cells>& c) { return !c.get().empty(); }) == slipperyCollection.cend()) { |
||||
|
os << "formula " << agentName << "IsOnSlippery = false;\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
bool first = true; |
||||
|
os << "formula " << agentName << "IsOnSlippery = "; |
||||
|
|
||||
|
for (const auto& slippery: slipperyCollection) { |
||||
|
for(const auto& cell : slippery.get()) { |
||||
|
if(first) first = false; else os << " | "; |
||||
|
os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")"; |
||||
|
} |
||||
|
} |
||||
|
os << ";\n"; |
||||
|
if(enforceOneWays) { |
||||
|
first = true; |
||||
|
os << "formula " << agentName << "IsOnSlipperyNorth = "; |
||||
|
|
||||
|
for (const auto& cell: slipperyNorth) { |
||||
|
if(first) first = false; else os << " | "; |
||||
|
os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")"; |
||||
|
} |
||||
|
os << ";\n"; |
||||
|
first = true; |
||||
|
os << "formula " << agentName << "IsOnSlipperyEast = "; |
||||
|
|
||||
|
for (const auto& cell: slipperyEast) { |
||||
|
if(first) first = false; else os << " | "; |
||||
|
os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")"; |
||||
|
} |
||||
|
os << ";\n"; |
||||
|
first = true; |
||||
|
os << "formula " << agentName << "IsOnSlipperySouth = "; |
||||
|
|
||||
|
for (const auto& cell: slipperySouth) { |
||||
|
if(first) first = false; else os << " | "; |
||||
|
os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")"; |
||||
|
} |
||||
|
os << ";\n"; |
||||
|
first = true; |
||||
|
os << "formula " << agentName << "IsOnSlipperyWest = "; |
||||
|
for (const auto& cell: slipperyWest) { |
||||
|
if(first) first = false; else os << " | "; |
||||
|
os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")"; |
||||
|
} |
||||
|
os << ";\n"; |
||||
|
} |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printIsInLavaFormula(std::ostream& os, const AgentName &agentName, const cells &lava) { |
||||
|
if(lava.size() == 0) { |
||||
|
os << "formula " << agentName << "IsInLava = false;\n"; |
||||
|
return os; |
||||
|
} |
||||
|
bool first = true; |
||||
|
os << "formula " << agentName << "IsInLava = "; |
||||
|
for(auto const& cell : lava) { |
||||
|
if(first) first = false; else os << " | "; |
||||
|
os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")"; |
||||
|
} |
||||
|
os << ";\n"; |
||||
|
os << "formula " << agentName << "IsInLavaAndNotDone = " << agentName << "IsInLava & !" << agentName << "Done;\n"; |
||||
|
os << "label \"" << agentName << "IsInLavaAndNotDone\" = " << agentName << "IsInLava & !" << agentName << "Done;\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printTurningNotAllowedFormulas(std::ostream& os, const AgentName &agentName, const cells &noTurnFloor) { |
||||
|
if( (!enforceOneWays or noTurnFloor.size() == 0) or (noTurnFloor.size() == 0) ) { |
||||
|
os << "formula " << agentName << "CannotTurn = false;\n"; |
||||
|
return os; |
||||
|
} |
||||
|
bool first = true; |
||||
|
os << "formula " << agentName << "CannotTurn = "; |
||||
|
for(auto const& cell : noTurnFloor) { |
||||
|
if(first) first = false; else os << " | "; |
||||
|
os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")"; |
||||
|
} |
||||
|
os << " | " << agentName << "IsOnSlippery;\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printIsFixedFormulas(std::ostream& os, const AgentName &agentName) { |
||||
|
os << "formula " << agentName << "IsFixed = false;\n"; |
||||
|
os << "formula " << agentName << "SlipperyTurnLeftAllowed = true;\n"; |
||||
|
os << "formula " << agentName << "SlipperyTurnRightAllowed = true;\n"; |
||||
|
os << "formula " << agentName << "SlipperyMoveForwardAllowed = true;\n"; |
||||
|
os << "label \"FixedStates\" = " << agentName << "IsFixed | !" << agentName << "SlipperyTurnRightAllowed | !" << agentName << "SlipperyTurnLeftAllowed | !" << agentName << "SlipperyMoveForwardAllowed | " << agentName << "IsInGoal | " << agentName << "IsInLava"; |
||||
|
if(enforceOneWays) { |
||||
|
os << " | " << agentName << "CannotTurn"; |
||||
|
} |
||||
|
os << ";\n"; |
||||
|
//os << "label \"FixedStates\" = " << agentName << "IsFixed | " << agentName << "IsOnSlippery | " << agentName << "IsInGoal | " << agentName << "IsInLava;\n";
|
||||
|
|
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printWallFormula(std::ostream& os, const AgentName &agentName, const cells &walls) { |
||||
|
os << "formula " << agentName << "IsOnWall = "; |
||||
|
bool first = true; |
||||
|
for(auto const& cell : walls) { |
||||
|
if(first) first = false; else os << " | "; |
||||
|
os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")"; |
||||
|
} |
||||
|
os << ";\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printFormulas(std::ostream& os, |
||||
|
const AgentName &agentName, |
||||
|
const cells &restrictionNorth, |
||||
|
const cells &restrictionEast, |
||||
|
const cells &restrictionSouth, |
||||
|
const cells &restrictionWest, |
||||
|
const std::vector<std::reference_wrapper<cells>> &slipperyCollection, |
||||
|
const cells &lava, |
||||
|
const cells &walls, |
||||
|
const cells &noTurnFloor, |
||||
|
const cells &slipperyNorth, |
||||
|
const cells &slipperyEast, |
||||
|
const cells &slipperySouth, |
||||
|
const cells &slipperyWest) { |
||||
|
printRestrictionFormula(os, agentName, "North", restrictionNorth); |
||||
|
printRestrictionFormula(os, agentName, "East ", restrictionEast); |
||||
|
printRestrictionFormula(os, agentName, "South", restrictionSouth); |
||||
|
printRestrictionFormula(os, agentName, "West ", restrictionWest); |
||||
|
printIsOnSlipperyFormula(os, agentName, slipperyCollection, slipperyNorth, slipperyEast, slipperySouth, slipperyWest); |
||||
|
printIsInLavaFormula(os, agentName, lava); |
||||
|
printWallFormula(os, agentName, walls); |
||||
|
printTurningNotAllowedFormulas(os, agentName, noTurnFloor); |
||||
|
printIsFixedFormulas(os, agentName); |
||||
|
os << "\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printGoalLabel(std::ostream& os, const AgentName &agentName, const cells &goals) { |
||||
|
if(goals.size() == 0) { |
||||
|
os << "formula " << agentName << "IsInGoal = false;\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
bool first = true; |
||||
|
os << "formula " << agentName << "IsInGoal = "; |
||||
|
for(auto const& cell : goals) { |
||||
|
if(first) first = false; else os << " | "; |
||||
|
os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")"; |
||||
|
} |
||||
|
os << ";\n"; |
||||
|
os << "formula " << agentName << "IsInGoalAndNotDone = " << agentName << "IsInGoal & !" << agentName << "Done;\n"; |
||||
|
os << "label \"" << agentName << "IsInGoalAndNotDone\" = " << agentName << "IsInGoal & !" << agentName << "Done;\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printCrashLabel(std::ostream &os, const std::vector<AgentName> agentNames) { |
||||
|
os << "label crash = "; |
||||
|
bool first = true; |
||||
|
for(auto const& agentName : agentNames) { |
||||
|
if(agentName == "Agent") continue; |
||||
|
if(first) first = false; else os << " | "; |
||||
|
os << "(xAgent=x" << agentName << ")&(yAgent=y" << agentName << ")"; |
||||
|
} |
||||
|
os << ";\n\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printAvoidanceLabel(std::ostream &os, const std::vector<AgentName> agentNames, const int &distance) { |
||||
|
os << "label avoidance = "; |
||||
|
bool first = true; |
||||
|
for(auto const& agentName : agentNames) { |
||||
|
if(agentName == "Agent") continue; |
||||
|
if(first) first = false; else os << " | "; |
||||
|
os << "max(xAgent-x" << agentName << ",x" << agentName << "-xAgent)+"; |
||||
|
os << "max(yAgent-y" << agentName << ",y" << agentName << "-yAgent) "; |
||||
|
} |
||||
|
os << ";\n\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
// TODO this does not account for multiple agents yet, i.e. key can be picked up multiple times
|
||||
|
std::ostream& PrismModulesPrinter::printKeysLabels(std::ostream& os, const AgentName &agentName, const cells &keys) { |
||||
|
if(keys.size() == 0) return os; |
||||
|
|
||||
|
for(auto const& key : keys) { |
||||
|
int xKey = key.getCoordinates().first; |
||||
|
int yKey = key.getCoordinates().second; |
||||
|
std::string keyColor = key.getColor(); |
||||
|
os << "label \"" << agentName << "PickedUp" << keyColor << "Key\" = " << agentName << "_has_" << keyColor << "_key = true;\n"; |
||||
|
os << "formula " << agentName << "CanPickUp" << keyColor << "Key = "; |
||||
|
os << "((x" << agentName << "-1 = " << xKey << "&y" << agentName << " = " << yKey << "&view" << agentName << " = 1) |"; |
||||
|
os << " (x" << agentName << "+1 = " << xKey << "&y" << agentName << " = " << yKey << "&view" << agentName << " = 3) |"; |
||||
|
os << " (x" << agentName << " = " << xKey << "&y" << agentName << "-1 = " << yKey << "&view" << agentName << " = 0) |"; |
||||
|
os << " (x" << agentName << " = " << xKey << "&y" << agentName << "+1 = " << yKey << "&view" << agentName << " = 2) ) &"; |
||||
|
os << "!" << agentName << "_has_" << keyColor << "_key;"; |
||||
|
} |
||||
|
os << "\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printBooleansForKeys(std::ostream &os, const AgentName &agentName, const cells &keys) { |
||||
|
for(auto const& key : keys) { |
||||
|
os << "\t" << agentName << "_has_"<< key.getColor() << "_key : bool init false;\n"; |
||||
|
} |
||||
|
os << "\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printBooleansForBackground(std::ostream &os, const AgentName &agentName, const std::map<Color, cells> &backgroundTiles) { |
||||
|
for(auto const& [color, cells] : backgroundTiles) { |
||||
|
if(cells.size() == 0) continue; |
||||
|
std::string c = getColor(color); |
||||
|
c.at(0) = std::toupper(c.at(0)); |
||||
|
os << "\t" << agentName << "_picked_up_" << c << " : bool init false;\n"; |
||||
|
} |
||||
|
os << "\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printActionsForKeys(std::ostream &os, const AgentName &agentName, const cells &keys) { |
||||
|
for(auto const& key : keys) { |
||||
|
std::string keyColor = key.getColor(); |
||||
|
os << "\t[pickup_" << keyColor << "_key] " << agentName << "CanPickUp" << keyColor << "Key -> "; |
||||
|
os << "(" << agentName << "_has_" << keyColor << "_key'=true);"; |
||||
|
} |
||||
|
os << "\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printActionsForBackground(std::ostream &os, const AgentName &agentName, const std::map<Color, cells> &backgroundTiles) { |
||||
|
for(auto const& [color, cells] : backgroundTiles) { |
||||
|
if(cells.size() == 0) continue; |
||||
|
std::string c = getColor(color); |
||||
|
c.at(0) = std::toupper(c.at(0)); |
||||
|
os << "\t[" << agentName << "_pickup_" << c << "] " << agentName << "On" << c << " & !" << agentName << "_picked_up_" << c << " -> "; |
||||
|
os << "(" << agentName << "_picked_up_" << c << "'=true);\n"; |
||||
|
} |
||||
|
os << "\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printInitStruct(std::ostream &os, const AgentName &agentName) { |
||||
|
os << "init\n"; |
||||
|
os << "\t(!AgentIsInGoal & !AgentIsInLava & !AgentDone & !AgentIsOnWall)"; |
||||
|
if(enforceOneWays) { |
||||
|
os << " & ( !AgentCannotTurn ) "; |
||||
|
} else { |
||||
|
os << " & ( !AgentIsOnSlippery ) "; |
||||
|
} |
||||
|
os << "\nendinit\n\n"; |
||||
|
|
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printModule(std::ostream &os, const AgentName &agentName, const size_t &agentIndex, const coordinates &boundaries, const coordinates& initialPosition, const cells &keys, const std::map<Color, cells> &backgroundTiles, const bool agentWithView, const std::vector<float> &probabilities) { |
||||
|
os << "module " << agentName << "\n"; |
||||
|
os << "\tx" << agentName << " : [1.." << boundaries.second << "];\n"; |
||||
|
os << "\ty" << agentName << " : [1.." << boundaries.first << "];\n"; |
||||
|
printBooleansForKeys(os, agentName, keys); |
||||
|
printBooleansForBackground(os, agentName, backgroundTiles); |
||||
|
os << "\t" << agentName << "Done : bool;\n"; |
||||
|
if(agentWithView) { |
||||
|
os << "\tview" << agentName << " : [0..3];\n"; |
||||
|
os << "\n"; |
||||
|
os << "\t[" << agentName << "_turn_right] " << moveGuard(agentIndex) << " !" << agentName << "CannotTurn & " << " !" << agentName << "IsFixed & " << " !" << agentName << "IsInGoal & !" << agentName << "IsInLava & !" << agentName << "IsOnSlippery -> (view" << agentName << "'=mod(view" << agentName << " + 1, 4)) " << moveUpdate(agentIndex) << ";\n"; |
||||
|
os << "\t[" << agentName << "_turn_left] " << moveGuard(agentIndex) << " !" << agentName << "CannotTurn & " << " !" << agentName << "IsFixed & " << " !" << agentName << "IsInGoal & !" << agentName << "IsInLava & !" << agentName << "IsOnSlippery & view" << agentName << ">0 -> (view" << agentName << "'=view" << agentName << " - 1) " << moveUpdate(agentIndex) << ";\n"; |
||||
|
os << "\t[" << agentName << "_turn_left] " << moveGuard(agentIndex) << " !" << agentName << "CannotTurn & " << " !" << agentName << "IsFixed & " << " !" << agentName << "IsInGoal & !" << agentName << "IsInLava & !" << agentName << "IsOnSlippery & view" << agentName << "=0 -> (view" << agentName << "'=3) " << moveUpdate(agentIndex) << ";\n"; |
||||
|
if(enforceOneWays) { |
||||
|
os << "\t[" << agentName << "_stuck] !" << agentName << "IsFixed & " << agentName << "CannotTurn & view" << agentName << " = 0 & " << agentName << "CannotMoveEast -> true;\n"; |
||||
|
os << "\t[" << agentName << "_stuck] !" << agentName << "IsFixed & " << agentName << "CannotTurn & view" << agentName << " = 1 & " << agentName << "CannotMoveSouth -> true;\n"; |
||||
|
os << "\t[" << agentName << "_stuck] !" << agentName << "IsFixed & " << agentName << "CannotTurn & view" << agentName << " = 2 & " << agentName << "CannotMoveWest -> true;\n"; |
||||
|
os << "\t[" << agentName << "_stuck] !" << agentName << "IsFixed & " << agentName << "CannotTurn & view" << agentName << " = 3 & " << agentName << "CannotMoveNorth -> true;\n"; |
||||
|
} |
||||
|
} else { |
||||
|
os << "\t[" << agentName << "_turns] " << " !" << agentName << "CannotTurn & " << " !" << agentName << "IsFixed & " << moveGuard(agentIndex) << " true -> (x" << agentName << "'=x" << agentName << ")" << moveUpdate(agentIndex) << ";\n"; |
||||
|
} |
||||
|
printActionsForKeys(os, agentName, keys); |
||||
|
printActionsForBackground(os, agentName, backgroundTiles); |
||||
|
os << "\n"; |
||||
|
printMovementActions(os, agentName, agentIndex, agentWithView); |
||||
|
for(auto const& probability : probabilities) { |
||||
|
printMovementActions(os, agentName, agentIndex, agentWithView, probability); |
||||
|
} |
||||
|
printDoneActions(os, agentName, agentIndex); |
||||
|
os << "\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printMovementActions(std::ostream &os, const AgentName &agentName, const size_t &agentIndex, const bool agentWithView, const float &probability) { |
||||
|
if(probability >= 1) { |
||||
|
os << "\t[" << agentName << "_move_north]" << moveGuard(agentIndex) << viewVariable(agentName, 3, agentWithView) << " !" << agentName << "IsFixed & " << " !" << agentName << "IsOnSlippery & !" << agentName << "IsInLava &!" << agentName << "IsInGoal & !" << agentName << "CannotMoveNorth -> (y" << agentName << "'=y" << agentName << "-1)" << moveUpdate(agentIndex) << ";\n"; |
||||
|
os << "\t[" << agentName << "_move_east] " << moveGuard(agentIndex) << viewVariable(agentName, 0, agentWithView) << " !" << agentName << "IsFixed & " << " !" << agentName << "IsOnSlippery & !" << agentName << "IsInLava &!" << agentName << "IsInGoal & !" << agentName << "CannotMoveEast -> (x" << agentName << "'=x" << agentName << "+1)" << moveUpdate(agentIndex) << ";\n"; |
||||
|
os << "\t[" << agentName << "_move_south]" << moveGuard(agentIndex) << viewVariable(agentName, 1, agentWithView) << " !" << agentName << "IsFixed & " << " !" << agentName << "IsOnSlippery & !" << agentName << "IsInLava &!" << agentName << "IsInGoal & !" << agentName << "CannotMoveSouth -> (y" << agentName << "'=y" << agentName << "+1)" << moveUpdate(agentIndex) << ";\n"; |
||||
|
os << "\t[" << agentName << "_move_west] " << moveGuard(agentIndex) << viewVariable(agentName, 2, agentWithView) << " !" << agentName << "IsFixed & " << " !" << agentName << "IsOnSlippery & !" << agentName << "IsInLava &!" << agentName << "IsInGoal & !" << agentName << "CannotMoveWest -> (x" << agentName << "'=x" << agentName << "-1)" << moveUpdate(agentIndex) << ";\n"; |
||||
|
} else { |
||||
|
std::string probabilityString = std::to_string(probability); |
||||
|
std::string percentageString = std::to_string((int)(100 * probability)); |
||||
|
std::string complementProbabilityString = std::to_string(1 - probability); |
||||
|
os << "\t[" << agentName << "_move_north_" << percentageString << "] "; |
||||
|
os << moveGuard(agentIndex) << viewVariable(agentName, 3, agentWithView) << " !" << agentName << "IsFixed & " << " !" << agentName << "IsOnSlippery & !" << agentName << "IsInLava & !" << agentName << "CannotMoveNorth -> "; |
||||
|
os << probabilityString << ": (y" << agentName << "'=y" << agentName << "-1)" << moveUpdate(agentIndex) << " + "; |
||||
|
os << complementProbabilityString << ": (y" << agentName << "'=y" << agentName << ") " << moveUpdate(agentIndex) << ";\n"; |
||||
|
|
||||
|
os << "\t[" << agentName << "_move_east_" << percentageString << "] "; |
||||
|
os << moveGuard(agentIndex) << viewVariable(agentName, 0, agentWithView) << " !" << agentName << "IsFixed & " << " !" << agentName << "IsOnSlippery & !" << agentName << "IsInLava & !" << agentName << "CannotMoveEast -> "; |
||||
|
os << probabilityString << ": (x" << agentName << "'=x" << agentName << "+1)" << moveUpdate(agentIndex) << " + "; |
||||
|
os << complementProbabilityString << ": (x" << agentName << "'=x" << agentName << ") " << moveUpdate(agentIndex) << ";\n"; |
||||
|
|
||||
|
os << "\t[" << agentName << "_move_south_" << percentageString << "] "; |
||||
|
os << moveGuard(agentIndex) << viewVariable(agentName, 1, agentWithView) << " !" << agentName << "IsFixed & " << " !" << agentName << "IsOnSlippery & !" << agentName << "IsInLava & !" << agentName << "CannotMoveSouth -> "; |
||||
|
os << probabilityString << ": (y" << agentName << "'=y" << agentName << "+1)" << moveUpdate(agentIndex) << " + "; |
||||
|
os << complementProbabilityString << ": (y" << agentName << "'=y" << agentName << ") " << moveUpdate(agentIndex) << ";\n"; |
||||
|
|
||||
|
os << "\t[" << agentName << "_move_west_" << percentageString << "] "; |
||||
|
os << moveGuard(agentIndex) << viewVariable(agentName, 2, agentWithView) << " !" << agentName << "IsFixed & " << " !" << agentName << "IsOnSlippery & !" << agentName << "IsInLava & !" << agentName << "CannotMoveWest -> "; |
||||
|
os << probabilityString << ": (x" << agentName << "'=x" << agentName << "-1)" << moveUpdate(agentIndex) << " + "; |
||||
|
os << complementProbabilityString << ": (x" << agentName << "'=x" << agentName << ") " << moveUpdate(agentIndex) << ";\n"; |
||||
|
} |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printDoneActions(std::ostream &os, const AgentName &agentName, const size_t &agentIndex) { |
||||
|
os << "\t[" << agentName << "_done]" << moveGuard(agentIndex) << agentName << "IsInGoal | " << agentName << "IsInLava -> (" << agentName << "Done'=true);\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printSlipperyTurn(std::ostream &os, const AgentName &agentName, const size_t &agentIndex, const coordinates &c, std::set<std::string> &slipperyActions, const std::array<bool, 8>& neighborhood, SlipperyType orientation) { |
||||
|
constexpr std::size_t PROB_PIECES = 9, ALL_POSS_DIRECTIONS = 9; |
||||
|
|
||||
|
std::array<std::string, ALL_POSS_DIRECTIONS> positionTransition = { |
||||
|
/* north */ "(y" + agentName + "'=y" + agentName + "-1)", |
||||
|
/* north east */ "(x" + agentName + "'=x" + agentName + "+1) & (y" + agentName + "'=y" + agentName + "-1)", |
||||
|
/* east */ "(x" + agentName + "'=x" + agentName + "+1)", |
||||
|
/* east south */ "(x" + agentName + "'=x" + agentName + "+1) & (y" + agentName + "'=y" + agentName + "+1)", |
||||
|
/* south */ "(y" + agentName + "'=y" + agentName + "+1)", |
||||
|
/* south west */ "(x" + agentName + "'=x" + agentName + "-1) & (y" + agentName + "'=y" + agentName + "+1)", |
||||
|
/* west */ "(x" + agentName + "'=x" + agentName + "-1)", |
||||
|
/* north west */ "(x" + agentName + "'=x" + agentName + "-1) & (y" + agentName + "'=y" + agentName + "-1)", |
||||
|
/* own position */ "(x" + agentName + "'=x" + agentName + ") & (y" + agentName + "'=y" + agentName + ")" |
||||
|
}; |
||||
|
|
||||
|
// view transition appdx in form (guard, update part)
|
||||
|
// IMPORTANT: No mod() usage for turn left due to bug in mod() function for decrement
|
||||
|
|
||||
|
std::array<std::pair<std::string, std::string>, 3> viewTransition = { |
||||
|
/* turn to right */ std::make_pair(" & " + agentName + "SlipperyTurnRightAllowed ", " & (view" + agentName + "'=mod(view" + agentName + " + 1, 4))"), |
||||
|
/* turn to left */ std::make_pair(" & " + agentName + "SlipperyTurnLeftAllowed & view" + agentName + ">0", " & (view" + agentName + "'=view" + agentName + " - 1)"), |
||||
|
/* turn to left */ std::make_pair(" & " + agentName + "SlipperyTurnLeftAllowed & view" + agentName + "=0", " & (view" + agentName + "'=3)") |
||||
|
}; |
||||
|
|
||||
|
// direction specifics
|
||||
|
|
||||
|
std::string actionName; |
||||
|
std::size_t remainPosIndex = 8; |
||||
|
std::array<std::size_t, ALL_POSS_DIRECTIONS> prob_piece_dir; // { n, ne, w, se, s, sw, w, nw, CURRENT POS }
|
||||
|
|
||||
|
switch (orientation) |
||||
|
{ |
||||
|
case SlipperyType::North: |
||||
|
actionName = "\t[" + agentName + "turn_at_slip_north]"; |
||||
|
prob_piece_dir = { 0, 0, 0, 1, 1, 1, 0, 0, 0 /* <- R */ }; |
||||
|
break; |
||||
|
|
||||
|
case SlipperyType::South: |
||||
|
actionName = "\t[" + agentName + "turn_at_slip_south]"; |
||||
|
prob_piece_dir = { 1, 1, 0, 0, 0, 0, 0, 1, 0 /* <- R */ }; |
||||
|
break; |
||||
|
|
||||
|
case SlipperyType::East: |
||||
|
actionName = "\t[" + agentName + "turn_at_slip_east]"; |
||||
|
prob_piece_dir = { 0, 0, 0, 0, 0, 1, 1, 1, 0 /* <- R */ }; |
||||
|
break; |
||||
|
|
||||
|
case SlipperyType::West: |
||||
|
actionName = "\t[" + agentName + "turn_at_slip_west]"; |
||||
|
prob_piece_dir = { 0, 1, 1, 1, 0, 0, 0, 0, 0 /* <- R */ }; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
slipperyActions.insert(actionName); |
||||
|
|
||||
|
// override probability to 0 if corresp. direction is blocked
|
||||
|
|
||||
|
for (std::size_t i = 0; i < ALL_POSS_DIRECTIONS - 1; i++) { |
||||
|
if (!neighborhood.at(i)) |
||||
|
prob_piece_dir.at(i) = 0; |
||||
|
} |
||||
|
|
||||
|
// determine residual probability (R) by replacing 0 with (1 - overall sum)
|
||||
|
|
||||
|
prob_piece_dir.at(remainPosIndex) = PROB_PIECES - std::accumulate(prob_piece_dir.begin(), prob_piece_dir.end(), 0); |
||||
|
|
||||
|
// <DEBUG_AREA>
|
||||
|
{ |
||||
|
assert(prob_piece_dir.at(remainPosIndex) <= 9 && prob_piece_dir.at(remainPosIndex) >= 6 && "Value not in Range!"); |
||||
|
assert(std::accumulate(prob_piece_dir.begin(), prob_piece_dir.end(), 0) == PROB_PIECES && "Does not sum up to 1!"); |
||||
|
} |
||||
|
// </DEBUG_AREA>
|
||||
|
|
||||
|
|
||||
|
// generic output (for every view transition)
|
||||
|
for (std::size_t v = 0; v < viewTransition.size(); v++) { |
||||
|
|
||||
|
os << actionName << moveGuard(agentIndex) << " x" << agentName << "=" << c.second << " & y" << agentName << "=" << c.first << viewTransition.at(v).first; |
||||
|
for (std::size_t i = 0; i < ALL_POSS_DIRECTIONS; i++) { |
||||
|
os << (i == 0 ? " -> " : " + ") << prob_piece_dir.at(i) << "/" << PROB_PIECES << " : " << positionTransition.at(i) << viewTransition.at(v).second << moveUpdate(agentIndex) << (i == ALL_POSS_DIRECTIONS - 1 ? ";\n" : "\n"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printSlipperyMove(std::ostream &os, const AgentName &agentName, const size_t &agentIndex, const coordinates &c, std::set<std::string> &slipperyActions, const std::array<bool, 8>& neighborhood, SlipperyType orientation) { |
||||
|
constexpr std::size_t PROB_PIECES = 9, ALL_POSS_DIRECTIONS = 8; |
||||
|
|
||||
|
std::array<std::string, ALL_POSS_DIRECTIONS> positionTransition = { |
||||
|
/* north */ "(y" + agentName + "'=y" + agentName + "-1)", |
||||
|
/* north east */ "(x" + agentName + "'=x" + agentName + "+1) & (y" + agentName + "'=y" + agentName + "-1)", |
||||
|
/* east */ "(x" + agentName + "'=x" + agentName + "+1)", |
||||
|
/* east south */ "(x" + agentName + "'=x" + agentName + "+1) & (y" + agentName + "'=y" + agentName + "+1)", |
||||
|
/* south */ "(y" + agentName + "'=y" + agentName + "+1)", |
||||
|
/* south west */ "(x" + agentName + "'=x" + agentName + "-1) & (y" + agentName + "'=y" + agentName + "+1)", |
||||
|
/* west */ "(x" + agentName + "'=x" + agentName + "-1)", |
||||
|
/* north west */ "(x" + agentName + "'=x" + agentName + "-1) & (y" + agentName + "'=y" + agentName + "-1)" |
||||
|
}; |
||||
|
|
||||
|
// direction specifics
|
||||
|
|
||||
|
std::size_t straightPosIndex; |
||||
|
std::string actionName, specialTransition; // if straight ahead is blocked
|
||||
|
std::array<std::size_t, ALL_POSS_DIRECTIONS> prob_piece_dir; // { n, ne, w, se, s, sw, w, nw }
|
||||
|
|
||||
|
switch (orientation) |
||||
|
{ |
||||
|
case SlipperyType::North: |
||||
|
actionName = "\t[" + agentName + "move_on_slip_north]"; |
||||
|
prob_piece_dir = { 0, 0, 1, 2, 0 /* <- R */, 2, 1, 0 }; |
||||
|
straightPosIndex = 4; |
||||
|
specialTransition = "(y" + agentName + "'=y" + agentName + (!neighborhood.at(straightPosIndex) ? ")" : "+1)"); |
||||
|
break; |
||||
|
|
||||
|
case SlipperyType::South: |
||||
|
actionName = "\t[" + agentName + "move_on_slip_south]"; |
||||
|
prob_piece_dir = { 0 /* <- R */, 2, 1, 0, 0, 0, 1, 2 }; |
||||
|
straightPosIndex = 0; // always north
|
||||
|
specialTransition = "(y" + agentName + "'=y" + agentName + (!neighborhood.at(straightPosIndex) ? ")" : "-1)"); |
||||
|
break; |
||||
|
|
||||
|
case SlipperyType::East: |
||||
|
actionName = "\t[" + agentName + "move_on_slip_east]"; |
||||
|
prob_piece_dir = { 1, 0, 0, 0, 1, 2, 0 /* <- R */, 2 }; |
||||
|
straightPosIndex = 6; |
||||
|
specialTransition = "(x" + agentName + "'=x" + agentName + (!neighborhood.at(straightPosIndex) ? ")" : "-1)"); |
||||
|
break; |
||||
|
|
||||
|
case SlipperyType::West: |
||||
|
actionName = "\t[" + agentName + "move_on_slip_west]"; |
||||
|
prob_piece_dir = { 1, 2, 0 /* <- R */, 2, 1, 0, 0, 0 }; |
||||
|
straightPosIndex = 2; |
||||
|
specialTransition = "(x" + agentName + "'=x" + agentName + (!neighborhood.at(straightPosIndex) ? ")" : "+1)"); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
slipperyActions.insert(actionName); |
||||
|
|
||||
|
// override probability to 0 if corresp. direction is blocked
|
||||
|
|
||||
|
for (std::size_t i = 0; i < ALL_POSS_DIRECTIONS; i++) { |
||||
|
if (!neighborhood.at(i)) |
||||
|
prob_piece_dir.at(i) = 0; |
||||
|
} |
||||
|
|
||||
|
// determine residual probability (R) by replacing 0 with (1 - overall sum)
|
||||
|
if(enforceOneWays) { |
||||
|
prob_piece_dir = {0,0,0,0,0,0,0,0}; |
||||
|
} |
||||
|
prob_piece_dir.at(straightPosIndex) = PROB_PIECES - std::accumulate(prob_piece_dir.begin(), prob_piece_dir.end(), 0); |
||||
|
|
||||
|
// <DEBUG_AREA>
|
||||
|
{ |
||||
|
assert(prob_piece_dir.at(straightPosIndex) <= 9 && prob_piece_dir.at(straightPosIndex) >= 3 && "Value not in Range!"); |
||||
|
assert(std::accumulate(prob_piece_dir.begin(), prob_piece_dir.end(), 0) == PROB_PIECES && "Does not sum up to 1!"); |
||||
|
assert(orientation != SlipperyType::North || (prob_piece_dir.at(7) == 0 && prob_piece_dir.at(0) == 0 && prob_piece_dir.at(1) == 0 && "Slippery up should be impossible!")); |
||||
|
assert(orientation != SlipperyType::South || (prob_piece_dir.at(3) == 0 && prob_piece_dir.at(4) == 0 && prob_piece_dir.at(5) == 0 && "Slippery down should be impossible!")); |
||||
|
assert(orientation != SlipperyType::East || (prob_piece_dir.at(1) == 0 && prob_piece_dir.at(2) == 0 && prob_piece_dir.at(3) == 0 && "Slippery right should be impossible!")); |
||||
|
assert(orientation != SlipperyType::West || (prob_piece_dir.at(5) == 0 && prob_piece_dir.at(6) == 0 && prob_piece_dir.at(7) == 0 && "Slippery left should be impossible!")); |
||||
|
} |
||||
|
// </DEBUG_AREA>
|
||||
|
|
||||
|
// special case: straight forward is blocked (then remain in same position)
|
||||
|
|
||||
|
positionTransition.at(straightPosIndex) = specialTransition; |
||||
|
|
||||
|
// generic output (for every view and every possible view direction)
|
||||
|
|
||||
|
os << actionName << moveGuard(agentIndex) << " x" << agentName << "=" << c.second << " & y" << agentName << "=" << c.first << " & " << agentName << "SlipperyMoveForwardAllowed "; |
||||
|
|
||||
|
for (std::size_t i = 0; i < ALL_POSS_DIRECTIONS; i++) { |
||||
|
os << (i == 0 ? " -> " : " + ") << prob_piece_dir.at(i) << "/" << PROB_PIECES << " : " << positionTransition.at(i) << moveUpdate(agentIndex) << (i == ALL_POSS_DIRECTIONS - 1 ? ";\n" : "\n"); |
||||
|
} |
||||
|
|
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printEndmodule(std::ostream &os) { |
||||
|
os << "endmodule\n"; |
||||
|
os << "\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printPlayerStruct(std::ostream &os, const AgentName &agentName, const bool agentWithView, const std::vector<float> &probabilities, const std::set<std::string> &slipperyActions) { |
||||
|
os << "player " << agentName << "\n\t"; |
||||
|
bool first = true; |
||||
|
std::list<std::string> allActions = { "_move_north", "_move_east", "_move_south", "_move_west" }; |
||||
|
std::list<std::string> movementActions = allActions; |
||||
|
for(auto const& probability : probabilities) { |
||||
|
std::string percentageString = std::to_string((int)(100 * probability)); |
||||
|
for(auto const& movement : movementActions) { |
||||
|
allActions.push_back(movement + "_" + percentageString); |
||||
|
} |
||||
|
} |
||||
|
if(agentWithView) { |
||||
|
allActions.push_back("_turn_left"); |
||||
|
allActions.push_back("_turn_right"); |
||||
|
} else { |
||||
|
allActions.push_back("_turns"); |
||||
|
} |
||||
|
|
||||
|
for(auto const& action : allActions) { |
||||
|
if(first) first = false; else os << ", "; |
||||
|
os << "[" << agentName << action << "]"; |
||||
|
} |
||||
|
for(auto const& action : slipperyActions) { |
||||
|
os << ", " << action; |
||||
|
} |
||||
|
os << "\nendplayer\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printGlobalMoveVariable(std::ostream &os, const size_t &numberOfPlayer) { |
||||
|
os << "\nglobal move : [0.." << std::to_string(numberOfPlayer - 1) << "] init 0;\n\n"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::ostream& PrismModulesPrinter::printRewards(std::ostream &os, const AgentName &agentName, const std::map<coordinates, float> &stateRewards, const cells &lava, const cells &goals, const std::map<Color, cells> &backgroundTiles) { |
||||
|
if(lava.size() != 0) { |
||||
|
os << "rewards \"SafetyNoBFS\"\n"; |
||||
|
os << "\tAgentIsInLavaAndNotDone: -100;\n"; |
||||
|
os << "endrewards\n"; |
||||
|
} |
||||
|
|
||||
|
os << "rewards \"SafetyNoBFSAndGoal\"\n"; |
||||
|
if(goals.size() != 0) os << "\tAgentIsInGoalAndNotDone: 100;\n"; |
||||
|
if(lava.size() != 0) os << "\tAgentIsInLavaAndNotDone: -100;\n"; |
||||
|
os << "endrewards\n"; |
||||
|
|
||||
|
os << "rewards \"Time\"\n"; |
||||
|
os << "\t!AgentIsInGoal : -1;\n"; |
||||
|
if(goals.size() != 0) os << "\tAgentIsInGoalAndNotDone: 100;\n"; |
||||
|
if(lava.size() != 0) os << "\tAgentIsInLavaAndNotDone: -100;\n"; |
||||
|
os << "endrewards\n"; |
||||
|
|
||||
|
if(stateRewards.size() > 0) { |
||||
|
os << "rewards \"SafetyWithBFS\"\n"; |
||||
|
if(lava.size() != 0) os << "\tAgentIsInLavaAndNotDone: -100;\n"; |
||||
|
for(auto const [coordinates, reward] : stateRewards) { |
||||
|
os << "\txAgent=" << coordinates.first << "&yAgent=" << coordinates.second << " : " << reward << ";\n"; |
||||
|
} |
||||
|
os << "endrewards\n"; |
||||
|
} |
||||
|
if(stateRewards.size() > 0) { |
||||
|
os << "rewards \"SafetyWithBFSAndGoal\"\n"; |
||||
|
if(goals.size() != 0) os << "\tAgentIsInGoalAndNotDone: 100;\n"; |
||||
|
if(lava.size() != 0) os << "\tAgentIsInLavaAndNotDone: -100;\n"; |
||||
|
for(auto const [coordinates, reward] : stateRewards) { |
||||
|
os << "\txAgent=" << coordinates.first << "&yAgent=" << coordinates.second << " : " << reward << ";\n"; |
||||
|
} |
||||
|
os << "endrewards\n"; |
||||
|
} |
||||
|
|
||||
|
for(auto const entry : backgroundTiles) |
||||
|
{ |
||||
|
std::cout << getColor(entry.first) << " "; |
||||
|
for(auto const cell : entry.second){ |
||||
|
std::cout << cell.getCoordinates().first << " " << cell.getCoordinates().second << std::endl; |
||||
|
} |
||||
|
} |
||||
|
if(backgroundTiles.size() > 0) { |
||||
|
os << "rewards \"TaxiReward\"\n"; |
||||
|
os << "\t!AgentIsInGoal : -1;\n"; |
||||
|
std::string allPassengersPickedUp = ""; |
||||
|
bool first = true; |
||||
|
for(auto const [color, cells] : backgroundTiles) { |
||||
|
if(cells.size() == 0) continue; |
||||
|
if(first) first = false; else allPassengersPickedUp += "&"; |
||||
|
std::string c = getColor(color); |
||||
|
c.at(0) = std::toupper(c.at(0)); |
||||
|
std::string visitedLabel = agentName + "_picked_up_" + c; |
||||
|
allPassengersPickedUp += visitedLabel; |
||||
|
os << "[" << agentName << "_pickup_" << c << "] true : 100;\n"; |
||||
|
} |
||||
|
if(goals.size() != 0) os << "\tAgentIsInGoalAndNotDone & " << allPassengersPickedUp << " : 100;\n"; |
||||
|
if(goals.size() != 0) os << "\tAgentIsInGoalAndNotDone & !(" << allPassengersPickedUp << ") : -100;\n"; |
||||
|
os << "endrewards"; |
||||
|
} |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
std::string PrismModulesPrinter::moveGuard(const size_t &agentIndex) { |
||||
|
return isGame() ? " move=" + std::to_string(agentIndex) + " & " : " "; |
||||
|
} |
||||
|
|
||||
|
std::string PrismModulesPrinter::moveUpdate(const size_t &agentIndex) { |
||||
|
return isGame() ? |
||||
|
(agentIndex == numberOfPlayer - 1) ? |
||||
|
" & (move'=0) " : |
||||
|
" & (move'=" + std::to_string(agentIndex + 1) + ") " : |
||||
|
""; |
||||
|
} |
||||
|
|
||||
|
std::string PrismModulesPrinter::viewVariable(const AgentName &agentName, const size_t &agentDirection, const bool agentWithView) { |
||||
|
return agentWithView ? " view" + agentName + "=" + std::to_string(agentDirection) + " & " : " "; |
||||
|
} |
||||
|
|
||||
|
bool PrismModulesPrinter::isGame() const { |
||||
|
return modelType == ModelType::SMG; |
||||
|
} |
||||
|
} |
@ -0,0 +1,91 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <iostream> |
||||
|
#include <functional> |
||||
|
#include "MinigridGrammar.h" |
||||
|
#include "PrismPrinter.h" |
||||
|
|
||||
|
namespace prism { |
||||
|
class PrismModulesPrinter { |
||||
|
public: |
||||
|
PrismModulesPrinter(const ModelType &modelType, const size_t &numberOfPlayer, const bool enforceOneWays = false); |
||||
|
|
||||
|
std::ostream& printRestrictionFormula(std::ostream& os, const AgentName &agentName, const std::string &direction, const cells &cells); |
||||
|
std::ostream& printIsOnSlipperyFormula(std::ostream& os, const AgentName &agentName, const std::vector<std::reference_wrapper<cells>> &slipperyCollection, const cells &slipperyNorth, const cells &slipperyEast, const cells &slipperySouth, const cells &slipperyWest); |
||||
|
std::ostream& printGoalLabel(std::ostream& os, const AgentName&agentName, const cells &goals); |
||||
|
std::ostream& printCrashLabel(std::ostream &os, const std::vector<AgentName> agentNames); |
||||
|
std::ostream& printAvoidanceLabel(std::ostream &os, const std::vector<AgentName> agentNames, const int &distance); |
||||
|
std::ostream& printKeysLabels(std::ostream& os, const AgentName&agentName, const cells &keys); |
||||
|
std::ostream& printBackgroundLabels(std::ostream &os, const AgentName &agentName, const std::pair<Color, cells> &backgroundTiles); |
||||
|
std::ostream& printIsInLavaFormula(std::ostream& os, const AgentName &agentName, const cells &lava); |
||||
|
std::ostream& printIsFixedFormulas(std::ostream& os, const AgentName &agentName); |
||||
|
std::ostream& printTurningNotAllowedFormulas(std::ostream& os, const AgentName &agentName, const cells &floor); |
||||
|
std::ostream& printWallFormula(std::ostream& os, const AgentName &agentName, const cells &walls); |
||||
|
std::ostream& printFormulas(std::ostream& os, |
||||
|
const AgentName&agentName, |
||||
|
const cells &restrictionNorth, |
||||
|
const cells &restrictionEast, |
||||
|
const cells &restrictionSouth, |
||||
|
const cells &restrictionWest, |
||||
|
const std::vector<std::reference_wrapper<cells>> &slipperyCollection, |
||||
|
const cells &lava, |
||||
|
const cells &walls, |
||||
|
const cells &noTurnFloor, |
||||
|
const cells &slipperyNorth, |
||||
|
const cells &slipperyEast, |
||||
|
const cells &slipperySouth, |
||||
|
const cells &slipperyWest); |
||||
|
|
||||
|
/* |
||||
|
* Representation for Slippery Tile. |
||||
|
* -) North: Slips from North to South |
||||
|
* -) East: Slips from East to West |
||||
|
* -) South: Slips from South to North |
||||
|
* -) West: Slips from West to East |
||||
|
*/ |
||||
|
enum class SlipperyType { North, East, South, West }; |
||||
|
|
||||
|
/* |
||||
|
* Prints Slippery on move action. |
||||
|
* |
||||
|
* @param neighborhood: Information of wall-blocks in 8-neighborhood { n, nw, e, se, s, sw, w, nw }. If entry is false, then corresponding neighboorhood position is a wall. |
||||
|
* @param orientation: Information of slippery type (either north, south, east, west). |
||||
|
*/ |
||||
|
std::ostream& printSlipperyMove(std::ostream &os, const AgentName &agentName, const size_t &agentIndex, const coordinates &c, std::set<std::string> &slipperyActions, const std::array<bool, 8>& neighborhood, SlipperyType orientation); |
||||
|
|
||||
|
/* |
||||
|
* Prints Slippery on turn action. |
||||
|
* |
||||
|
* @param neighborhood: Information of wall-blocks in 8-neighborhood { n, nw, e, se, s, sw, w, nw }. If entry is false, then corresponding neighboorhood position is a wall. |
||||
|
* @param orientation: Information of slippery type (either north, south, east, west). |
||||
|
*/ |
||||
|
std::ostream& printSlipperyTurn(std::ostream &os, const AgentName &agentName, const size_t &agentIndex, const coordinates &c, std::set<std::string> &slipperyActions, const std::array<bool, 8>& neighborhood, SlipperyType orientation); |
||||
|
|
||||
|
std::ostream& printModel(std::ostream &os, const ModelType &modelType); |
||||
|
std::ostream& printBooleansForKeys(std::ostream &os, const AgentName &agentName, const cells &keys); |
||||
|
std::ostream& printActionsForKeys(std::ostream &os, const AgentName &agentName, const cells &keys); |
||||
|
std::ostream& printBooleansForBackground(std::ostream &os, const AgentName &agentName, const std::map<Color, cells> &backgroundTiles); |
||||
|
std::ostream& printActionsForBackground(std::ostream &os, const AgentName &agentName, const std::map<Color, cells> &backgroundTiles); |
||||
|
std::ostream& printInitStruct(std::ostream &os, const AgentName &agentName); |
||||
|
std::ostream& printModule(std::ostream &os, const AgentName &agentName, const size_t &agentIndex, const coordinates &boundaries, const coordinates& initialPosition, const cells &keys, const std::map<Color, cells> &backgroundTiles, const bool agentWithView, const std::vector<float> &probabilities = {}); |
||||
|
std::ostream& printMovementActions(std::ostream &os, const AgentName &agentName, const size_t &agentIndex, const bool agentWithView, const float &probability = 1.0); |
||||
|
std::ostream& printDoneActions(std::ostream &os, const AgentName &agentName, const size_t &agentIndex); |
||||
|
std::ostream& printEndmodule(std::ostream &os); |
||||
|
std::ostream& printPlayerStruct(std::ostream &os, const AgentName &agentName, const bool agentWithView, const std::vector<float> &probabilities = {}, const std::set<std::string> &slipperyActions = {}); |
||||
|
std::ostream& printGlobalMoveVariable(std::ostream &os, const size_t &numberOfPlayer); |
||||
|
|
||||
|
std::ostream& printRewards(std::ostream &os, const AgentName &agentName, const std::map<coordinates, float> &stateRewards, const cells &lava, const cells &goals, const std::map<Color, cells> &backgroundTiles); |
||||
|
|
||||
|
std::string moveGuard(const size_t &agentIndex); |
||||
|
std::string moveUpdate(const size_t &agentIndex); |
||||
|
|
||||
|
std::string viewVariable(const AgentName &agentName, const size_t &agentDirection, const bool agentWithView); |
||||
|
|
||||
|
bool isGame() const; |
||||
|
private: |
||||
|
|
||||
|
ModelType const& modelType; |
||||
|
const size_t numberOfPlayer; |
||||
|
bool enforceOneWays; |
||||
|
}; |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <string> |
||||
|
|
||||
|
#include "cell.h" |
||||
|
|
||||
|
typedef std::string AgentName; |
||||
|
typedef std::pair<std::string, coordinates> AgentNameAndPosition; |
||||
|
typedef std::map<AgentNameAndPosition::first_type, AgentNameAndPosition::second_type> AgentNameAndPositionMap; |
||||
|
|
||||
|
namespace prism { |
||||
|
enum class ModelType { |
||||
|
MDP, SMG |
||||
|
}; |
||||
|
} |
@ -0,0 +1,83 @@ |
|||||
|
#include "cell.h"
|
||||
|
|
||||
|
#include <stdexcept>
|
||||
|
|
||||
|
std::ostream &operator<<(std::ostream &os, const cell &c) { |
||||
|
os << static_cast<char>(c.type) << static_cast<char>(c.color); |
||||
|
os << " at (" << c.row << "," << c.column << ")"; |
||||
|
return os; |
||||
|
} |
||||
|
|
||||
|
cell cell::getNorth(const std::vector<cell> &grid) const { |
||||
|
auto north = std::find_if(grid.begin(), grid.end(), [this](const cell &c) { |
||||
|
return this->row - 1 == c.row && this->column == c.column; |
||||
|
}); |
||||
|
if(north == grid.end()) { |
||||
|
throw std::logic_error{ "Cannot get cell north of (" + std::to_string(row) + "," + std::to_string(column) + ")"}; |
||||
|
std::exit(EXIT_FAILURE); |
||||
|
} |
||||
|
return *north; |
||||
|
} |
||||
|
|
||||
|
cell cell::getEast(const std::vector<cell> &grid) const { |
||||
|
auto east = std::find_if(grid.begin(), grid.end(), [this](const cell &c) { |
||||
|
return this->row == c.row && this->column + 1 == c.column; |
||||
|
}); |
||||
|
if(east == grid.end()) { |
||||
|
throw std::logic_error{ "Cannot get cell east of (" + std::to_string(row) + "," + std::to_string(column) + ")"}; |
||||
|
std::exit(EXIT_FAILURE); |
||||
|
} |
||||
|
return *east; |
||||
|
} |
||||
|
|
||||
|
cell cell::getSouth(const std::vector<cell> &grid) const { |
||||
|
auto south = std::find_if(grid.begin(), grid.end(), [this](const cell &c) { |
||||
|
return this->row + 1 == c.row && this->column == c.column; |
||||
|
}); |
||||
|
if(south == grid.end()) { |
||||
|
throw std::logic_error{ "Cannot get cell south of (" + std::to_string(row) + "," + std::to_string(column) + ")"}; |
||||
|
std::exit(EXIT_FAILURE); |
||||
|
} |
||||
|
return *south; |
||||
|
} |
||||
|
|
||||
|
cell cell::getWest(const std::vector<cell> &grid) const { |
||||
|
auto west = std::find_if(grid.begin(), grid.end(), [this](const cell &c) { |
||||
|
return this->row == c.row && this->column - 1 == c.column; |
||||
|
}); |
||||
|
if(west == grid.end()) { |
||||
|
throw std::logic_error{ "Cannot get cell west of (" + std::to_string(row) + "," + std::to_string(column) + ")"}; |
||||
|
std::exit(EXIT_FAILURE); |
||||
|
} |
||||
|
return *west; |
||||
|
} |
||||
|
|
||||
|
coordinates cell::getCoordinates() const { |
||||
|
return std::make_pair(row, column); |
||||
|
} |
||||
|
|
||||
|
std::string cell::getColor() const { |
||||
|
switch(color) { |
||||
|
case Color::Red: return "red"; |
||||
|
case Color::Green: return "green"; |
||||
|
case Color::Blue: return "blue"; |
||||
|
case Color::Purple: return "purple"; |
||||
|
case Color::Yellow: return "yellow"; |
||||
|
case Color::None: return "transparent"; |
||||
|
default: return ""; |
||||
|
//case Color::Grey = 'G',
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
std::string getColor(Color color) { |
||||
|
switch(color) { |
||||
|
case Color::Red: return "red"; |
||||
|
case Color::Green: return "green"; |
||||
|
case Color::Blue: return "blue"; |
||||
|
case Color::Purple: return "purple"; |
||||
|
case Color::Yellow: return "yellow"; |
||||
|
case Color::None: return "transparent"; |
||||
|
default: return ""; |
||||
|
//case Color::Grey = 'G',
|
||||
|
} |
||||
|
} |
@ -0,0 +1,62 @@ |
|||||
|
#pragma once |
||||
|
|
||||
|
#include <iostream> |
||||
|
#include <utility> |
||||
|
#include <vector> |
||||
|
|
||||
|
typedef std::pair<int, int> coordinates; |
||||
|
|
||||
|
class Grid; |
||||
|
|
||||
|
enum class Type : char { |
||||
|
Wall = 'W', |
||||
|
Floor = ' ', |
||||
|
Door = 'D', |
||||
|
LockedDoor = 'L', |
||||
|
Key = 'K', |
||||
|
Ball = 'A', |
||||
|
Box = 'B', |
||||
|
Goal = 'G', |
||||
|
Lava = 'V', |
||||
|
Agent = 'X', |
||||
|
Adversary = 'Z', |
||||
|
SlipperyNorth = 'n', |
||||
|
SlipperySouth = 's', |
||||
|
SlipperyEast = 'e', |
||||
|
SlipperyWest = 'w' |
||||
|
}; |
||||
|
enum class Color : char { |
||||
|
Red = 'R', |
||||
|
Green = 'G', |
||||
|
Blue = 'B', |
||||
|
Purple = 'P', |
||||
|
Yellow = 'Y', |
||||
|
//Grey = 'G', |
||||
|
None = ' ' |
||||
|
}; |
||||
|
|
||||
|
constexpr std::initializer_list<Color> allColors = {Color::Red, Color::Green, Color::Blue, Color::Purple, Color::Yellow}; |
||||
|
std::string getColor(Color color); |
||||
|
|
||||
|
class cell { |
||||
|
public: |
||||
|
coordinates getNorth() const { return std::make_pair(row - 1, column); } |
||||
|
coordinates getSouth() const { return std::make_pair(row + 1, column); } |
||||
|
coordinates getEast() const { return std::make_pair(row, column + 1); } |
||||
|
coordinates getWest() const { return std::make_pair(row, column - 1); } |
||||
|
|
||||
|
cell getNorth(const std::vector<cell> &grid) const; |
||||
|
cell getEast(const std::vector<cell> &grid) const; |
||||
|
cell getSouth(const std::vector<cell> &grid) const; |
||||
|
cell getWest(const std::vector<cell> &grid) const; |
||||
|
|
||||
|
friend std::ostream& operator<<(std::ostream& os, const cell& cell); |
||||
|
|
||||
|
coordinates getCoordinates() const; |
||||
|
std::string getColor() const; |
||||
|
|
||||
|
int row; |
||||
|
int column; |
||||
|
Type type; |
||||
|
Color color; |
||||
|
}; |
1331
util/popl.hpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue