#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <map>
#include <memory>
#include <stack>
#include <string>
#include <vector>
long long defaultX = 0;
long long totalUses = 0;
// #define DEBUG
namespace Variables {
std::map<std::string, long long> variables;
long long get(const std::string& key) {
auto it = variables.find(key);
if (it == variables.end()) {
long long defaultVal = key == "X" ? defaultX : 0;
variables.insert({key, defaultVal});
return defaultVal;
}
return it->second;
}
void reset() {
variables.clear();
}
void increase(const std::string& key) {
long long value = get(key) + 1;
variables[key] = value;
}
void clear(const std::string& key) {
variables[key] = 0;
}
};
class Instruction {
public:
std::string variable;
std::string type;
int uses = 0;
virtual void handle() = 0;
virtual void printUses(int indentation) {
for (int i = 0; i < indentation; i++) {
std::cout << "| ";
}
std::cout << type << " " << variable << " " << uses << std::endl;
}
virtual ~Instruction() = default;
Instruction(std::string variable, std::string type) : variable(variable), type(type) { }
};
class PrintInstruction : public Instruction {
public:
PrintInstruction(const std::string& variable) : Instruction(variable, "print") { }
void handle() override {
std::cout << Variables::get(variable) << " ";
}
};
class ClearInstruction : public Instruction {
public:
ClearInstruction(const std::string& variable) : Instruction(variable, "clear") { }
void handle() override {
Variables::clear(variable);
}
};
class IncreaseInstruction : public Instruction {
public:
IncreaseInstruction(const std::string& variable) : Instruction(variable, "increase") { }
void handle() override {
Variables::increase(variable);
}
};
class RepeatInstruction : public Instruction {
public:
std::vector<std::shared_ptr<Instruction>> instructions;
void handle() override {
auto guh = variable == "" ? 1 : Variables::get(variable);
for (int i = 0; i < guh; i++) {
for (auto ins : instructions) {
totalUses++;
ins->uses++;
ins->handle();
}
}
}
RepeatInstruction(std::string variable = "") : Instruction(variable, "repeat") { }
void printUses(int indentation) override {
for (int i = 0; i < indentation; i++) {
std::cout << "| ";
}
std::cout << type << " " << variable << " " << uses << std::endl;
for (auto ins : instructions) {
ins->printUses(indentation + 1);
}
}
};
std::shared_ptr<Instruction> readPrint(const std::vector<std::string>& words, std::size_t& index) {
std::string str = words.at(++index);
return std::make_shared<PrintInstruction>(str);
}
std::shared_ptr<Instruction> readClear(const std::vector<std::string>& words, std::size_t& index) {
std::string str = words.at(++index);
return std::make_shared<ClearInstruction>(str);
}
std::shared_ptr<Instruction> readIncrease(const std::vector<std::string>& words, std::size_t& index) {
std::string str = words.at(++index);
return std::make_shared<IncreaseInstruction>(str);
}
std::shared_ptr<RepeatInstruction> readRepeat(const std::vector<std::string>& words, std::size_t& index) {
std::string times = words.at(++index);
index += 2;
return std::make_shared<RepeatInstruction>(times);
}
int calcSteps(int collatz) {
int steps = 0;
while (true) {
steps++;
if (collatz % 2 == 0) collatz /= 2;
else collatz = collatz * 3 + 1;
if (collatz == 1) return steps;
}
}
void collatzCheck() {
// std::vector<std::pair<int, int>> guh;
//
// int largest = 0;
// for (int i = 1; i < 1000; i++) {
// int n = calcSteps(i);
// int g = std::ceil(( n - 40 ) / i);
//
// if (g > largest) {
// std::cout << g << " at " << i << std::endl;
// largest = g;
// }
// guh.push_back({i, n});
// }
//
// std::sort(guh.begin(), guh.end(), [](std::pair<int, int> i1, std::pair<int, int> i2) { return i1.second < i2.second; });
// for (auto [i, n] : guh) {
// std::cout << i << ": " << n << std::endl;
// }
}
int main([[maybe_unused]] int argc, [[maybe_unused]] char *argv[]) {
collatzCheck();
auto base = std::make_shared<RepeatInstruction>();
std::stack<std::shared_ptr<RepeatInstruction>> stack;
stack.push(base);
std::vector<std::string> words;
std::string temp;
while (std::cin >> temp) {
int commentIndex = temp.find('#');
if (commentIndex >= 0) {
if (commentIndex > 0) {
temp = temp.substr(0, commentIndex);
words.push_back(temp);
}
std::string line;
std::getline(std::cin, line);
continue;
}
if (temp == "END") {
goto END;
} else {
words.push_back(temp);
}
}
END:
std::size_t index = 0;
while (index < words.size()) {
std::string str = words.at(index);
switch (str.at(0)) {
case 'P' /* Print */: {
stack.top()->instructions.push_back(readPrint(words, index));
break;
}
case 'C' /* Clear */: {
stack.top()->instructions.push_back(readClear(words, index));
break;
}
case 'I' /* Increase */: {
stack.top()->instructions.push_back(readIncrease(words, index));
break;
}
case 'R' /* Repeat */: {
auto guh = readRepeat(words, index);
stack.top()->instructions.push_back(guh);
stack.push(guh);
break;
}
case ')' /* Repeat end */: {
stack.pop();
break;
}
}
index++;
}
if (false) {
defaultX = 100;
Variables::reset();
base->handle();
base->printUses(0);
std::cout << "total" << totalUses << std::endl;
} else {
for (int i = 1; i <= 1000; i++) {
defaultX = i;
Variables::reset();
base->handle();
if (totalUses >= 60'000'000) {
base->printUses(0);
break;
}
}
}
std::cout << "total" << totalUses << std::endl;
}
// Tuleva X on parillinen kun D on pariton