nissy-core

The "engine" of nissy, including the H48 optimal solver.
git clone https://git.tronto.net/nissy-core
Download | Log | Files | Refs | README | LICENSE

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 }