You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1022 lines
52 KiB

12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
  1. #include "PrismModulesPrinter.h"
  2. #include <map>
  3. #include <string>
  4. namespace prism {
  5. PrismModulesPrinter::PrismModulesPrinter(const ModelType &modelType, const size_t &numberOfPlayer, std::vector<Configuration> config, const bool enforceOneWays)
  6. : modelType(modelType), numberOfPlayer(numberOfPlayer), enforceOneWays(enforceOneWays), configuration(config), viewDirectionMapping({{0, "East"}, {1, "South"}, {2, "West"}, {3, "North"}}) {
  7. }
  8. std::ostream& PrismModulesPrinter::printModel(std::ostream &os, const ModelType &modelType) {
  9. switch(modelType) {
  10. case(ModelType::MDP):
  11. os << "mdp";
  12. break;
  13. case(ModelType::SMG):
  14. os << "smg";
  15. break;
  16. }
  17. os << "\n\n";
  18. return os;
  19. }
  20. std::ostream& PrismModulesPrinter::printBackgroundLabels(std::ostream &os, const AgentName &agentName, const std::pair<Color, cells> &backgroundTiles) {
  21. if(backgroundTiles.second.size() == 0) return os;
  22. bool first = true;
  23. std::string color = getColor(backgroundTiles.first);
  24. color.at(0) = std::toupper(color.at(0));
  25. os << "formula " << agentName << "On" << color << " = ";
  26. for(auto const& cell : backgroundTiles.second) {
  27. if(first) first = false; else os << " | ";
  28. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  29. }
  30. os << ";\n";
  31. os << "label \"" << agentName << "On" << color << "\" = " << agentName << "On" << color << ";\n";
  32. return os;
  33. }
  34. std::ostream& PrismModulesPrinter::printRestrictionFormula(std::ostream& os, const AgentName &agentName, const std::string &direction, const cells &grid_cells, const cells &keys, const cells &doors) {
  35. bool first = true;
  36. os << "formula " << agentName << "CannotMove" << direction << " = " ;
  37. for(auto const& cell : grid_cells) {
  38. if(first) first = false;
  39. else os << " | ";
  40. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  41. }
  42. if (!keys.empty()) {
  43. os << " | " << agentName << "CannotMove" << direction << "BecauseOfKey";
  44. }
  45. if (!doors.empty()) {
  46. os << " | " << agentName << "CannotMove" << direction << "BecauseOfDoor";
  47. }
  48. os << ";\n";
  49. return os;
  50. }
  51. std::ostream& PrismModulesPrinter::printKeyRestrictionFormula(std::ostream& os, const AgentName &agentName, const std::string &direction, const cells &keys) {
  52. bool first = true;
  53. os << "formula " << agentName << "CannotMove" << direction << "BecauseOfKey" << " = ";
  54. for (auto const& key : keys) {
  55. if(first) first = false;
  56. else os << " | ";
  57. std::string keyColor = key.getColor();
  58. std::string xKey = "xKey" + keyColor;
  59. std::string yKey = "yKey" + keyColor;
  60. coordinates coords;
  61. os << "(!" << agentName << "_has_" << keyColor << "_key & ";
  62. if (direction == "North") {
  63. os << " x" << agentName << " = " << xKey << "&y" << agentName << "-1 = " << yKey << ")";
  64. } else if (direction == "South") {
  65. os << " x" << agentName << " = " << xKey << "&y" << agentName << "+1 = " << yKey << ")";
  66. } else if (direction == "East") {
  67. os << " x" << agentName << "+1 = " << xKey << "&y" << agentName << " = " << yKey << ")";
  68. } else if (direction == "West") {
  69. os << " x" << agentName << "-1 = " << xKey << "&y" << agentName << " = " << yKey << ")";
  70. } else {
  71. os << "Invalid Direction! in Key Restriction";
  72. }
  73. }
  74. os << ";\n";
  75. return os;
  76. }
  77. std::ostream& PrismModulesPrinter::printDoorRestrictionFormula(std::ostream& os, const AgentName &agentName, const std::string &direction, const cells &doors) {
  78. bool first = true;
  79. os << "formula " << agentName << "CannotMove" << direction << "BecauseOfDoor" << " = ";
  80. for (auto const& door : doors) {
  81. if (first) first = false;
  82. else os << " | ";
  83. std::string doorColor = door.getColor();
  84. size_t y = door.getCoordinates().first;
  85. size_t x = door.getCoordinates().second;
  86. os << "(!Door" << doorColor << "open & ";
  87. if (direction == "North") {
  88. os << " x" << agentName << " = " << x << "&y" << agentName << "-1 = " << y << ")";
  89. } else if (direction == "South") {
  90. os << " x" << agentName << " = " << x << "&y" << agentName << "+1 = " << y << ")";
  91. } else if (direction == "East") {
  92. os << " x" << agentName << "+1 = " << x << "&y" << agentName << " = " << y << ")";
  93. } else if (direction == "West") {
  94. os << " x" << agentName << "-1 = " << y << "&y" << agentName << " = " << y << ")";
  95. } else {
  96. os << "Invalid Direction! in Key Restriction";
  97. }
  98. }
  99. os << ";\n";
  100. return os;
  101. }
  102. 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) {
  103. if(std::find_if(slipperyCollection.cbegin(), slipperyCollection.cend(), [=](const std::reference_wrapper<cells>& c) { return !c.get().empty(); }) == slipperyCollection.cend()) {
  104. os << "formula " << agentName << "IsOnSlippery = false;\n";
  105. return os;
  106. }
  107. bool first = true;
  108. if (!slipperyNorth.empty()) {
  109. os << "formula " << agentName << "IsOnSlipperyNorth = ";
  110. for (const auto& cell : slipperyNorth) {
  111. if(first) first = false; else os << " | ";
  112. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  113. }
  114. os << ";\n";
  115. }
  116. if (!slipperyEast.empty()) {
  117. first = true;
  118. os << "formula " << agentName << "IsOnSlipperyEast = ";
  119. for (const auto& cell : slipperyEast) {
  120. if(first) first = false; else os << " | ";
  121. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  122. }
  123. os << ";\n";
  124. }
  125. if (!slipperySouth.empty()) {
  126. first = true;
  127. os << "formula " << agentName << "IsOnSlipperySouth = ";
  128. for (const auto& cell : slipperySouth) {
  129. if(first) first = false; else os << " | ";
  130. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  131. }
  132. os << ";\n";
  133. }
  134. if (!slipperyWest.empty()) {
  135. first = true;
  136. os << "formula " << agentName << "IsOnSlipperyWest = ";
  137. for (const auto& cell : slipperyWest) {
  138. if(first) first = false; else os << " | ";
  139. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  140. }
  141. os << ";\n";
  142. }
  143. first = true;
  144. os << "formula " << agentName << "IsOnSlippery = ";
  145. for (const auto& slippery: slipperyCollection) {
  146. for(const auto& cell : slippery.get()) {
  147. if(first) first = false; else os << " | ";
  148. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  149. }
  150. }
  151. os << ";\n";
  152. if(enforceOneWays) {
  153. first = true;
  154. os << "formula " << agentName << "IsOnSlipperyNorth = ";
  155. for (const auto& cell: slipperyNorth) {
  156. if(first) first = false; else os << " | ";
  157. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  158. }
  159. os << ";\n";
  160. first = true;
  161. os << "formula " << agentName << "IsOnSlipperyEast = ";
  162. for (const auto& cell: slipperyEast) {
  163. if(first) first = false; else os << " | ";
  164. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  165. }
  166. os << ";\n";
  167. first = true;
  168. os << "formula " << agentName << "IsOnSlipperySouth = ";
  169. for (const auto& cell: slipperySouth) {
  170. if(first) first = false; else os << " | ";
  171. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  172. }
  173. os << ";\n";
  174. first = true;
  175. os << "formula " << agentName << "IsOnSlipperyWest = ";
  176. for (const auto& cell: slipperyWest) {
  177. if(first) first = false; else os << " | ";
  178. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  179. }
  180. os << ";\n";
  181. }
  182. return os;
  183. }
  184. std::ostream& PrismModulesPrinter::printIsInLavaFormula(std::ostream& os, const AgentName &agentName, const cells &lava) {
  185. if(lava.size() == 0) {
  186. os << "formula " << agentName << "IsInLava = false;\n";
  187. return os;
  188. }
  189. bool first = true;
  190. os << "formula " << agentName << "IsInLava = ";
  191. for(auto const& cell : lava) {
  192. if(first) first = false; else os << " | ";
  193. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  194. }
  195. os << ";\n";
  196. os << "formula " << agentName << "IsInLavaAndNotDone = " << agentName << "IsInLava & !" << agentName << "Done;\n";
  197. os << "label \"" << agentName << "IsInLavaAndNotDone\" = " << agentName << "IsInLava & !" << agentName << "Done;\n";
  198. return os;
  199. }
  200. std::ostream& PrismModulesPrinter::printTurningNotAllowedFormulas(std::ostream& os, const AgentName &agentName, const cells &noTurnFloor) {
  201. if( (!enforceOneWays or noTurnFloor.size() == 0) or (noTurnFloor.size() == 0) ) {
  202. os << "formula " << agentName << "CannotTurn = false;\n";
  203. return os;
  204. }
  205. bool first = true;
  206. os << "formula " << agentName << "CannotTurn = ";
  207. for(auto const& cell : noTurnFloor) {
  208. if(first) first = false; else os << " | ";
  209. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  210. }
  211. os << " | " << agentName << "IsOnSlippery;\n";
  212. return os;
  213. }
  214. std::ostream& PrismModulesPrinter::printIsFixedFormulas(std::ostream& os, const AgentName &agentName) {
  215. os << "formula " << agentName << "IsFixed = false;\n";
  216. os << "formula " << agentName << "SlipperyTurnLeftAllowed = true;\n";
  217. os << "formula " << agentName << "SlipperyTurnRightAllowed = true;\n";
  218. os << "formula " << agentName << "SlipperyMoveForwardAllowed = true;\n";
  219. os << "label \"FixedStates" << agentName << "\" = " << agentName << "IsFixed | !" << agentName << "SlipperyTurnRightAllowed | !" << agentName << "SlipperyTurnLeftAllowed | !" << agentName << "SlipperyMoveForwardAllowed | " << agentName << "IsInGoal | " << agentName << "IsInLava";
  220. if(enforceOneWays) {
  221. os << " | " << agentName << "CannotTurn";
  222. }
  223. os << ";\n";
  224. //os << "label \"FixedStates\" = " << agentName << "IsFixed | " << agentName << "IsOnSlippery | " << agentName << "IsInGoal | " << agentName << "IsInLava;\n";
  225. return os;
  226. }
  227. std::ostream& PrismModulesPrinter::printWallFormula(std::ostream& os, const AgentName &agentName, const cells &walls) {
  228. os << "formula " << agentName << "IsOnWall = ";
  229. bool first = true;
  230. for(auto const& cell : walls) {
  231. if(first) first = false; else os << " | ";
  232. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  233. }
  234. os << ";\n";
  235. return os;
  236. }
  237. std::ostream& PrismModulesPrinter::printFormulas(std::ostream& os,
  238. const AgentName &agentName,
  239. const cells &restrictionNorth,
  240. const cells &restrictionEast,
  241. const cells &restrictionSouth,
  242. const cells &restrictionWest,
  243. const std::vector<std::reference_wrapper<cells>> &slipperyCollection,
  244. const cells &lava,
  245. const cells &walls,
  246. const cells &noTurnFloor,
  247. const cells &slipperyNorth,
  248. const cells &slipperyEast,
  249. const cells &slipperySouth,
  250. const cells &slipperyWest,
  251. const cells &keys,
  252. const cells &doors) {
  253. printRestrictionFormula(os, agentName, "North", restrictionNorth, keys, doors);
  254. printRestrictionFormula(os, agentName, "East", restrictionEast, keys, doors);
  255. printRestrictionFormula(os, agentName, "South", restrictionSouth, keys, doors);
  256. printRestrictionFormula(os, agentName, "West", restrictionWest, keys, doors);
  257. if (!keys.empty()) {
  258. printKeyRestrictionFormula(os, agentName, "North", keys);
  259. printKeyRestrictionFormula(os, agentName, "East", keys);
  260. printKeyRestrictionFormula(os, agentName, "South", keys);
  261. printKeyRestrictionFormula(os, agentName, "West", keys);
  262. }
  263. if (!doors.empty()) {
  264. printDoorRestrictionFormula(os, agentName, "North", doors);
  265. printDoorRestrictionFormula(os, agentName, "East", doors);
  266. printDoorRestrictionFormula(os, agentName, "South", doors);
  267. printDoorRestrictionFormula(os, agentName, "West", doors);
  268. }
  269. printIsOnSlipperyFormula(os, agentName, slipperyCollection, slipperyNorth, slipperyEast, slipperySouth, slipperyWest);
  270. printIsInLavaFormula(os, agentName, lava);
  271. printWallFormula(os, agentName, walls);
  272. printTurningNotAllowedFormulas(os, agentName, noTurnFloor);
  273. printIsFixedFormulas(os, agentName);
  274. os << "\n";
  275. return os;
  276. }
  277. std::ostream& PrismModulesPrinter::printGoalLabel(std::ostream& os, const AgentName &agentName, const cells &goals) {
  278. if(goals.size() == 0) {
  279. os << "formula " << agentName << "IsInGoal = false;\n";
  280. return os;
  281. }
  282. bool first = true;
  283. os << "formula " << agentName << "IsInGoal = ";
  284. for(auto const& cell : goals) {
  285. if(first) first = false; else os << " | ";
  286. os << "(x" << agentName << "=" << cell.column << "&y" << agentName << "=" << cell.row << ")";
  287. }
  288. os << ";\n";
  289. os << "formula " << agentName << "IsInGoalAndNotDone = " << agentName << "IsInGoal & !" << agentName << "Done;\n";
  290. os << "label \"" << agentName << "IsInGoalAndNotDone\" = " << agentName << "IsInGoal & !" << agentName << "Done;\n";
  291. return os;
  292. }
  293. std::ostream& PrismModulesPrinter::printCrashLabel(std::ostream &os, const std::vector<AgentName> agentNames) {
  294. os << "label crash = ";
  295. bool first = true;
  296. for(auto const& agentName : agentNames) {
  297. if(agentName == "Agent") continue;
  298. if(first) first = false; else os << " | ";
  299. os << "(xAgent=x" << agentName << ")&(yAgent=y" << agentName << ")";
  300. }
  301. os << ";\n\n";
  302. return os;
  303. }
  304. std::ostream& PrismModulesPrinter::printConfiguration(std::ostream& os, const std::vector<Configuration>& configurations) {
  305. for (auto& configuration : configurations) {
  306. if (configuration.overwrite_ || configuration.type_ == ConfigType::Module) {
  307. continue;
  308. }
  309. os << configuration.expression_ << std::endl;
  310. }
  311. return os;
  312. }
  313. std::ostream& PrismModulesPrinter::printConstants(std::ostream &os, const std::vector<std::string> &constants) {
  314. for (auto& constant : constants) {
  315. os << constant << std::endl;
  316. }
  317. return os;
  318. }
  319. std::ostream& PrismModulesPrinter::printAvoidanceLabel(std::ostream &os, const std::vector<AgentName> agentNames, const int &distance) {
  320. os << "label avoidance = ";
  321. bool first = true;
  322. for(auto const& agentName : agentNames) {
  323. if(agentName == "Agent") continue;
  324. if(first) first = false; else os << " | ";
  325. os << "max(xAgent-x" << agentName << ",x" << agentName << "-xAgent)+";
  326. os << "max(yAgent-y" << agentName << ",y" << agentName << "-yAgent) ";
  327. }
  328. os << ";\n\n";
  329. return os;
  330. }
  331. // TODO this does not account for multiple agents yet, i.e. key can be picked up multiple times
  332. std::ostream& PrismModulesPrinter::printKeysLabels(std::ostream& os, const AgentName &agentName, const cells &keys) {
  333. if(keys.size() == 0) return os;
  334. for(auto const& key : keys) {
  335. std::string keyColor = key.getColor();
  336. std::string xKey = "xKey" + keyColor;
  337. std::string yKey = "yKey" + keyColor;
  338. os << "label \"" << agentName << "PickedUp" << keyColor << "Key\" = " << agentName << "_has_" << keyColor << "_key = true;\n";
  339. os << "formula " << agentName << "CanPickUp" << keyColor << "Key = ";
  340. os << "((x" << agentName << "-1 = " << xKey << "&y" << agentName << " = " << yKey << "&view" << agentName << " = 2) |";
  341. os << " (x" << agentName << "+1 = " << xKey << "&y" << agentName << " = " << yKey << "&view" << agentName << " = 0) |";
  342. os << " (x" << agentName << " = " << xKey << "&y" << agentName << "-1 = " << yKey << "&view" << agentName << " = 3) |";
  343. os << " (x" << agentName << " = " << xKey << "&y" << agentName << "+1 = " << yKey << "&view" << agentName << " = 1) ) &";
  344. os << "!" << agentName << "_has_" << keyColor << "_key;";
  345. }
  346. os << "\n";
  347. return os;
  348. }
  349. std::ostream& PrismModulesPrinter::printBooleansForKeys(std::ostream &os, const AgentName &agentName, const cells &keys) {
  350. for(auto const& key : keys) {
  351. os << "\t" << agentName << "_has_"<< key.getColor() << "_key : bool;\n";//init false;\n";
  352. }
  353. os << "\n";
  354. return os;
  355. }
  356. std::ostream& PrismModulesPrinter::printBooleansForBackground(std::ostream &os, const AgentName &agentName, const std::map<Color, cells> &backgroundTiles) {
  357. for(auto const& [color, cells] : backgroundTiles) {
  358. if(cells.size() == 0) continue;
  359. std::string c = getColor(color);
  360. c.at(0) = std::toupper(c.at(0));
  361. os << "\t" << agentName << "_picked_up_" << c << " : bool init false;\n";
  362. }
  363. os << "\n";
  364. return os;
  365. }
  366. std::ostream& PrismModulesPrinter::printActionsForKeys(std::ostream &os, const AgentName &agentName, const cells &keys) {
  367. for(auto const& key : keys) { // TODO ADD Drop action and enforce that pickup only possible if pockets empty (nothing picked up already)
  368. os << "\n";
  369. std::string keyColor = key.getColor();
  370. os << "\t[pickup_" << keyColor << "_key]\t" << pickupGuard(agentName, keyColor) << "-> ";
  371. os << "(" << agentName << "_has_" << keyColor << "_key'=true) & (" << agentName << "_is_carrying_object'=true);\n";
  372. os << "\n";
  373. os << "\t[drop_" << keyColor << "_key_north]\t" << dropGuard(agentName, keyColor, 3) << "-> ";
  374. os << "(" << agentName << "_has_" << keyColor << "_key'=false) & (" << agentName << "_is_carrying_object'=false);\n";
  375. os << "\t[drop_" << keyColor << "_key_west]\t" << dropGuard(agentName, keyColor, 2) << "-> ";
  376. os << "(" << agentName << "_has_" << keyColor << "_key'=false) & (" << agentName << "_is_carrying_object'=false);\n";
  377. os << "\t[drop_" << keyColor << "_key_south]\t" << dropGuard(agentName, keyColor, 1) << "-> ";
  378. os << "(" << agentName << "_has_" << keyColor << "_key'=false) & (" << agentName << "_is_carrying_object'=false);\n";
  379. os << "\t[drop_" << keyColor << "_key_east]\t" << dropGuard(agentName, keyColor, 0) << "-> ";
  380. os << "(" << agentName << "_has_" << keyColor << "_key'=false) & (" << agentName << "_is_carrying_object'=false);\n";
  381. }
  382. return os;
  383. }
  384. std::string PrismModulesPrinter::pickupGuard(const AgentName &agentName, const std::string keyColor ) {
  385. return "!" + agentName + "_is_carrying_object &\t" + agentName + "CanPickUp" + keyColor + "Key ";
  386. }
  387. std::string PrismModulesPrinter::dropGuard(const AgentName &agentName, const std::string keyColor, size_t view) {
  388. return viewVariable(agentName, view, true) + "\t!" + agentName + "CannotMove" + viewDirectionMapping.at(view) + "\t&\t" + agentName + "_has_" + keyColor + "_key\t";
  389. }
  390. std::ostream& PrismModulesPrinter::printActionsForBackground(std::ostream &os, const AgentName &agentName, const std::map<Color, cells> &backgroundTiles) {
  391. for(auto const& [color, cells] : backgroundTiles) {
  392. if(cells.size() == 0) continue;
  393. std::string c = getColor(color);
  394. c.at(0) = std::toupper(c.at(0));
  395. os << "\t[" << agentName << "_pickup_" << c << "] " << agentName << "On" << c << " & !" << agentName << "_picked_up_" << c << " -> ";
  396. os << "(" << agentName << "_picked_up_" << c << "'=true);\n";
  397. }
  398. os << "\n";
  399. return os;
  400. }
  401. std::ostream& PrismModulesPrinter::printInitStruct(std::ostream &os, const AgentNameAndPositionMap &agents, const KeyNameAndPositionMap &keys, const cells &lockedDoors, const cells &unlockedDoors, prism::ModelType modelType) {
  402. os << "init\n";
  403. os << "\t";
  404. bool first = true;
  405. for (auto const& agent : agents) {
  406. if (first) first = false;
  407. else os << " & ";
  408. os << "(!" << agent.first << "IsInGoal & !" << agent.first << "IsInLava & !" << agent.first << "Done & !" << agent.first << "IsOnWall & ";
  409. os << "x" << agent.first << "=" << agent.second.second << " & y" << agent.first << "=" << agent.second.first << ")";
  410. os << " & !" << agent.first << "_is_carrying_object";
  411. if(enforceOneWays) {
  412. os << " & ( !AgentCannotTurn ) ";
  413. } else {
  414. os << " & ( !AgentIsOnSlippery ) ";
  415. }
  416. for (auto const& key : keys) {
  417. os << " & ( !" << agent.first << "_has_" << key.first << "_key )";
  418. }
  419. }
  420. for (auto const& key : keys) {
  421. os << " & ( xKey" << key.first << "="<< key.second.second<< ")";
  422. os << " & ( yKey" << key.first << "=" << key.second.first << ")";
  423. }
  424. for (auto const& locked : lockedDoors) {
  425. os << " & (Door" << locked.getColor() << "locked & !Door" << locked.getColor() << "open)";
  426. }
  427. for (auto const& unlocked : unlockedDoors) {
  428. os << " & (!Door" << unlocked.getColor() << "locked & !Door" << unlocked.getColor() << "open)";
  429. }
  430. if (modelType == ModelType::SMG) {
  431. os << " & move=0";
  432. }
  433. os << "\nendinit\n\n";
  434. return os;
  435. }
  436. 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) {
  437. os << "module " << agentName << "\n";
  438. os << "\tx" << agentName << " : [1.." << boundaries.second << "];\n";
  439. os << "\ty" << agentName << " : [1.." << boundaries.first << "];\n";
  440. os << "\t" << agentName << "_is_carrying_object : bool;\n";
  441. printBooleansForKeys(os, agentName, keys);
  442. printBooleansForBackground(os, agentName, backgroundTiles);
  443. os << "\t" << agentName << "Done : bool;\n";
  444. if(agentWithView) {
  445. os << "\tview" << agentName << " : [0..3];\n";
  446. os << "\n";
  447. 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";
  448. 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";
  449. 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";
  450. if(enforceOneWays) {
  451. os << "\t[" << agentName << "_stuck] !" << agentName << "IsFixed & " << agentName << "CannotTurn & view" << agentName << " = 0 & " << agentName << "CannotMoveEast -> true;\n";
  452. os << "\t[" << agentName << "_stuck] !" << agentName << "IsFixed & " << agentName << "CannotTurn & view" << agentName << " = 1 & " << agentName << "CannotMoveSouth -> true;\n";
  453. os << "\t[" << agentName << "_stuck] !" << agentName << "IsFixed & " << agentName << "CannotTurn & view" << agentName << " = 2 & " << agentName << "CannotMoveWest -> true;\n";
  454. os << "\t[" << agentName << "_stuck] !" << agentName << "IsFixed & " << agentName << "CannotTurn & view" << agentName << " = 3 & " << agentName << "CannotMoveNorth -> true;\n";
  455. }
  456. } else {
  457. os << "\t[" << agentName << "_turns] " << " !" << agentName << "CannotTurn & " << " !" << agentName << "IsFixed & " << moveGuard(agentIndex) << " true -> (x" << agentName << "'=x" << agentName << ")" << moveUpdate(agentIndex) << ";\n";
  458. }
  459. printActionsForKeys(os, agentName, keys);
  460. printActionsForBackground(os, agentName, backgroundTiles);
  461. os << "\n";
  462. printMovementActions(os, agentName, agentIndex, agentWithView);
  463. for(auto const& probability : probabilities) {
  464. printMovementActions(os, agentName, agentIndex, agentWithView, probability);
  465. }
  466. printDoneActions(os, agentName, agentIndex);
  467. printConfiguredActions(os, agentName);
  468. os << "\n";
  469. return os;
  470. }
  471. std::ostream& PrismModulesPrinter::printKeyModule(std::ostream &os, const cell &key, const coordinates &boundaries, AgentName agentName) {
  472. std::string keyIdentifier = "Key" + key.getColor();
  473. os << "module " << keyIdentifier << "\n";
  474. os << "\tx" << keyIdentifier << " : [-1.." << boundaries.second << "];\n";
  475. os << "\ty" << keyIdentifier << " : [-1.." << boundaries.first << "];\n";
  476. os << "\n";
  477. printKeyActions(os, key ,keyIdentifier, agentName);
  478. os << "\n";
  479. return os;
  480. }
  481. std::ostream& PrismModulesPrinter::printKeyActions(std::ostream &os, const cell &key ,const std::string &keyIdentifier, AgentName agentName) {
  482. std::string keyColor = key.getColor();
  483. os << "\t[pickup_" << keyColor << "key]\t" << pickupGuard(agentName, keyColor) << "-> ";
  484. os << "(xKey" << keyColor << "'=-1) & (yKey" << keyColor << "'=-1)" << ";\n";
  485. os << "\t[drop_" << keyColor << "_key_north]\t" << dropGuard(agentName, keyColor, 3) << "-> ";
  486. os << "(xKey" << keyColor << "'=x" << agentName << ") & (yKey" << keyColor << "'=y" <<agentName << "-1) ;\n";
  487. os << "\t[drop_" << keyColor << "_key_west]\t" << dropGuard(agentName, keyColor, 2) << "-> ";
  488. os << "(xKey" << keyColor << "'=x" << agentName << "-1) & (yKey" << keyColor << "'=y" <<agentName << ") ;\n";
  489. os << "\t[drop_" << keyColor << "_key_south]\t" << dropGuard(agentName, keyColor, 1) << "-> ";
  490. os << "(xKey" << keyColor << "'=x" << agentName << ") & (yKey" << keyColor << "'=y" <<agentName << "+1) ;\n";
  491. os << "\t[drop_" << keyColor << "_key_east]\t" << dropGuard(agentName, keyColor, 0) << "-> ";
  492. os << "(xKey" << keyColor << "'=x" << agentName << "+1) & (yKey" << keyColor << "'=y" <<agentName << ") ;\n";
  493. return os;
  494. }
  495. std::ostream& PrismModulesPrinter::printDoorModule(std::ostream &os, const cell &door, const coordinates &boundaries, AgentName agent) {
  496. std::string doorIdentifier = "Door" + door.getColor();
  497. os << "module " << doorIdentifier << "\n";
  498. os << "\t" << doorIdentifier << "locked : bool;\n";
  499. os << "\t" << doorIdentifier << "open : bool;\n";
  500. printDoorActions(os, door, doorIdentifier, agent);
  501. return os;
  502. }
  503. std::ostream& PrismModulesPrinter::printDoorActions(std::ostream &os, const cell &door ,const std::string &doorIdentifier, AgentName agentName) {
  504. os << "\t[" << "unlock_" << doorIdentifier << "]\t" << unlockGuard(agentName, door) << " -> ";
  505. os << "(" << doorIdentifier << "locked'=false) & (" << doorIdentifier << "open'=true) ;\n";
  506. os << "\t[" << "toggle_" << doorIdentifier << "]\t" << toggleGuard(agentName, door) << " -> ";
  507. os << "(" << doorIdentifier << "open'=!" << doorIdentifier << "open) ;\n";
  508. return os;
  509. }
  510. std::string PrismModulesPrinter::unlockGuard(const AgentName &agentName, const cell& door) {
  511. std::string doorColor = door.getColor();
  512. std::string ret;
  513. ret += agentName + "_has_" + doorColor + "_key & ";
  514. ret += "((" + viewVariable(agentName, 0, true) + "x" + agentName + "+ 1 = " + std::to_string(door.column) + " & y" + agentName + "= " + std::to_string(door.row) + ")";
  515. ret += " | (" + viewVariable(agentName, 1, true) + "x" + agentName + " = " + std::to_string(door.column) + " & y" + agentName + " + 1 = " + std::to_string(door.row) + ")";
  516. ret += " | (" + viewVariable(agentName, 2, true) + "x" + agentName + "- 1 = " + std::to_string(door.column) + " & y" + agentName + "= " + std::to_string(door.row) + ")";
  517. ret += " | (" + viewVariable(agentName, 3, true) + "x" + agentName + " = " + std::to_string(door.column) + " & y" + agentName + " - 1 = " + std::to_string(door.row) + "))";
  518. return ret;
  519. }
  520. std::string PrismModulesPrinter::toggleGuard(const AgentName &agentName, const cell& door) {
  521. std::string doorColor = door.getColor();
  522. std::string ret;
  523. ret += "!Door" + doorColor + "locked & (";
  524. ret += "(" + viewVariable(agentName, 0, true) + "x" + agentName + "+ 1 = " + std::to_string(door.column) + " & y" + agentName + "= " + std::to_string(door.row) + ")";
  525. ret += " | (" + viewVariable(agentName, 1, true) + "x" + agentName + " = " + std::to_string(door.column) + " & y" + agentName + " + 1 = " + std::to_string(door.row) + ")";
  526. ret += " | (" + viewVariable(agentName, 2, true) + "x" + agentName + "- 1 = " + std::to_string(door.column) + " & y" + agentName + "= " + std::to_string(door.row) + ")";
  527. ret += " | (" + viewVariable(agentName, 3, true) + "x" + agentName + " = " + std::to_string(door.column) + " & y" + agentName + " - 1 = " + std::to_string(door.row) + "))";
  528. return ret;
  529. }
  530. std::ostream& PrismModulesPrinter::printConfiguredActions(std::ostream &os, const AgentName &agentName) {
  531. for (auto& config : configuration) {
  532. if (config.type_ == ConfigType::Module && !config.overwrite_ && agentName == config.module_) {
  533. os << config.expression_ ;
  534. }
  535. }
  536. os << "\n";
  537. return os;
  538. }
  539. std::ostream& PrismModulesPrinter::printMovementActions(std::ostream &os, const AgentName &agentName, const size_t &agentIndex, const bool agentWithView, const float &probability) {
  540. if(probability >= 1) {
  541. 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";
  542. 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";
  543. 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";
  544. 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";
  545. } else {
  546. std::string probabilityString = std::to_string(probability);
  547. std::string percentageString = std::to_string((int)(100 * probability));
  548. std::string complementProbabilityString = std::to_string(1 - probability);
  549. os << "\t[" << agentName << "_move_north_" << percentageString << "] ";
  550. os << moveGuard(agentIndex) << viewVariable(agentName, 3, agentWithView) << " !" << agentName << "IsFixed & " << " !" << agentName << "IsOnSlippery & !" << agentName << "IsInLava & !" << agentName << "CannotMoveNorth -> ";
  551. os << probabilityString << ": (y" << agentName << "'=y" << agentName << "-1)" << moveUpdate(agentIndex) << " + ";
  552. os << complementProbabilityString << ": (y" << agentName << "'=y" << agentName << ") " << moveUpdate(agentIndex) << ";\n";
  553. os << "\t[" << agentName << "_move_east_" << percentageString << "] ";
  554. os << moveGuard(agentIndex) << viewVariable(agentName, 0, agentWithView) << " !" << agentName << "IsFixed & " << " !" << agentName << "IsOnSlippery & !" << agentName << "IsInLava & !" << agentName << "CannotMoveEast -> ";
  555. os << probabilityString << ": (x" << agentName << "'=x" << agentName << "+1)" << moveUpdate(agentIndex) << " + ";
  556. os << complementProbabilityString << ": (x" << agentName << "'=x" << agentName << ") " << moveUpdate(agentIndex) << ";\n";
  557. os << "\t[" << agentName << "_move_south_" << percentageString << "] ";
  558. os << moveGuard(agentIndex) << viewVariable(agentName, 1, agentWithView) << " !" << agentName << "IsFixed & " << " !" << agentName << "IsOnSlippery & !" << agentName << "IsInLava & !" << agentName << "CannotMoveSouth -> ";
  559. os << probabilityString << ": (y" << agentName << "'=y" << agentName << "+1)" << moveUpdate(agentIndex) << " + ";
  560. os << complementProbabilityString << ": (y" << agentName << "'=y" << agentName << ") " << moveUpdate(agentIndex) << ";\n";
  561. os << "\t[" << agentName << "_move_west_" << percentageString << "] ";
  562. os << moveGuard(agentIndex) << viewVariable(agentName, 2, agentWithView) << " !" << agentName << "IsFixed & " << " !" << agentName << "IsOnSlippery & !" << agentName << "IsInLava & !" << agentName << "CannotMoveWest -> ";
  563. os << probabilityString << ": (x" << agentName << "'=x" << agentName << "-1)" << moveUpdate(agentIndex) << " + ";
  564. os << complementProbabilityString << ": (x" << agentName << "'=x" << agentName << ") " << moveUpdate(agentIndex) << ";\n";
  565. }
  566. return os;
  567. }
  568. std::ostream& PrismModulesPrinter::printDoneActions(std::ostream &os, const AgentName &agentName, const size_t &agentIndex) {
  569. os << "\t[" << agentName << "_done]" << moveGuard(agentIndex) << agentName << "IsInGoal | " << agentName << "IsInLava -> (" << agentName << "Done'=true);\n";
  570. return os;
  571. }
  572. 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) {
  573. constexpr std::size_t PROB_PIECES = 9, ALL_POSS_DIRECTIONS = 9;
  574. std::array<std::string, ALL_POSS_DIRECTIONS> positionTransition = {
  575. /* north */ "(y" + agentName + "'=y" + agentName + "-1)",
  576. /* north east */ "(x" + agentName + "'=x" + agentName + "+1) & (y" + agentName + "'=y" + agentName + "-1)",
  577. /* east */ "(x" + agentName + "'=x" + agentName + "+1)",
  578. /* east south */ "(x" + agentName + "'=x" + agentName + "+1) & (y" + agentName + "'=y" + agentName + "+1)",
  579. /* south */ "(y" + agentName + "'=y" + agentName + "+1)",
  580. /* south west */ "(x" + agentName + "'=x" + agentName + "-1) & (y" + agentName + "'=y" + agentName + "+1)",
  581. /* west */ "(x" + agentName + "'=x" + agentName + "-1)",
  582. /* north west */ "(x" + agentName + "'=x" + agentName + "-1) & (y" + agentName + "'=y" + agentName + "-1)",
  583. /* own position */ "(x" + agentName + "'=x" + agentName + ") & (y" + agentName + "'=y" + agentName + ")"
  584. };
  585. // view transition appdx in form (guard, update part)
  586. // IMPORTANT: No mod() usage for turn left due to bug in mod() function for decrement
  587. std::array<std::tuple<std::string, std::string, std::string>, 3> viewTransition = {
  588. std::make_tuple(" & " + agentName + "SlipperyTurnRightAllowed ", " & (view" + agentName + "'=mod(view" + agentName + " + 1, 4))", "_right]"),
  589. std::make_tuple(" & " + agentName + "SlipperyTurnLeftAllowed & view" + agentName + ">0", " & (view" + agentName + "'=view" + agentName + " - 1)", "_left]"),
  590. std::make_tuple(" & " + agentName + "SlipperyTurnLeftAllowed & view" + agentName + "=0", " & (view" + agentName + "'=3)", "_left]")
  591. };
  592. // direction specifics
  593. std::string actionName;
  594. std::string positionGuard;
  595. std::size_t remainPosIndex = 8;
  596. std::array<std::size_t, ALL_POSS_DIRECTIONS> prob_piece_dir; // { n, ne, w, se, s, sw, w, nw, CURRENT POS }
  597. std::array<std::string, ALL_POSS_DIRECTIONS> prob_piece_dir_constants;
  598. switch (orientation)
  599. {
  600. case SlipperyType::North:
  601. actionName = "\t[" + agentName + "turn_at_slip_north";
  602. positionGuard = "\t" + agentName + "IsOnSlipperyNorth";
  603. prob_piece_dir = { 0, 0, 0, 1, 1, 1, 0, 0, 0 /* <- R */ };
  604. prob_piece_dir_constants = { "prop_zero", "prop_zero", "prop_zero", "prop_next_neighbour", "prop_next_neighbour" /* <- R */, "prop_next_neighbour", "prop_zero", "prop_zero","prop_zero" };
  605. break;
  606. case SlipperyType::South:
  607. actionName = "\t[" + agentName + "turn_at_slip_south";
  608. positionGuard = "\t" + agentName + "IsOnSlipperySouth";
  609. prob_piece_dir = { 1, 1, 0, 0, 0, 0, 0, 1, 0 /* <- R */ };
  610. prob_piece_dir_constants = { "prop_next_neighbour", "prop_next_neighbour", "prop_zero", "prop_zero", "prop_zero", "prop_zero", "prop_zero", "prop_next_neighbour", "prop_zero" };
  611. break;
  612. case SlipperyType::East:
  613. actionName = "\t[" + agentName + "turn_at_slip_east";
  614. positionGuard = "\t" + agentName + "IsOnSlipperyEast";
  615. prob_piece_dir = { 0, 0, 0, 0, 0, 1, 1, 1, 0 /* <- R */ };
  616. prob_piece_dir_constants = { "prop_zero", "prop_zero", "prop_zero", "prop_zero", "prop_zero", "prop_next_neighbour", "prop_next_neighbour", "prop_next_neighbour", "prop_zero" };
  617. break;
  618. case SlipperyType::West:
  619. actionName = "\t[" + agentName + "turn_at_slip_west";
  620. positionGuard = "\t" + agentName + "IsOnSlipperyWest";
  621. prob_piece_dir = { 0, 1, 1, 1, 0, 0, 0, 0, 0 /* <- R */ };
  622. prob_piece_dir_constants = { "prop_zero", "prop_next_neighbour", "prop_next_neighbour", "prop_next_neighbour", "prop_zero", "prop_zero", "prop_zero", "prop_zero", "prop_zero" };
  623. break;
  624. }
  625. slipperyActions.insert(actionName + "_left]");
  626. slipperyActions.insert(actionName + "_right]");
  627. // override probability to 0 if corresp. direction is blocked
  628. for (std::size_t i = 0; i < ALL_POSS_DIRECTIONS - 1; i++) {
  629. if (!neighborhood.at(i))
  630. prob_piece_dir.at(i) = 0;
  631. }
  632. // determine residual probability (R) by replacing 0 with (1 - overall sum)
  633. prob_piece_dir.at(remainPosIndex) = PROB_PIECES - std::accumulate(prob_piece_dir.begin(), prob_piece_dir.end(), 0);
  634. prob_piece_dir_constants.at(remainPosIndex) = "prop_slippery_turn";
  635. // <DEBUG_AREA>
  636. {
  637. assert(prob_piece_dir.at(remainPosIndex) <= 9 && prob_piece_dir.at(remainPosIndex) >= 6 && "Value not in Range!");
  638. assert(std::accumulate(prob_piece_dir.begin(), prob_piece_dir.end(), 0) == PROB_PIECES && "Does not sum up to 1!");
  639. }
  640. // </DEBUG_AREA>
  641. // generic output (for every view transition)
  642. for (std::size_t v = 0; v < viewTransition.size(); v++) {
  643. os << actionName << std::get<2>(viewTransition.at(v)) << moveGuard(agentIndex) << " x" << agentName << "=" << c.second << " & y" << agentName << "=" << c.first << std::get<0>(viewTransition.at(v));
  644. for (std::size_t i = 0; i < ALL_POSS_DIRECTIONS; i++) {
  645. // os << (i == 0 ? " -> " : " + ") << prob_piece_dir_constants.at(i) << "/" << "total_prob" << " : " << positionTransition.at(i) << std::get<1>(viewTransition.at(v)) << moveUpdate(agentIndex) << (i == ALL_POSS_DIRECTIONS - 1 ? ";\n" : "\n");
  646. os << (i == 0 ? " -> " : " + ") << prob_piece_dir_constants.at(i) << " : " << positionTransition.at(i) << std::get<1>(viewTransition.at(v)) << moveUpdate(agentIndex) << (i == ALL_POSS_DIRECTIONS - 1 ? ";\n" : "\n");
  647. }
  648. }
  649. return os;
  650. }
  651. 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) {
  652. constexpr std::size_t PROB_PIECES = 9, ALL_POSS_DIRECTIONS = 8;
  653. std::array<std::string, ALL_POSS_DIRECTIONS> positionTransition = {
  654. /* north */ "(y" + agentName + "'=y" + agentName + "-1)",
  655. /* north east */ "(x" + agentName + "'=x" + agentName + "+1) & (y" + agentName + "'=y" + agentName + "-1)",
  656. /* east */ "(x" + agentName + "'=x" + agentName + "+1)",
  657. /* east south */ "(x" + agentName + "'=x" + agentName + "+1) & (y" + agentName + "'=y" + agentName + "+1)",
  658. /* south */ "(y" + agentName + "'=y" + agentName + "+1)",
  659. /* south west */ "(x" + agentName + "'=x" + agentName + "-1) & (y" + agentName + "'=y" + agentName + "+1)",
  660. /* west */ "(x" + agentName + "'=x" + agentName + "-1)",
  661. /* north west */ "(x" + agentName + "'=x" + agentName + "-1) & (y" + agentName + "'=y" + agentName + "-1)"
  662. };
  663. // direction specifics
  664. std::size_t straightPosIndex;
  665. std::string actionName, specialTransition; // if straight ahead is blocked
  666. std::string positionGuard;
  667. std::array<std::size_t, ALL_POSS_DIRECTIONS> prob_piece_dir; // { n, ne, w, se, s, sw, w, nw }
  668. std::array<std::string, ALL_POSS_DIRECTIONS> prob_piece_dir_constants;
  669. switch (orientation)
  670. {
  671. case SlipperyType::North:
  672. actionName = "\t[" + agentName + "move_on_slip_north]";
  673. positionGuard = "\t" + agentName + "IsOnSlipperyNorth";
  674. prob_piece_dir = { 0, 0, 1, 2, 0 /* <- R */, 2, 1, 0 };
  675. prob_piece_dir_constants = { "prop_zero", "prop_zero", "prop_next_neighbour", "prop_direct_neighbour", "prop_zero" /* <- R */, "prop_direct_neighbour", "prop_next_neighbour", "prop_zero" };
  676. straightPosIndex = 4;
  677. specialTransition = "(y" + agentName + "'=y" + agentName + (!neighborhood.at(straightPosIndex) ? ")" : "+1)");
  678. break;
  679. case SlipperyType::South:
  680. actionName = "\t[" + agentName + "move_on_slip_south]";
  681. positionGuard = "\t" + agentName + "IsOnSlipperySouth";
  682. prob_piece_dir = { 0 /* <- R */, 2, 1, 0, 0, 0, 1, 2 };
  683. prob_piece_dir_constants = { "prop_zero" /* <- R */, "prop_direct_neighbour", "prop_next_neighbour", "prop_zero", "prop_zero", "prop_zero", "prop_next_neighbour", "prop_direct_neighbour" };
  684. straightPosIndex = 0; // always north
  685. specialTransition = "(y" + agentName + "'=y" + agentName + (!neighborhood.at(straightPosIndex) ? ")" : "-1)");
  686. break;
  687. case SlipperyType::East:
  688. actionName = "\t[" + agentName + "move_on_slip_east]";
  689. positionGuard = "\t" + agentName + "IsOnSlipperyEast";
  690. prob_piece_dir = { 1, 0, 0, 0, 1, 2, 0 /* <- R */, 2 };
  691. prob_piece_dir_constants = { "prop_next_neighbour", "prop_zero", "prop_zero", "prop_zero", "prop_next_neighbour", "prop_direct_neighbour", "prop_zero" /* <- R */, "prop_direct_neighbour" };
  692. straightPosIndex = 6;
  693. specialTransition = "(x" + agentName + "'=x" + agentName + (!neighborhood.at(straightPosIndex) ? ")" : "-1)");
  694. break;
  695. case SlipperyType::West:
  696. actionName = "\t[" + agentName + "move_on_slip_west]";
  697. positionGuard = "\t" + agentName + "IsOnSlipperyWest";
  698. prob_piece_dir = { 1, 2, 0 /* <- R */, 2, 1, 0, 0, 0 };
  699. prob_piece_dir_constants = {"prop_next_neighbour", "prop_direct_neighbour", "prop_zero" /* <- R */, "prop_direct_neighbour", "prop_next_neighbour", "prop_zero","prop_zero", "prop_zero" };
  700. straightPosIndex = 2;
  701. specialTransition = "(x" + agentName + "'=x" + agentName + (!neighborhood.at(straightPosIndex) ? ")" : "+1)");
  702. break;
  703. }
  704. slipperyActions.insert(actionName);
  705. // override probability to 0 if corresp. direction is blocked
  706. for (std::size_t i = 0; i < ALL_POSS_DIRECTIONS; i++) {
  707. if (!neighborhood.at(i))
  708. prob_piece_dir.at(i) = 0;
  709. }
  710. // determine residual probability (R) by replacing 0 with (1 - overall sum)
  711. if(enforceOneWays) {
  712. prob_piece_dir = {0,0,0,0,0,0,0,0};
  713. prob_piece_dir_constants = {"zero","zero","zero","zero","zero","zero","zero","zero"};
  714. }
  715. prob_piece_dir.at(straightPosIndex) = PROB_PIECES - std::accumulate(prob_piece_dir.begin(), prob_piece_dir.end(), 0);
  716. prob_piece_dir_constants.at(straightPosIndex) = "prop_slippery_move_forward";
  717. // <DEBUG_AREA>
  718. {
  719. assert(prob_piece_dir.at(straightPosIndex) <= 9 && prob_piece_dir.at(straightPosIndex) >= 3 && "Value not in Range!");
  720. assert(std::accumulate(prob_piece_dir.begin(), prob_piece_dir.end(), 0) == PROB_PIECES && "Does not sum up to 1!");
  721. 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!"));
  722. 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!"));
  723. 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!"));
  724. 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!"));
  725. }
  726. // </DEBUG_AREA>
  727. // special case: straight forward is blocked (then remain in same position)
  728. positionTransition.at(straightPosIndex) = specialTransition;
  729. // generic output (for every view and every possible view direction)
  730. os << actionName << moveGuard(agentIndex) << " x" << agentName << "=" << c.second << " & y" << agentName << "=" << c.first << " & " << agentName << "SlipperyMoveForwardAllowed ";
  731. for (std::size_t i = 0; i < ALL_POSS_DIRECTIONS; i++) {
  732. os << (i == 0 ? " -> " : " + ") << prob_piece_dir_constants.at(i) << " : " << positionTransition.at(i) << moveUpdate(agentIndex) << (i == ALL_POSS_DIRECTIONS - 1 ? ";\n" : "\n");
  733. // os << (i == 0 ? " -> " : " + ") << prob_piece_dir_constants.at(i) << "/" << "total_prob" << " : " << positionTransition.at(i) << moveUpdate(agentIndex) << (i == ALL_POSS_DIRECTIONS - 1 ? ";\n" : "\n");
  734. }
  735. return os;
  736. }
  737. std::ostream& PrismModulesPrinter::printEndmodule(std::ostream &os) {
  738. os << "endmodule\n";
  739. os << "\n";
  740. return os;
  741. }
  742. std::ostream& PrismModulesPrinter::printPlayerStruct(std::ostream &os, const AgentName &agentName, const bool agentWithView, const std::vector<float> &probabilities, const std::set<std::string> &slipperyActions) {
  743. os << "player " << agentName << "\n\t";
  744. bool first = true;
  745. std::list<std::string> allActions = { "_move_north", "_move_east", "_move_south", "_move_west" };
  746. std::list<std::string> movementActions = allActions;
  747. for(auto const& probability : probabilities) {
  748. std::string percentageString = std::to_string((int)(100 * probability));
  749. for(auto const& movement : movementActions) {
  750. allActions.push_back(movement + "_" + percentageString);
  751. }
  752. }
  753. if(agentWithView) {
  754. allActions.push_back("_turn_left");
  755. allActions.push_back("_turn_right");
  756. } else {
  757. allActions.push_back("_turns");
  758. }
  759. for(auto const& action : allActions) {
  760. if(first) first = false; else os << ", ";
  761. os << "[" << agentName << action << "]";
  762. }
  763. for(auto const& action : slipperyActions) {
  764. os << ", " << action;
  765. }
  766. os << ", [" << agentName << "_done]";
  767. os << "\nendplayer\n";
  768. return os;
  769. }
  770. std::ostream& PrismModulesPrinter::printGlobalMoveVariable(std::ostream &os, const size_t &numberOfPlayer) {
  771. os << "\nglobal move : [0.." << std::to_string(numberOfPlayer - 1) << "];\n\n";
  772. return os;
  773. }
  774. 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) {
  775. if(lava.size() != 0) {
  776. os << "rewards \"" << agentName << "SafetyNoBFS\"\n";
  777. os << "\t" <<agentName << "IsInLavaAndNotDone: -100;\n";
  778. os << "endrewards\n";
  779. }
  780. if (!goals.empty() || !lava.empty()) {
  781. os << "rewards \"" << agentName << "SafetyNoBFSAndGoal\"\n";
  782. if(goals.size() != 0) os << "\t" << agentName << "IsInGoalAndNotDone: 100;\n";
  783. if(lava.size() != 0) os << "\t" << agentName << "IsInLavaAndNotDone: -100;\n";
  784. os << "endrewards\n";
  785. }
  786. os << "rewards \"" << agentName << "Time\"\n";
  787. os << "\t!" << agentName << "IsInGoal : -1;\n";
  788. if(goals.size() != 0) os << "\t" << agentName << "IsInGoalAndNotDone: 100;\n";
  789. if(lava.size() != 0) os << "\t" << agentName << "IsInLavaAndNotDone: -100;\n";
  790. os << "endrewards\n";
  791. if(stateRewards.size() > 0) {
  792. os << "rewards \"" << agentName << "SafetyWithBFS\"\n";
  793. if(lava.size() != 0) os << "\t" << agentName << "IsInLavaAndNotDone: -100;\n";
  794. for(auto const [coordinates, reward] : stateRewards) {
  795. os << "\txAgent=" << coordinates.first << "&yAgent=" << coordinates.second << " : " << reward << ";\n";
  796. }
  797. os << "endrewards\n";
  798. }
  799. if(stateRewards.size() > 0) {
  800. os << "rewards \"" << agentName << "SafetyWithBFSAndGoal\"\n";
  801. if(goals.size() != 0) os << "\tAgentIsInGoalAndNotDone: 100;\n";
  802. if(lava.size() != 0) os << "\tAgentIsInLavaAndNotDone: -100;\n";
  803. for(auto const [coordinates, reward] : stateRewards) {
  804. os << "\txAgent=" << coordinates.first << "&yAgent=" << coordinates.second << " : " << reward << ";\n";
  805. }
  806. os << "endrewards\n";
  807. }
  808. for(auto const entry : backgroundTiles)
  809. {
  810. std::cout << getColor(entry.first) << " ";
  811. for(auto const cell : entry.second){
  812. std::cout << cell.getCoordinates().first << " " << cell.getCoordinates().second << std::endl;
  813. }
  814. }
  815. if(backgroundTiles.size() > 0) {
  816. os << "rewards \"TaxiReward\"\n";
  817. os << "\t!AgentIsInGoal : -1;\n";
  818. std::string allPassengersPickedUp = "";
  819. bool first = true;
  820. for(auto const [color, cells] : backgroundTiles) {
  821. if(cells.size() == 0) continue;
  822. if(first) first = false; else allPassengersPickedUp += "&";
  823. std::string c = getColor(color);
  824. c.at(0) = std::toupper(c.at(0));
  825. std::string visitedLabel = agentName + "_picked_up_" + c;
  826. allPassengersPickedUp += visitedLabel;
  827. os << "[" << agentName << "_pickup_" << c << "] true : 100;\n";
  828. }
  829. if(goals.size() != 0) os << "\tAgentIsInGoalAndNotDone & " << allPassengersPickedUp << " : 100;\n";
  830. if(goals.size() != 0) os << "\tAgentIsInGoalAndNotDone & !(" << allPassengersPickedUp << ") : -100;\n";
  831. os << "endrewards";
  832. }
  833. return os;
  834. }
  835. std::string PrismModulesPrinter::moveGuard(const size_t &agentIndex) {
  836. return isGame() ? " move=" + std::to_string(agentIndex) + " & " : " ";
  837. }
  838. std::string PrismModulesPrinter::moveUpdate(const size_t &agentIndex) {
  839. return isGame() ?
  840. (agentIndex == numberOfPlayer - 1) ?
  841. " & (move'=0) " :
  842. " & (move'=" + std::to_string(agentIndex + 1) + ") " :
  843. "";
  844. }
  845. std::string PrismModulesPrinter::viewVariable(const AgentName &agentName, const size_t &agentDirection, const bool agentWithView) {
  846. return agentWithView ? " view" + agentName + "=" + std::to_string(agentDirection) + " & " : " ";
  847. }
  848. bool PrismModulesPrinter::isGame() const {
  849. return modelType == ModelType::SMG;
  850. }
  851. }