From 5cd642eb026ee58b01aaef2675c39dcbb24e161e Mon Sep 17 00:00:00 2001 From: Payam1991Gr Date: Wed, 3 May 2023 09:10:45 +0330 Subject: [PATCH] first commit --- .clang-format | 1 + .gitignore | 34 +----- README.md | 15 ++- main.cpp | 317 ++++++++++++++++++++++++++++++++++++++++++++++++++ main.hpp | 90 ++++++++++++++ 5 files changed, 424 insertions(+), 33 deletions(-) create mode 100644 .clang-format create mode 100644 main.cpp create mode 100644 main.hpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..f87f20d --- /dev/null +++ b/.clang-format @@ -0,0 +1 @@ +ColumnLimit: 110 diff --git a/.gitignore b/.gitignore index 259148f..1e157ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,32 +1,2 @@ -# Prerequisites -*.d - -# Compiled Object files -*.slo -*.lo -*.o -*.obj - -# Precompiled Headers -*.gch -*.pch - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a -*.lib - -# Executables -*.exe -*.out -*.app +data/ +bin/ diff --git a/README.md b/README.md index 31eceab..b556265 100644 --- a/README.md +++ b/README.md @@ -1 +1,14 @@ -# hyperjump-cpp \ No newline at end of file +# [Hyperjump](https://hyperjumps.quantamagazine.org/) +Dummy math game solver. + +## Config +Tweak the variables in the main funtion. + + ## Build and Run +```sh +mkdir -p bin data +g++ -std=c++17 main.cpp -o bin/main && ./bin/main +``` + +## Output +Check data/output.txt for the result. diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..f193b0a --- /dev/null +++ b/main.cpp @@ -0,0 +1,317 @@ +#include "main.hpp" +#include +#include +#include +#include +#include + +using std::cerr; +using std::cout; +using std::endl; +using std::make_unique; +using std::move; +using std::ostream; +using std::set; +using std::string; +using std::stringstream; +using std::to_string; +using std::unique_ptr; +using std::vector; + +int main() { + // Solver solver({8, 7, 7, 4, 1, 3, 6, 7}); + Solver solver({8, 3, 4, 1, 5, 7, 8, 1}, 6, Solver::Mode::FULL); + // Solver solver({8, 3, 4, 1, 5, 7, 8, 1}, 8, Solver::Mode::FULL); + // Solver solver({8, 7, 7, 4, 1, 3, 6, 7}, 6, Solver::Mode::FULL); + solver.solve(); +} + +void uniqueList(vector &list) noexcept { + std::sort(list.begin(), list.end()); + auto it = std::unique(list.begin(), list.end()); + list.resize(std::distance(list.begin(), it)); +} + +void uniqueList(vector &list) noexcept { + std::sort(list.begin(), list.end()); + auto it = std::unique(list.begin(), list.end()); + list.resize(std::distance(list.begin(), it)); +} + +void uniqueList(vector &list) noexcept { + std::sort(list.begin(), list.end(), [](Tree *l, Tree *r) { return *l < *r; }); + auto it = std::unique(list.begin(), list.end(), [](Tree *l, Tree *r) { return *l == *r; }); + list.resize(std::distance(list.begin(), it)); +} + +Solver::Solver(vector &&options, int size, Mode mode, int finalValue) noexcept + : settings(move(options), size, move(mode), finalValue) {} + +// TODO does move work for vectors? +Solver::Solver(Solver::Settings &&settings) noexcept : settings(move(settings)) { + if (settings.areOptionsInvalid) + showInvalidOptionsError(); +} + +unique_ptr> Solver::makeOptionsFor(int key) noexcept { + auto list = make_unique>(); + list->reserve(settings.options.size()); + bool found = false; + for (int option : settings.options) { + if (!found && option == key) + found = true; + else + list->push_back(option); + } + uniqueList(*list); + return list; +} + +void Solver::solve() noexcept { + if (settings.areOptionsInvalid) { + showInvalidOptionsError(); + return; + } + auto keys = uniqueClone(settings.options); + using il = std::initializer_list; + std::ofstream output(OUTPUT_DIR); + for (auto key : *keys) { + auto &o = settings.options; + state.keyIndex = std::find(o.begin(), o.end(), key) - o.begin(); + auto options = makeOptionsFor(key); + for (int option : *options) { + Tree tree(key, &settings, &state); + tree.put(option, settings.size - 1); + auto solutions = tree.solutions(); + for (auto &solution : *solutions) + output << solution << endl; + if (state.goalAchieved) + break; + } + if (state.goalAchieved) + break; + } + output.close(); +} + +Tree::Tree() noexcept : settings(nullptr), state(nullptr) {} + +Tree::Tree(int value, Solver::Settings *settings, Solver::State *state, Tree *parent) noexcept + : digits(0), endPoint(true), settings(settings), state(state) { + values.push_back(value); + if (parent != nullptr) { + auto cvs = parent->cvalues; + auto ri = parent->remainedIndices; + for (auto &v : cvs) + values.push_back(v + value); + remainedIndices.insert(remainedIndices.begin(), ri.begin(), ri.end()); + } else { + auto optionsSize = settings->options.size(); + remainedIndices.reserve(optionsSize); + for (int i = 0; i < optionsSize; i++) + if (i != state->keyIndex) + remainedIndices.push_back(i); + } + for (auto &v : values) + cvalues.push_back(10 * v); +}; + +int Tree::value() const noexcept { + if (values.size() == 0) + return 0; + else + return values[0]; +} + +Tree::Solutions Tree::solutions() noexcept { + stringstream ss; + auto solutions = make_unique>(); + processSolution(solutions, ss); + return solutions; +} + +string Tree::processSolution(Solutions &solutions, stringstream &ss, string padding) noexcept { + // TODO stringstream is horribly used! + ss.str(""); + if (padding != "") + padding += " -> "; + padding += to_string(values[0]); + appendSolution(adds, solutions, ss, padding); + appendSolution(subs, solutions, ss, padding); + appendSolution(muls, solutions, ss, padding); + appendSolution(divs, solutions, ss, padding); + if (endPoint) { + ss << padding; + string solution = ss.str(); + if (solution.size() > 1) { + solutions->emplace(solution); + if (settings->needsOneTarget) + state->goalAchieved = true; + } + return ""; + } else + return ss.str(); +} + +void Tree::appendSolution(vector &trees, Solutions &solutions, stringstream &ss, + string &padding) noexcept { + // TODO stringstream is horribly used! + // TODO inefficient: the whole tree must be flattened. + if (state->goalAchieved) + return; + vector refTrees; + refTrees.reserve(trees.size()); + for (auto &tree : trees) + refTrees.emplace_back(&tree); + uniqueList(refTrees); + for (auto &tree : refTrees) { + ss << tree->processSolution(solutions, ss, padding); + if (state->goalAchieved) + break; + } +} + +void Tree::append(stringstream &ss, vector &trees, char op, string &padding) noexcept { + // TODO stringstream is horribly used! + for (int i = 0; i < trees.size(); i++) { + auto tree = trees[i]; + ss << padding; + for (int j = 0; j < tree.digits; j++) + ss << "."; + ss << op << " " << trees[i].toString(padding); + } +} + +string Tree::toString(string padding) noexcept { + // TODO stringstream is horribly used! + stringstream ss; + ss << values[0] << endl; + padding += " "; + append(ss, adds, '+', padding); + append(ss, subs, '-', padding); + append(ss, muls, '*', padding); + append(ss, divs, '/', padding); + return ss.str(); +} + +bool has(int n, vector &indices, Solver::Settings *settings) noexcept { + for (int i = 0; i < indices.size(); i++) + if (settings->options[indices[i]] == n) { + indices.erase(indices.begin() + i); + return true; + } + return false; +} + +void Tree::put(vector &trees, bool &success, int value, int n, int level, int digits) noexcept { + Tree t(n, settings, state, this); + if (t.put(value % 10, level)) { + t.digits = digits; + trees.push_back(move(t)); + success = true; + } +} + +bool Tree::put(int n, int level) noexcept { + if (level == 0 && n == settings->finalValue) + return true; + if (!has(n, remainedIndices, settings)) + return false; + if (level == 0) + return false; + level--; + bool success = false; + for (int i = 0; i < values.size(); i++) { + auto value = values[i]; + put(adds, success, value + n, n, level, i); + if (value > n) + put(subs, success, value - n, n, level, i); + put(muls, success, value * n, n, level, i); + if (value % n == 0) + put(divs, success, value / n, n, level, i); + } + endPoint = !success; + return success; +} + +// TODO show functions need cleanup +void show(vector &answer) noexcept { + stringstream ss; + ss << "["; + bool first = true; + for (auto i : answer) { + if (first) + first = false; + else + ss << ", "; + ss << i; + } + ss << "]"; + cout << ss.str() << endl; +} + +void show(vector &trees) noexcept { + stringstream ss; + ss << "["; + bool first = true; + for (auto &tree : trees) { + if (first) + first = false; + else + ss << ", "; + ss << tree.value(); + } + ss << "]"; + cout << ss.str() << endl; +} + +void show(vector &trees) noexcept { + stringstream ss; + ss << "["; + bool first = true; + for (auto &tree : trees) { + if (first) + first = false; + else + ss << ", "; + ss << tree->value(); + } + ss << "]"; + cout << ss.str() << endl; +} + +Solver::Settings::Settings(std::vector &&options, int size, Mode mode, int finalValue) noexcept + : size(size), finalValue(finalValue), areOptionsInvalid(false), + needsOneTarget(mode == DEFAULT_SOLVER_MODE), options(move(options)) { + if (this->options.size() < 2) + areOptionsInvalid = true; +} + +Solver::State::State() noexcept : goalAchieved(false), keyIndex(0) {} + +void Solver::showInvalidOptionsError() noexcept { std::cerr << "Invalid Options!" << endl; } + +Tree::operator int() const noexcept { return value(); } + +unique_ptr> uniqueClone(vector &list) { + auto clone = make_unique>(); + clone->reserve(list.size()); + for (int i : list) + clone->push_back(i); + uniqueList(*clone); + return clone; +} + +ostream &operator<<(ostream &os, vector &v) { + os << "["; + bool first = true; + for (int i : v) { + if (first) + first = false; + else + os << ", "; + os << i; + } + os << "]"; + return os; +} diff --git a/main.hpp b/main.hpp new file mode 100644 index 0000000..cb1430b --- /dev/null +++ b/main.hpp @@ -0,0 +1,90 @@ +#ifndef MAIN_HPP +#define MAIN_HPP + +#include +#include +#include +#include + +class Solver { +public: + enum class Mode { FULL, FIRST }; + inline static const Mode DEFAULT_SOLVER_MODE = Mode::FIRST; + static constexpr const char *OUTPUT_DIR = "data/output.txt"; + + struct Settings { + int size; + int finalValue; + bool needsOneTarget; + std::vector options; + bool areOptionsInvalid; + + Settings(std::vector &&options, int size, Mode mode, int finalValue) noexcept; + }; + + struct State { + bool goalAchieved; + int keyIndex; + + State() noexcept; + }; + + Solver(std::vector &&options, int size = 6, Mode mode = DEFAULT_SOLVER_MODE, + int finalValue = 9) noexcept; + explicit Solver(Settings &&settings) noexcept; + void solve() noexcept; + +private: + Settings settings; + State state; + + inline void showInvalidOptionsError() noexcept; + std::unique_ptr> makeOptionsFor(int key) noexcept; +}; + +class Tree { + using Solutions = std::unique_ptr>; + +public: + bool endPoint; + Tree() noexcept; + Tree(int value, Solver::Settings *settings, Solver::State *state, Tree *parent = nullptr) noexcept; + std::string toString(std::string padding = "") noexcept; + bool put(int n, int level) noexcept; + inline int value() const noexcept; + operator int() const noexcept; + Solutions solutions() noexcept; + +protected: + std::vector values; + std::vector cvalues; + std::vector remainedIndices; + std::vector adds; + std::vector subs; + std::vector muls; + std::vector divs; + int digits; + +private: + Solver::Settings *settings; + Solver::State *state; + + void put(std::vector &trees, bool &success, int value, int n, int level, int digits) noexcept; + std::string processSolution(Solutions &solutions, std::stringstream &, std::string padding = "") noexcept; + void appendSolution(std::vector &trees, Solutions &solutions, std::stringstream &, + std::string &padding) noexcept; + void append(std::stringstream &, std::vector &, char op, std::string &padding) noexcept; +}; + +int main(); +void show(std::vector &answer) noexcept; +void show(std::vector &) noexcept; +void show(std::vector &) noexcept; +bool has(int n, std::vector &indices, Solver::Settings *) noexcept; +void uniqueList(std::vector &list) noexcept; +void uniqueList(std::vector &) noexcept; +void uniqueList(std::vector &) noexcept; +std::unique_ptr> uniqueClone(std::vector &list); +std::ostream &operator<<(std::ostream &os, std::vector &v); + +#endif