Guest User

Untitled

a guest
Oct 18th, 2018
116
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.22 KB | None | 0 0
  1. /*
  2. PROBLEM: 1405 - The Halting Problem
  3. ANSWER: Accepted
  4. LANGUAGE: C++17 (g++ 7.3.0, -std=c++17 -O2 -lm) [+0s]
  5. RUNTIME: 0.004s
  6. FILE SIZE: 8.53 KB
  7. SUBMISSION: 10/16/18, 3:31:00 PM
  8. */
  9. #include <iostream>
  10. #include <sstream>
  11. #include <vector>
  12. #include <unordered_set>
  13. #include <unordered_map>
  14. #include <algorithm>
  15. #include <functional>
  16. #include <memory>
  17. #include <exception>
  18.  
  19. enum class CommandType {
  20. OP = 0,
  21. IF = 1,
  22. ENDIF = 2,
  23. CALL = 3,
  24. RET = 4
  25. };
  26.  
  27. class Program;
  28.  
  29. class Param {
  30. public:
  31. Param() {};
  32. virtual int getValue() const = 0;
  33. virtual std::string toString() const = 0;
  34. virtual int &getRef() = 0;
  35. };
  36.  
  37. class Constant : public Param {
  38. public:
  39. Constant(int value) : Param(), value(value) {};
  40. int getValue() const {
  41. return value;
  42. };
  43. int &getRef() {
  44. throw std::logic_error("can't get a ref to a constant parameter.");
  45. };
  46. std::string toString() const {return std::to_string(value);};
  47. private:
  48. int value;
  49. };
  50.  
  51. class Register : public Param {
  52. public:
  53. Register(int &value, int r) : Param(), value(value), r(r) {};
  54. int getValue() const {
  55. return value;
  56. };
  57. int &getRef() {
  58. return value;
  59. };
  60. std::string toString() const {return "R"+std::to_string(r);};
  61. private:
  62. int &value;
  63. int r;
  64. };
  65.  
  66. Param *makeParam(Program &, std::string);
  67.  
  68. class Command {
  69. public:
  70. Command(Program &program, std::string cmd, Param *p1, Param *p2) : program(program), cmd(cmd), p1(p1), p2(p2) {};
  71. virtual ~Command() {};
  72. virtual void execute() = 0;
  73. virtual CommandType type() {return CommandType::OP;};
  74. std::string toString() {
  75. std::string p1str, p2str;
  76. if (p1)
  77. p1str = p1->toString();
  78.  
  79. if (p2)
  80. p2str = ","+p2->toString();
  81.  
  82. return cmd + " " + p1str + p2str;
  83. };
  84. protected:
  85. Program &program;
  86. std::string cmd;
  87. std::unique_ptr<Param> p1, p2;
  88. };
  89.  
  90. Command *makeCommand(Program &p, std::string cmd, std::string p1, std::string p2);
  91.  
  92. class Program {
  93. public:
  94. Program(int r0) : r0(r0) {};
  95. int &getRegister(int r) {return registers[r];};
  96. void addCommand(std::string cmd, std::string p1, std::string p2) {
  97. commands.emplace_back(makeCommand(*this, cmd, p1, p2));
  98. };
  99.  
  100. void incIP() {++IP;};
  101. void resetIP() {IP = 0;};
  102. void branchIP() {IP = branches[IP];};
  103.  
  104. void run(bool debug) {
  105. init();
  106.  
  107. while (!terminated) {
  108. if (debug) {
  109. std::cerr << IP << ": " << commands[IP]->toString() << " [ ";
  110. for (auto r: registers)
  111. std::cerr << r << " ";
  112. std::cerr << "]" << std::endl;
  113. }
  114.  
  115. commands[IP]->execute();
  116. }
  117. };
  118.  
  119. void pushRegisters(int callValue) {
  120. if (callValues.count(callValue) > 0)
  121. throw std::logic_error("this program entered an infinite loop.");
  122.  
  123. callValues.insert(callValue);
  124. callStack.push_back(callValue);
  125. stack.push_back(std::make_pair(registers, std::make_pair(IP, callValue)));
  126. };
  127.  
  128. int popRegisters() {
  129. if (stack.size() > 0) {
  130. for (size_t i = 0; i < registers.size(); ++i) // copy to keep the register references
  131. registers[i] = stack.back().first[i];
  132.  
  133. IP = stack.back().second.first;
  134. int callValue = stack.back().second.second;
  135. stack.pop_back();
  136. callValues.erase(callValue);
  137. callStack.pop_back();
  138. return callValue;
  139. }
  140. terminated = true;
  141. return -1;
  142. };
  143.  
  144. int getMemoizedCall(int callValue) {
  145. auto it = memoizedCalls.find(callValue);
  146. if (it != memoizedCalls.end())
  147. return it->second;
  148. return -1;
  149. }
  150.  
  151. void setMemoizedCall(int callValue, int retValue) {
  152. memoizedCalls[callValue] = retValue;
  153. }
  154. private:
  155. bool terminated = false;
  156. int IP = 0; // instruction pointer
  157. int r0;
  158. std::unordered_map<int, int> branches;
  159. std::vector<std::unique_ptr<Command> > commands; // the program itself
  160. std::vector<int> registers = {0,0,0,0,0,0,0,0,0,0};
  161. std::vector<std::pair<std::vector<int>, std::pair<int, int> > > stack; // save/restore regsiters+IP+CALL_VALUE for CALL & RET
  162. std::unordered_map<int, int> memoizedCalls; // speed up cache
  163.  
  164. // infinite loop control (parallel structures for faster access)
  165. std::unordered_set<int> callValues;
  166. std::vector<int> callStack;
  167.  
  168. void computeBranches() {
  169. branches.clear();
  170. std::vector<int> branchCtrl;
  171. for (size_t i = 0; i < commands.size(); ++i) {
  172. if (commands[i]->type() == CommandType::IF)
  173. branchCtrl.push_back(i);
  174. if (commands[i]->type() == CommandType::ENDIF) {
  175. branches[branchCtrl.back()] = i+1;
  176. branchCtrl.pop_back();
  177. }
  178. }
  179. };
  180.  
  181. void init() {
  182. terminated = false;
  183. computeBranches();
  184.  
  185. resetIP();
  186. std::for_each(registers.begin(), registers.end(), [](int &r){r=0;});
  187. memoizedCalls.clear();
  188. callValues.clear();
  189. callStack.clear();
  190.  
  191. registers[0] = r0;
  192. callValues.insert(r0);
  193. callStack.push_back(r0);
  194. };
  195. };
  196.  
  197. class OP : public Command {
  198. public:
  199. OP(Program &program, std::string cmd, Param *p1, Param *p2, std::function<void(int &, int)> op) :
  200. Command(program, cmd, p1, p2), op(op) {};
  201. void execute() override {
  202. op(p1->getRef(), p2->getValue());
  203. program.incIP();
  204. };
  205. private:
  206. std::function<void(int &, int)> op;
  207. };
  208.  
  209. class ENDIF : public Command {
  210. public:
  211. ENDIF(Program &program, std::string cmd) : Command(program, cmd, nullptr, nullptr) {};
  212. void execute() override {
  213. program.incIP();
  214. };
  215. CommandType type() override {return CommandType::ENDIF;};
  216. };
  217.  
  218. class IF : public Command {
  219. public:
  220. IF(Program &program, std::string cmd, Param *p1, Param *p2, std::function<bool(int, int)> comp) :
  221. Command(program, cmd, p1, p2), comp(comp) {};
  222. void execute() override {
  223. if (comp(p1->getValue(),p2->getValue()))
  224. program.incIP();
  225. else
  226. program.branchIP();
  227. };
  228. CommandType type() override {return CommandType::IF;};
  229. protected:
  230. std::function<bool(int, int)> comp;
  231. };
  232.  
  233. class CALL : public Command {
  234. public:
  235. CALL(Program &program, std::string cmd, Param *p1) : Command(program, cmd, p1, nullptr) {};
  236. void execute() override {
  237. int callValue = p1->getValue();
  238. int retValue = program.getMemoizedCall(callValue);
  239. if (retValue == -1) { // first time this call shows up
  240. program.pushRegisters(callValue);
  241. program.getRegister(0) = callValue;
  242. program.resetIP();
  243. } else { // reuse previously run call, simulate a return
  244. program.incIP();
  245. program.getRegister(9) = retValue;
  246. }
  247. };
  248. CommandType type() override {return CommandType::CALL;};
  249. };
  250.  
  251. class RET : public Command {
  252. public:
  253. RET(Program &program, std::string cmd, Param *p1) : Command(program, cmd, p1, nullptr) {};
  254. void execute() override {
  255. int retValue = p1->getValue();
  256. int callValue = program.popRegisters();
  257. program.setMemoizedCall(callValue, retValue); // save this call/ret values for reuse (memoize it)
  258. program.getRegister(9) = retValue;
  259. program.incIP();
  260. };
  261. CommandType type() override {return CommandType::RET;};
  262. };
  263.  
  264. Param *makeParam(Program &p, std::string param) {
  265. if (param[0] == 'R') {
  266. int reg = std::stoi(param.substr(1));
  267. return new Register(p.getRegister(reg), reg);
  268. } else if (param.size() > 0)
  269. return new Constant(std::stoi(param));
  270. else
  271. return nullptr;
  272. }
  273.  
  274. Command *makeCommand(Program &p, std::string cmd, std::string p1, std::string p2) {
  275. if (cmd == "MOV")
  276. return new OP(p, cmd, makeParam(p, p1), makeParam(p, p2), [](int &a, int b){a=b;});
  277. if (cmd == "ADD")
  278. return new OP(p, cmd, makeParam(p, p1), makeParam(p, p2), [](int &a, int b){a+=b; if (a>999) a-=1000;});
  279. if (cmd == "SUB")
  280. return new OP(p, cmd, makeParam(p, p1), makeParam(p, p2), [](int &a, int b){a-=b; if (a<0) a+=1000;});
  281. if (cmd == "MUL")
  282. return new OP(p, cmd, makeParam(p, p1), makeParam(p, p2), [](int &a, int b){a*=b; a %= 1000;});
  283. if (cmd == "DIV")
  284. return new OP(p, cmd, makeParam(p, p1), makeParam(p, p2), [](int &a, int b){
  285. if((a*b)==0)
  286. a = 0;
  287. else
  288. a /= b;
  289. });
  290. if (cmd == "MOD")
  291. return new OP(p, cmd, makeParam(p, p1), makeParam(p, p2), [](int &a, int b){
  292. if((a*b)==0)
  293. a = 0;
  294. else
  295. a %= b;
  296. });
  297. if (cmd == "ENDIF")
  298. return new ENDIF(p, cmd);
  299. if (cmd == "IFEQ")
  300. return new IF(p, cmd, makeParam(p, p1), makeParam(p, p2), [](int a, int b){return a==b;});
  301. if (cmd == "IFNEQ")
  302. return new IF(p, cmd, makeParam(p, p1), makeParam(p, p2), [](int a, int b){return a!=b;});
  303. if (cmd == "IFG")
  304. return new IF(p, cmd, makeParam(p, p1), makeParam(p, p2), [](int a, int b){return a>b;});
  305. if (cmd == "IFL")
  306. return new IF(p, cmd, makeParam(p, p1), makeParam(p, p2), [](int a, int b){return a<b;});
  307. if (cmd == "IFGE")
  308. return new IF(p, cmd, makeParam(p, p1), makeParam(p, p2), [](int a, int b){return a>=b;});
  309. if (cmd == "IFLE")
  310. return new IF(p, cmd, makeParam(p, p1), makeParam(p, p2), [](int a, int b){return a<=b;});
  311. if (cmd == "CALL")
  312. return new CALL(p, cmd, makeParam(p, p1));
  313. if (cmd == "RET")
  314. return new RET(p, cmd, makeParam(p, p1));
  315. return nullptr;
  316. }
  317.  
  318. int main(int argc, char **argv) {
  319. int nlin, r0, pos = 0, prob = 0;
  320.  
  321. std::cin >> nlin >> r0;
  322. while (nlin != 0) {
  323. if (argc > 1)
  324. std::cerr << "*** " << prob << " = " << pos << std::endl;
  325. std::string line;
  326. std::getline(std::cin, line); ++pos;
  327.  
  328. Program program(r0);
  329.  
  330. for (int i = 0; i < nlin; ++i) {
  331. std::getline(std::cin, line); ++ pos;
  332. std::transform(line.begin(), line.end(), line.begin(),
  333. [](char ch) {
  334. if (ch == ',')
  335. return ' ';
  336. else
  337. return ch;
  338. });
  339. std::stringstream ss(line);
  340. std::string cmd;
  341. std::string p1, p2;
  342.  
  343. ss >> cmd >> p1 >> p2;
  344. program.addCommand(cmd, p1, p2);
  345. }
  346. try {
  347. program.run(argc > 1);
  348. std::cout << program.getRegister(9) << std::endl;
  349. } catch (...) {
  350. std::cout << "*" << std::endl;
  351. }
  352.  
  353. std::cin >> nlin >> r0;
  354. ++prob;
  355. }
  356. }
Add Comment
Please, Sign In to add comment