├── .gitignore ├── LICENSE ├── README.md ├── equations.cpp ├── equations.hpp ├── exampleUsage.cpp └── imageForReadme ├── 2017IsActuallyGonnaBeLit.PNG ├── 2017IsActuallyGonnaBeLitMathJax.PNG └── 2017Lit.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | exampleUsage -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 SandSnip3r 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Random Postfix Equation 2 | Inspired by people being dumb 3 | ![alt tag](imageForReadme/2017Lit.jpg) 4 | 5 | It's clear that this math is incorrect. I was curious if I could find a real equation that equaled 2017. 6 | 7 | I decided to take the random approach. I'll pick a combination of random numbers from a user-given list and random operations. Currently, only 4 operations are supported, `+`, `-`, `*`, and `/`. I have a few reasons for taking this random approach. 8 | 9 | 1. Taking the sequential approach would hardly exhaust all equations if the quantity of numbers or the number of terms in the equation is large. The random approach obviously wont exaust all the equations either, it might even create duplicates, but it will help with problem #2. 10 | 2. I believe if I sequentially stepped through the possible equations, I would get solution groupings as well. For example, I'll have to go through billions of equations that start with a small number divided by something. In that case, I'd only see small numbers and never see 2017. 11 | 3. It was a bit easier to quickly POC this idea. 12 | 13 | I used postfix because generating random infix equations would introduce ambiguity. Also, evaluating postfix equations is super simple. 14 | 15 | #### This little header is pretty simple to use. 16 | 17 | * Start by creating an `std::vector` of numbers that you want to be used in the randomly built equations. 18 | * Instantiate a `RandomEquationBuilder`. 19 | * Ask the `RandomEquationBuilder` instance to build an `Equation` for you with a specified term count. 20 | * Finally, retreive and print the result. 21 | 22 | ```c++ 23 | const std::vector NUMBERS = {1,2,3,4,5,6,7}; 24 | RandomEquationBuilder randomEquationBuilder(NUMBERS); 25 | 26 | const int DESIRED_TERM_COUNT = 4; 27 | Equation equation = randomEquationBuilder.build(DESIRED_TERM_COUNT); 28 | 29 | double result = equation.evaluate(); 30 | std::cout << equation.toString() << " = " << result << '\n'; 31 | ``` 32 | 33 | It turns out that 2017 is a pretty difficult number to create using an equation of only 420's and 69's. I believe that's because 2017 is prime. After trying for quite a while, I didnt find an equation until I started generating equations with 16 terms. 34 | 35 | `69 69 / 69 69 + 69 420 69 69 69 / 69 + + 69 420 + - / * * 69 / 69 420 420 + / / -` 36 | 37 | Which translates to the following infix 38 | 39 | ![alt tag](imageForReadme/2017IsActuallyGonnaBeLitMathJax.PNG) 40 | 41 | This was rendered using the MathJax formula `\frac{69}{69} - (69 + 69) \times 69 \times \frac{\frac{\frac{420}{69 + \frac{69}{69} + 69 - (69 + 420)}}{69}}{\frac{69}{420 + 420}} = 2017` 42 | 43 | [Here is a Wolfram Alpha query representing the above](http://www.wolframalpha.com/input/?i=69+%2F+69+-+(69+%2B+69)+*+69+*+420+%2F+(69+%2B+69+%2F+69+%2B+69+-+(69+%2B+420))+%2F+69+%2F+(69+%2F+(420+%2B+420))) 44 | -------------------------------------------------------------------------------- /equations.cpp: -------------------------------------------------------------------------------- 1 | #include "equations.hpp" 2 | #include 3 | #include 4 | 5 | EquationPiece::EquationPiece(char op) : type(Type::Operation), operation(op) {} 6 | 7 | EquationPiece::EquationPiece(double num) : type(Type::Number), number(num) {} 8 | 9 | std::string Equation::doubleToString(double num) const { 10 | std::string doubleString = std::to_string(num); 11 | doubleString.erase(doubleString.find_last_not_of('0') + 1, std::string::npos); 12 | if (!doubleString.empty() && doubleString.back() == '.') { 13 | doubleString.pop_back(); 14 | } 15 | return doubleString; 16 | } 17 | 18 | void Equation::addNumber(double num) { 19 | equationPieces.emplace_back(num); 20 | } 21 | 22 | void Equation::addOperation(char op) { 23 | if (find(OPERATIONS.begin(), OPERATIONS.end(), op) == OPERATIONS.end()) { 24 | throw std::runtime_error(std::string("Invalid operation ")+op+" added to equation."); 25 | } 26 | equationPieces.emplace_back(op); 27 | } 28 | 29 | std::string Equation::toString() const { 30 | std::string equationString; 31 | for (auto piece : equationPieces) { 32 | if (piece.type == EquationPiece::Type::Number) { 33 | //Convert number to string and add it to the resulting string 34 | equationString += doubleToString(piece.number); 35 | } else { 36 | //Add operation to resulting string 37 | equationString += piece.operation; 38 | } 39 | equationString += ' '; 40 | } 41 | equationString.pop_back(); 42 | return equationString; 43 | } 44 | 45 | double Equation::evaluate() { 46 | std::stack evaluationStack; 47 | for (auto piece : equationPieces) { 48 | if (piece.type == EquationPiece::Type::Number) { 49 | //Next thing in the equation is a number, add it to the stack 50 | evaluationStack.emplace(piece.number); 51 | } else { 52 | //Next thing in the equation is a operation, 53 | // pop the previous 2 numbers 54 | if (evaluationStack.size() < 2) { 55 | throw std::runtime_error("Trying to evaluate equation. Failed because too few numbers exist."); 56 | } 57 | double num1 = evaluationStack.top(); 58 | evaluationStack.pop(); 59 | double num2 = evaluationStack.top(); 60 | evaluationStack.pop(); 61 | 62 | // apply the operation 63 | double result; 64 | switch (piece.operation) { 65 | case '+': 66 | result = num2+num1; 67 | break; 68 | case '-': 69 | result = num2-num1; 70 | break; 71 | case '*': 72 | result = num2*num1; 73 | break; 74 | case '/': 75 | if (num1 == 0) { 76 | throw std::runtime_error("Trying to divide by 0."); 77 | } 78 | result = num2/num1; 79 | break; 80 | default: 81 | //Cant get here because addOperation disallows invalid operations 82 | break; 83 | } 84 | 85 | // push the result onto the stack 86 | evaluationStack.push(result); 87 | } 88 | } 89 | if (evaluationStack.size() != 1) { 90 | throw std::runtime_error("Trying to evaluate equation. Failed because too few operations exist."); 91 | } 92 | return evaluationStack.top(); 93 | } 94 | 95 | const std::vector Equation::OPERATIONS = {'+','-','*','/'}; 96 | 97 | void RandomEquationBuilder::createRandomEngine() { 98 | std::random_device rd; 99 | std::vector seeds; 100 | seeds.reserve(std::mt19937::state_size); 101 | for (size_t i=0; i dist(0,NUMBERS.size()-1); 110 | return NUMBERS[dist(eng)]; 111 | } 112 | 113 | char RandomEquationBuilder::randomOperation() { 114 | std::uniform_int_distribution dist(0,Equation::OPERATIONS.size()-1); 115 | return Equation::OPERATIONS[dist(eng)]; 116 | } 117 | 118 | RandomEquationBuilder::RandomEquationBuilder(const std::vector NUMS) : NUMBERS(NUMS) { 119 | createRandomEngine(); 120 | } 121 | 122 | Equation RandomEquationBuilder::build(const int DESIRED_NUMBER_COUNT_IN_EQUATION) { 123 | Equation equation; 124 | int numberCount=0; 125 | int balance=0; 126 | std::bernoulli_distribution opOrNumDist(0.5); 127 | while (numberCount < DESIRED_NUMBER_COUNT_IN_EQUATION) { 128 | if (balance >= 2) { 129 | //50/50 chance to add number or operation 130 | if (opOrNumDist(eng)) { 131 | //Add operation 132 | equation.addOperation(randomOperation()); 133 | --balance; 134 | } else { 135 | //Add number 136 | equation.addNumber(randomNumber()); 137 | ++numberCount; 138 | ++balance; 139 | } 140 | } else { 141 | //Too few numbers in the equation, must add number 142 | equation.addNumber(randomNumber()); 143 | ++numberCount; 144 | ++balance; 145 | } 146 | } 147 | while (balance > 1) { 148 | //Not enough operations in the equation 149 | equation.addOperation(randomOperation()); 150 | --balance; 151 | } 152 | return equation; 153 | } 154 | -------------------------------------------------------------------------------- /equations.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EQUATIONS_HPP 2 | #define EQUATIONS_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class EquationPiece { 9 | private: 10 | public: 11 | enum class Type { Number, Operation }; 12 | Type type; 13 | char operation{'\0'}; 14 | double number{0}; 15 | EquationPiece(char op); 16 | EquationPiece(double num); 17 | }; 18 | 19 | class Equation { 20 | private: 21 | std::vector equationPieces; 22 | std::string doubleToString(double num) const; 23 | public: 24 | static const std::vector OPERATIONS; 25 | void addNumber(double num); 26 | void addOperation(char op); 27 | std::string toString() const; 28 | double evaluate(); 29 | }; 30 | 31 | class RandomEquationBuilder { 32 | private: 33 | const std::vector NUMBERS; 34 | std::mt19937 eng; 35 | void createRandomEngine(); 36 | double randomNumber(); 37 | char randomOperation(); 38 | public: 39 | RandomEquationBuilder(const std::vector NUMS); 40 | Equation build(const int DESIRED_NUMBER_COUNT_IN_EQUATION); 41 | }; 42 | 43 | #endif //EQUATIONS_HPP -------------------------------------------------------------------------------- /exampleUsage.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "equations.hpp" 3 | 4 | int main() { 5 | using namespace std; 6 | 7 | const vector NUMBERS = {69, 420}; 8 | RandomEquationBuilder randomEquationBuilder(NUMBERS); 9 | const int GOAL_NUMBER_COUNT = 3; 10 | 11 | int TRY_COUNT = 25; 12 | 13 | for (int i=0; i