Refactor day 18 part 1 in preperation for part 2

master
Nick Krichevsky 2020-12-18 11:46:21 -05:00
parent 7981733c39
commit 635cd054b9
1 changed files with 51 additions and 21 deletions

View File

@ -13,6 +13,10 @@
#include <vector> #include <vector>
enum Operation { ADDITION = '+', MULTIPLICATION = '*' }; enum Operation { ADDITION = '+', MULTIPLICATION = '*' };
class ExpressionNode;
using EvaluationStrategy = std::function<double(
const ExpressionNode &, const std::unique_ptr<ExpressionNode> &, const std::unique_ptr<ExpressionNode> &,
Operation)>;
class ExpressionNode { class ExpressionNode {
public: public:
@ -20,6 +24,7 @@ class ExpressionNode {
} }
virtual long evaluate() const = 0; virtual long evaluate() const = 0;
virtual int numChildren() const = 0;
virtual ~ExpressionNode() { virtual ~ExpressionNode() {
} }
@ -34,16 +39,17 @@ class ValueNode : public ExpressionNode {
return n; return n;
} }
int numChildren() const {
return 1;
}
private: private:
long n; long n;
}; };
class ExpressionTree : public ExpressionNode { class ExpressionTree : public ExpressionNode {
public: public:
ExpressionTree() { ExpressionTree(EvaluationStrategy strategy) : strategy(strategy) {
}
ExpressionTree(std::unique_ptr<ExpressionNode> &&left, std::unique_ptr<ExpressionNode> &&right, Operation &&op)
: left(std::move(left)), right(std::move(right)), op(std::move(op)) {
} }
void setLeft(std::unique_ptr<ExpressionNode> &&left) { void setLeft(std::unique_ptr<ExpressionNode> &&left) {
@ -54,6 +60,10 @@ class ExpressionTree : public ExpressionNode {
this->right = std::move(left); this->right = std::move(left);
} }
int numChildren() const {
return 2;
}
void putNextNode(std::unique_ptr<ExpressionNode> &&node) { void putNextNode(std::unique_ptr<ExpressionNode> &&node) {
if (!this->left) { if (!this->left) {
this->setLeft(std::move(node)); this->setLeft(std::move(node));
@ -79,23 +89,18 @@ class ExpressionTree : public ExpressionNode {
} }
} }
long leftValue = this->left->evaluate(); if (!this->strategy) {
long rightValue = this->right->evaluate(); throw "AAA";
switch (*op) {
case ADDITION:
return leftValue + rightValue;
case MULTIPLICATION:
return leftValue * rightValue;
default:
throw std::invalid_argument("Invalid operation");
} }
return this->strategy(*this, this->left, this->right, *(this->op));
} }
private: private:
std::unique_ptr<ExpressionNode> left; std::unique_ptr<ExpressionNode> left;
std::unique_ptr<ExpressionNode> right; std::unique_ptr<ExpressionNode> right;
std::optional<Operation> op; std::optional<Operation> op;
EvaluationStrategy strategy;
bool canFullyEvaluate() const { bool canFullyEvaluate() const {
return this->left && this->right && this->op; return this->left && this->right && this->op;
} }
@ -161,7 +166,8 @@ std::optional<std::pair<std::string_view, int>> parseParenthetical(int cursor, c
return std::pair<std::string_view, int>(input.substr(startPos + 1, cursor - startPos - 1), startPos); return std::pair<std::string_view, int>(input.substr(startPos + 1, cursor - startPos - 1), startPos);
} }
std::unique_ptr<ExpressionNode> buildTree(const std::string_view input, int depth = 0) { std::unique_ptr<ExpressionNode> buildTree(
const std::string_view input, const EvaluationStrategy &strategy, int depth = 0) {
if (std::count_if(input.cbegin(), input.cend(), [](char c) { return c == ' '; }) == 0) { if (std::count_if(input.cbegin(), input.cend(), [](char c) { return c == ' '; }) == 0) {
std::cout << std::string(depth, ' ') << "RIGHT: " << input << std::endl; std::cout << std::string(depth, ' ') << "RIGHT: " << input << std::endl;
std::optional<long> value = parseNumber(input); std::optional<long> value = parseNumber(input);
@ -172,7 +178,10 @@ std::unique_ptr<ExpressionNode> buildTree(const std::string_view input, int dept
return std::make_unique<ValueNode>(*value); return std::make_unique<ValueNode>(*value);
} }
ExpressionTree tree; if (!strategy) {
throw "AAAA";
}
ExpressionTree tree(strategy);
// This should technically be size_type but I need to be able to go before zero // This should technically be size_type but I need to be able to go before zero
int cursor = input.size() - 1; int cursor = input.size() - 1;
while (cursor > 0) { while (cursor > 0) {
@ -187,7 +196,7 @@ std::unique_ptr<ExpressionNode> buildTree(const std::string_view input, int dept
parseParenthetical(previousSpace - 1, input); parseParenthetical(previousSpace - 1, input);
if (parentheticalPart) { if (parentheticalPart) {
std::cout << std::string(depth, ' ') << "RIGHT (paren): " << parentheticalPart->first << std::endl; std::cout << std::string(depth, ' ') << "RIGHT (paren): " << parentheticalPart->first << std::endl;
auto parentheticalTree = buildTree(parentheticalPart->first, depth + 1); auto parentheticalTree = buildTree(parentheticalPart->first, strategy, depth + 1);
tree.setRight(std::move(parentheticalTree)); tree.setRight(std::move(parentheticalTree));
cursor = parentheticalPart->second - 2; cursor = parentheticalPart->second - 2;
continue; continue;
@ -199,7 +208,7 @@ std::unique_ptr<ExpressionNode> buildTree(const std::string_view input, int dept
tree.setOp(*componentOperation); tree.setOp(*componentOperation);
auto rest = input.substr(0, cursor + 1); auto rest = input.substr(0, cursor + 1);
std::cout << std::string(depth, ' ') << "LEFT: " << component << std::endl; std::cout << std::string(depth, ' ') << "LEFT: " << component << std::endl;
auto rightTree = buildTree(rest, depth + 1); auto rightTree = buildTree(rest, strategy, depth + 1);
tree.setLeft(std::move(rightTree)); tree.setLeft(std::move(rightTree));
// Once we have found an operator and the operand to the left of it, we're done // Once we have found an operator and the operand to the left of it, we're done
break; break;
@ -217,13 +226,34 @@ std::unique_ptr<ExpressionNode> buildTree(const std::string_view input, int dept
return std::make_unique<ExpressionTree>(std::move(tree)); return std::make_unique<ExpressionTree>(std::move(tree));
} }
long part1(const std::vector<std::string> &input) { long run(const std::vector<std::string> &input, const EvaluationStrategy &strategy) {
return std::accumulate(input.cbegin(), input.cend(), 0L, [](long total, const std::string &expression) { return std::accumulate(input.cbegin(), input.cend(), 0L, [&strategy](long total, const std::string &expression) {
auto tree = buildTree(expression); auto tree = buildTree(expression, strategy);
return total + tree->evaluate(); return total + tree->evaluate();
}); });
} }
long part1(const std::vector<std::string> &input) {
EvaluationStrategy strategy = [](const ExpressionNode &self,
const std::unique_ptr<ExpressionNode> &left,
const std::unique_ptr<ExpressionNode> &right,
Operation op) -> long {
long leftValue = left->evaluate();
long rightValue = right->evaluate();
switch (op) {
case ADDITION:
return leftValue + rightValue;
case MULTIPLICATION:
return leftValue * rightValue;
default:
throw std::invalid_argument("Invalid operation");
}
};
return run(input, strategy);
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (argc != 2) { if (argc != 2) {
std::cerr << argv[0] << " <input_file>" << std::endl; std::cerr << argv[0] << " <input_file>" << std::endl;