adapter.cpp (4873B)
1 #include "../cpp/nissy.h" 2 3 #include <emscripten/bind.h> 4 #include <map> 5 #include <set> 6 #include <string> 7 #include <vector> 8 9 extern "C" { 10 extern int addCallbackFunction(/* args intentionally unspecified */); 11 extern void callFunction(int, const char *); 12 extern int callFunctionInt(int); 13 } 14 15 static int logger_id = -1; 16 17 void log(std::string s) 18 { 19 if (logger_id == -1) 20 return; 21 22 callFunction(logger_id, s.c_str()); 23 } 24 25 void log_wrapper(const char *cstr, void *data) 26 { 27 log(cstr); 28 } 29 30 void set_logger(int id) 31 { 32 logger_id = id; 33 nissy::set_logger(log_wrapper, NULL); 34 } 35 36 // Some of the solvers are not available to the JS interface because of 37 // memory limitations. 38 const std::set<std::string> available_solvers 39 { 40 "h48h0k4", 41 "h48h1k2", 42 "h48h2k2", 43 "h48h3k2", 44 "h48h7k2", 45 }; 46 47 std::map<std::string, nissy::solver> loaded_solvers; 48 49 // TODO: this should ask the user if they want to download or generate. 50 // TODO: this should also save the data to a file (IDBFS / NODEFS) 51 bool init_solver(const std::string& name) 52 { 53 auto se = nissy::solver::get(name); 54 nissy::solver solver = std::get<nissy::solver>(se); 55 log("Generating data for solver " + solver.name + "\n"); 56 auto err = solver.generate_data(); 57 if (!err.ok()) { 58 log("Error generating the data!\n"); 59 return false; 60 } 61 log("Checking data integrity " 62 "(this is done only once per session per solver)...\n"); 63 if (!solver.check_data().ok()) { 64 log("Error generating the data!\n"); 65 return false; 66 } 67 loaded_solvers.insert({name, solver}); 68 log("Data generated successfully, but not saved " 69 "(feature not yet available)\n"); 70 return true; 71 } 72 73 bool solver_valid(const std::string& name) 74 { 75 if (loaded_solvers.contains(name) || 76 (available_solvers.contains(name) && init_solver(name))) 77 return true; 78 79 auto se = nissy::solver::get(name); 80 if (std::holds_alternative<nissy::solver>(se)) 81 log("The solver " + name + " is not available in " 82 "the web version of Nissy. Use a native version.\n"); 83 else 84 log("Invalid solver " + name + "\n"); 85 return false; 86 } 87 88 int poll_status(void *arg) 89 { 90 int id = *(int *)arg; 91 if (id == -1) 92 return nissy::status::RUN.value; 93 return callFunctionInt(id); 94 } 95 96 nissy::solver::solve_result solve(std::string name, 97 nissy::cube cube, nissy::nissflag nissflag, unsigned minmoves, 98 unsigned maxmoves, unsigned maxsols, unsigned optimal, unsigned threads, 99 int poll_status_id) 100 { 101 if (!solver_valid(name)) 102 return nissy::solver::solve_result 103 {.err = nissy::error::INVALID_SOLVER}; 104 105 return loaded_solvers.at(name).solve(cube, nissflag, minmoves, 106 maxmoves, maxsols, optimal, threads, NULL, &poll_status_id); 107 } 108 109 EMSCRIPTEN_BINDINGS(Nissy) 110 { 111 emscripten::class_<nissy::nissflag>("NissFlag") 112 .class_property("normal", &nissy::nissflag::NORMAL) 113 .class_property("inverse", &nissy::nissflag::INVERSE) 114 .class_property("mixed", &nissy::nissflag::MIXED) 115 .class_property("linear", &nissy::nissflag::LINEAR) 116 .class_property("all", &nissy::nissflag::ALL) 117 ; 118 119 emscripten::class_<nissy::error>("Error") 120 .function("ok", &nissy::error::ok) 121 .class_property("unsolvableWarning", &nissy::error::UNSOLVABLE_WARNING) 122 .class_property("unsolvableError", &nissy::error::UNSOLVABLE_ERROR) 123 .class_property("invalidCube", &nissy::error::INVALID_CUBE) 124 .class_property("invalidMoves", &nissy::error::INVALID_MOVES) 125 .class_property("invalidTrans", &nissy::error::INVALID_TRANS) 126 .class_property("invalidSolver", &nissy::error::INVALID_SOLVER) 127 .class_property("nullPointer", &nissy::error::NULL_POINTER) 128 .class_property("bufferSize", &nissy::error::BUFFER_SIZE) 129 .class_property("data", &nissy::error::DATA) 130 .class_property("options", &nissy::error::OPTIONS) 131 .class_property("unknown", &nissy::error::UNKNOWN) 132 ; 133 134 emscripten::constant("statusRUN", nissy::status::RUN.value); 135 emscripten::constant("statusSTOP", nissy::status::STOP.value); 136 emscripten::constant("statusPAUSE", nissy::status::PAUSE.value); 137 /* 138 emscripten::class_<nissy::status>("Status") 139 .class_property("run", &nissy::status::RUN) 140 .class_property("stop", &nissy::status::STOP) 141 .class_property("pause", &nissy::status::PAUSE) 142 ; 143 */ 144 145 emscripten::class_<nissy::cube>("Cube") 146 .constructor<>() 147 .function("move", &nissy::cube::move) 148 .function("transform", &nissy::cube::transform) 149 .function("invert", &nissy::cube::invert) 150 .function("toString", &nissy::cube::to_string) 151 ; 152 153 emscripten::class_<nissy::solver::solve_result>("SolveResult") 154 .property("err", &nissy::solver::solve_result::err) 155 .property("solutions", &nissy::solver::solve_result::solutions) 156 ; 157 158 emscripten::function("countMoves", &nissy::count_moves); 159 emscripten::function("solve", &solve, 160 emscripten::return_value_policy::take_ownership()); 161 emscripten::function("setLogger", &set_logger, 162 emscripten::allow_raw_pointers()); 163 emscripten::function("addCallbackFunction", &addCallbackFunction); 164 }