aboutsummaryrefslogtreecommitdiff
path: root/src/sdl/solve.c
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2019-01-16 07:15:26 -0500
committerPaul Duncan <pabs@pablotron.org>2019-01-16 07:15:26 -0500
commitc17f5a5377f959a7e67526e0ae89b329bf99a101 (patch)
treea350ecb2d677a060795fbf20aade2a2c7a5759b6 /src/sdl/solve.c
parent19a5965400f9a252adf540050046d2dc3a026d13 (diff)
downloadsok-c17f5a5377f959a7e67526e0ae89b329bf99a101.tar.bz2
sok-c17f5a5377f959a7e67526e0ae89b329bf99a101.zip
solve in background thread
Diffstat (limited to 'src/sdl/solve.c')
-rw-r--r--src/sdl/solve.c218
1 files changed, 218 insertions, 0 deletions
diff --git a/src/sdl/solve.c b/src/sdl/solve.c
new file mode 100644
index 0000000..0fee274
--- /dev/null
+++ b/src/sdl/solve.c
@@ -0,0 +1,218 @@
+#include <stdbool.h> // bool
+#include <errno.h> // errno
+#include <string.h> // strerror()
+#include <SDL.h>
+#include "util.h"
+#include "solve.h"
+
+struct solve_t_ {
+ SDL_mutex *mutex;
+
+ // thread-private copy of context
+ sok_ctx_t ctx;
+
+ Uint32 solve_event_type;
+
+ // number of moves at call to solve()
+ size_t old_num_moves;
+
+ // number of times the on_step cb has been invoked
+ size_t num_steps;
+
+ // result of solve
+ bool result;
+
+ // cancel solve
+ bool cancel;
+};
+
+static void
+push_event(
+ solve_t * const data,
+ const solve_event_type_t type,
+ void *user_data
+) {
+ // alloc/clear event
+ SDL_Event ev;
+ memset(&ev, 0, sizeof(SDL_Event));
+
+ // init event
+ ev.type = data->solve_event_type;
+ ev.user.code = (Sint32) type;
+ ev.user.data1 = data;
+ ev.user.data2 = user_data;
+
+ // push event
+ if (!SDL_PushEvent(&ev)) {
+ die("SDL_PushEvent(): %s", SDL_GetError());
+ }
+}
+
+static bool
+solve_on_step(
+ const sok_ctx_t * const ctx,
+ void *user_data
+) {
+ solve_t *data = user_data;
+ UNUSED(ctx);
+
+ // lock mutex
+ if (SDL_LockMutex(data->mutex)) {
+ die("SDL_LockMutex(): %s", SDL_GetError());
+ }
+
+ // increment number of steps
+ data->num_steps++;
+
+ // cache number of steps and cancel state
+ const size_t num_steps = data->num_steps;
+ const bool cancel = data->cancel;
+
+ // unlock mutex
+ if (SDL_UnlockMutex(data->mutex)) {
+ die("SDL_UnlockMutex(): %s", SDL_GetError());
+ }
+
+ if ((num_steps % 100) == 0) {
+ // push event
+ push_event(data, SOLVE_EVENT_STEP, NULL);
+ }
+
+ // return false if cancelled
+ return !cancel;
+}
+
+static void
+solve_on_error(
+ const char * const err,
+ void *user_data
+) {
+ solve_t *data = user_data;
+ UNUSED(user_data);
+ // die("Error solving level: %s", err);
+ push_event(data, SOLVE_EVENT_FAIL, (void*) err);
+}
+
+static const sok_solve_cbs_t
+SOLVE_CBS = {
+ .on_step = solve_on_step,
+ .on_error = solve_on_error,
+};
+
+static int
+solve_thread(
+ void * const thread_data
+) {
+ solve_t *data = thread_data;
+ warn("solve started");
+
+ // solve board
+ data->result = sok_solve(&(data->ctx), &SOLVE_CBS, data);
+ if (data->result) {
+ // push success
+ push_event(data, SOLVE_EVENT_DONE, NULL);
+ }
+ warn("solve done");
+
+ return 0;
+}
+
+solve_t *
+solve(
+ const sok_ctx_t * const ctx,
+ const Uint32 solve_event_type
+) {
+ // create thread mutex
+ SDL_mutex *mutex = SDL_CreateMutex();
+ if (!mutex) {
+ die("SDL_CreateMutex(): %s", SDL_GetError());
+ }
+
+ // alloc solve thread data
+ solve_t *data = malloc(sizeof(solve_t));
+ if (!data) {
+ die("malloc(): %s", strerror(errno));
+ }
+
+ // init solve data
+ data->mutex = mutex;
+ data->ctx = *ctx;
+ data->solve_event_type = solve_event_type;
+ data->old_num_moves = ctx->num_moves;
+ data->num_steps = 0;
+ data->result = false;
+ data->cancel = false;
+
+ // create solve thread
+ SDL_Thread *thread = SDL_CreateThread(solve_thread, "solve", data);
+ if (!thread) {
+ die("SDL_CreateThread(): %s", SDL_GetError());
+ }
+
+ // detach thread
+ SDL_DetachThread(thread);
+
+ SDL_Log("Solving (thread ID = %lu, address = %p)", SDL_GetThreadID(thread), thread);
+
+ // return thread data
+ return data;
+}
+
+void
+solve_fini(
+ solve_t * const data,
+ void (*on_done)(const bool, const sok_ctx_t *, const size_t, void *),
+ void *user_data
+) {
+ if (on_done) {
+ // call handler
+ on_done(data->result, &(data->ctx), data->num_steps, user_data);
+ }
+
+ // free mutex
+ SDL_DestroyMutex(data->mutex);
+ data->mutex = NULL;
+
+ // free thread data
+ free(data);
+}
+
+void
+solve_cancel(solve_t * const data) {
+ // lock mutex
+ if (SDL_LockMutex(data->mutex)) {
+ die("SDL_LockMutex(): %s", SDL_GetError());
+ }
+
+ // set cancel
+ data->cancel = true;
+
+ // lock mutex
+ if (SDL_UnlockMutex(data->mutex)) {
+ die("SDL_UnlockMutex(): %s", SDL_GetError());
+ }
+}
+
+size_t
+solve_get_num_steps(solve_t * const data) {
+ // lock mutex
+ if (SDL_LockMutex(data->mutex)) {
+ die("SDL_LockMutex(): %s", SDL_GetError());
+ }
+
+ // get num steps
+ const size_t num_steps = data->num_steps;
+
+ // lock mutex
+ if (SDL_UnlockMutex(data->mutex)) {
+ die("SDL_UnlockMutex(): %s", SDL_GetError());
+ }
+
+ // return num_steps
+ return num_steps;
+}
+
+bool
+solve_get_result(solve_t * const data) {
+ return data->result;
+}