181 lines
3.4 KiB
C++
181 lines
3.4 KiB
C++
#include <algorithm>
|
|
#include <cassert>
|
|
#include <iostream>
|
|
#include <list>
|
|
#include <map>
|
|
#include <regex>
|
|
#include <string>
|
|
|
|
enum class Opcode { Acc, Jmp, Nop };
|
|
using Value = int;
|
|
|
|
struct Instruction
|
|
{
|
|
Instruction(std::string const& s) : op_(to_opcode(s.substr(0, 3))), v_(to_value(s.substr(4))) {}
|
|
|
|
Opcode opcode() const noexcept { return op_; }
|
|
Value value() const noexcept { return v_; }
|
|
bool flip_jmp()
|
|
{
|
|
switch (op_) {
|
|
case Opcode::Acc:
|
|
return false;
|
|
case Opcode::Jmp:
|
|
op_ = Opcode::Nop;
|
|
return true;
|
|
case Opcode::Nop:
|
|
op_ = Opcode::Jmp;
|
|
return true;
|
|
default:
|
|
assert(false);
|
|
}
|
|
}
|
|
|
|
private:
|
|
Opcode to_opcode(std::string const& s)
|
|
{
|
|
if (s == "acc") {
|
|
return Opcode::Acc;
|
|
}
|
|
else if (s == "jmp") {
|
|
return Opcode::Jmp;
|
|
}
|
|
else if (s == "nop") {
|
|
return Opcode::Nop;
|
|
}
|
|
else {
|
|
assert(false);
|
|
return Opcode::Nop;
|
|
}
|
|
}
|
|
|
|
Value to_value(std::string const& s)
|
|
{
|
|
int sign = 0;
|
|
int v = 0;
|
|
std::size_t pos = 0;
|
|
if (s[0] == '+') {
|
|
sign = 1;
|
|
}
|
|
else if (s[0] == '-') {
|
|
sign = -1;
|
|
}
|
|
else {
|
|
assert(false);
|
|
}
|
|
v = std::stoi(s.substr(1), &pos);
|
|
assert(pos == s.length() - 1);
|
|
return v * sign;
|
|
}
|
|
|
|
Opcode op_;
|
|
Value v_;
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream& os, Instruction const& i)
|
|
{
|
|
switch (i.opcode()) {
|
|
case Opcode::Acc:
|
|
os << "acc";
|
|
break;
|
|
case Opcode::Jmp:
|
|
os << "jmp";
|
|
break;
|
|
case Opcode::Nop:
|
|
os << "nop";
|
|
break;
|
|
default:
|
|
os << "UNK";
|
|
break;
|
|
}
|
|
os << " ";
|
|
if (i.value() >= 0) {
|
|
os << "+";
|
|
}
|
|
os << i.value();
|
|
return os;
|
|
}
|
|
using Instructions = std::vector<Instruction>;
|
|
|
|
struct VM
|
|
{
|
|
VM() : pc_(0), acc_(0) {}
|
|
|
|
void add_instruction(Instruction const& i)
|
|
{
|
|
std::cout << i << "\n";
|
|
instructions_.push_back(i);
|
|
}
|
|
|
|
bool execute()
|
|
{
|
|
std::vector<bool> seen(instructions_.size(), false);
|
|
acc_ = 0;
|
|
pc_ = 0;
|
|
while (!seen[pc_]) {
|
|
assert(pc_ < instructions_.size());
|
|
seen[pc_] = true;
|
|
execute(instructions_[pc_]);
|
|
++pc_;
|
|
if (pc_ == instructions_.size()) {
|
|
std::cout << "Terminated\n";
|
|
return true;
|
|
}
|
|
}
|
|
std::cout << "PC seen before: " << pc_ << "\n";
|
|
return false;
|
|
}
|
|
|
|
void find_fix()
|
|
{
|
|
for (std::size_t pos = 0; pos < instructions_.size(); ++pos) {
|
|
if (instructions_[pos].flip_jmp()) {
|
|
if (execute()) {
|
|
std::cout << "Success at instruction " << pos << ": " << instructions_[pos] << "\n";
|
|
return;
|
|
}
|
|
instructions_[pos].flip_jmp();
|
|
}
|
|
}
|
|
}
|
|
|
|
Value acc() const noexcept { return acc_; }
|
|
|
|
private:
|
|
void execute(Instruction const& i)
|
|
{
|
|
std::cout << pc_ << ": " << i;
|
|
switch (i.opcode()) {
|
|
case Opcode::Acc:
|
|
std::cout << "; acc = " << acc_ << " + " << i.value();
|
|
acc_ += i.value();
|
|
std::cout << " = " << acc_;
|
|
break;
|
|
case Opcode::Jmp:
|
|
std::cout << "; pc = " << pc_ << " + " << i.value();
|
|
pc_ += i.value() - 1;
|
|
std::cout << " = " << pc_ + 1;
|
|
break;
|
|
case Opcode::Nop:
|
|
break;
|
|
}
|
|
std::cout << "\n";
|
|
}
|
|
|
|
Instructions instructions_;
|
|
std::size_t pc_;
|
|
Value acc_;
|
|
};
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
VM vm;
|
|
for (std::string line; std::getline(std::cin, line);) {
|
|
vm.add_instruction(Instruction(line));
|
|
}
|
|
|
|
vm.find_fix();
|
|
std::cout << "Accumulator: " << vm.acc() << "\n";
|
|
|
|
return 0;
|
|
} |