#include "checkouts.h" #include "comp.h" #include #include #include #include #include // TODO refactor *everything* struct match_state { struct leg *l1, *l2; int complete; }; void suggested(int rem, char *buf) { buf[0] = 0; if (rem > 1 && rem <= 170) { char *target = CHECKOUTS[2][rem-1]; if (target) { int trem = rem - segment_points(segment_from_name(target)); int len = sprintf(buf, "%s", target); if (trem) { target = CHECKOUTS[1][trem-1]; len += sprintf(buf + len, "-%s", target); trem = trem - segment_points(segment_from_name(target)); if (trem) { target = CHECKOUTS[0][trem-1]; len += sprintf(buf + len, "-%s", target); } } } } } EMSCRIPTEN_KEEPALIVE void get_suggested(int rem, int player) { static char buf[20]; suggested(rem, buf); if (player == 1) EM_ASM({userSugg($0)}, buf); else EM_ASM({boatSugg($0)}, buf); } EMSCRIPTEN_KEEPALIVE bool user_visit(struct match_state *state, int points) { if (state->l1->rem <= 0 || state->l2->rem <= 0) return false; if (points > state->l1->rem || state->l1->rem - points == 1 || points > 180 || points == 179 || points == 178 || points == 176 || points == 175 || points == 173 || points == 172 || points == 169 || points == 166 || points == 163) return false; struct leg *l = state->l1; struct visit *v = l->visits + l->n_visits++; v->points = points; l->rem -= points; v->rem = l->rem; EM_ASM({updateUserRem($0)}, l->rem); if (v->rem > 0) EM_ASM({updateUserAvg($0)}, (double)(l->start-l->rem)/l->n_visits); return true; } EMSCRIPTEN_KEEPALIVE int is_match_over(struct match_state *state) { if (state->l1->rem <= 0 || state->l2->rem <= 0) return 1; return 0; } EMSCRIPTEN_KEEPALIVE void draw_match(struct match_state *state) { struct leg *l1 = state->l1; struct leg *l2 = state->l2; char visit_no[10], u_pts[10], u_rem[10], b_pts[10], b_rem[10], b_darts[100]; visit_no[0] = u_pts[0] = u_rem[0] = b_pts[0] = b_rem[0] = b_darts[0] = 0; EM_ASM({drawVisit($0, $1, $2, $3, $4, $5)}, "0", "", "501", "", "501", ""); int n_visits = l1->n_visits > l2->n_visits ? l1->n_visits : l2->n_visits; for (int i = 0; i < n_visits; ++i) { sprintf(visit_no, "%d", i + 1); struct visit *v = l1->visits + i; sprintf(u_pts, "%d", v->points); sprintf(u_rem, "%d", v->rem); if (i < l2->n_visits) { v = l2->visits + i; sprintf(b_pts, "%d", v->points); sprintf(b_rem, "%d", v->rem); for (int j = 0; j < v->n_darts; ++j) { char *n = segment_name(v->darts[j]); sprintf(b_darts + (j ? (j * 5 - 1) : 0), j == 0 ? "%4s" : " %4s", n); free(n); } } EM_ASM({drawVisit($0, $1, $2, $3, $4, $5)}, visit_no, u_pts, u_rem, b_pts, b_rem, b_darts); visit_no[0] = 0; u_pts[0] = 0; u_rem[0] = 0; b_pts[0] = 0; b_rem[0] = 0; b_darts[0] = 0; } if (l1->rem <= 0) { EM_ASM(promptNumDarts()); } else if (l2->rem <= 0) { EM_ASM({promptMsg($0)}, "Bot wins. :("); EM_ASM(matchOver()); } else { EM_ASM({promptMsg($0)}, "Enter points:"); } } EMSCRIPTEN_KEEPALIVE void boat_visit(struct match_state *state, int delay_ms) { if (state->l1->rem <= 0 || state->l2->rem <= 0) return; EM_ASM({promptMsg($0)}, "Bot is throwing…"); struct leg *l = state->l2; comp_visit(l); struct visit *v = l->visits + l->n_visits - 1; double avg; if (v->rem > 0) avg = (double)(l->start - l->rem) / l->n_visits; else avg = ((double)l->start / (((l->n_visits - 1) * 3) + v->n_darts)) * 3; if (!delay_ms) { EM_ASM({updateBoatRem($0)}, l->rem); EM_ASM({updateBoatAvg($0)}, avg); EM_ASM({clearMatchLog()}); draw_match(state); if (!is_match_over(state)) EM_ASM(setUserActive()); return; } int pts = segment_points(v->darts[0]); char str[20]; char *seg_name = segment_name(v->darts[0]); strcpy(str, seg_name); free(seg_name); EM_ASM({scheduleBoatThrowing($0, $1, $2)}, pts, str, delay_ms); if (v->n_darts > 1) { pts += segment_points(v->darts[1]); seg_name = segment_name(v->darts[1]); strcat(strcat(str, "-"), seg_name); free(seg_name); EM_ASM({scheduleBoatThrowing($0, $1, $2)}, pts, str, delay_ms * 2); } if (v->n_darts > 2) { pts += segment_points(v->darts[2]); seg_name = segment_name(v->darts[2]); strcat(strcat(str, "-"), seg_name); free(seg_name); EM_ASM({scheduleBoatThrowing($0, $1, $2)}, pts, str, delay_ms * 3); } EM_ASM({scheduleEndBoatThrowing($0, $1, $2)}, l->rem, avg, delay_ms * (v->n_darts + 1)); } EMSCRIPTEN_KEEPALIVE int resp_numdarts(struct match_state *state, int n_darts) { if (n_darts < 1 || n_darts > 4) return 0; struct leg *l = state->l1; EM_ASM({updateUserAvg($0)}, ((double)l->start / (((l->n_visits - 1) * 3) + n_darts)) * 3); EM_ASM({promptMsg($0)}, "You win! :)"); EM_ASM(matchOver()); return 1; } void init_boat() { static int ran; if (ran) return; ran = 1; srand(time(NULL)); init_board(); EM_ASM({updateStdev($0)}, horizontal_stdev); } EMSCRIPTEN_KEEPALIVE struct match_state *start_match() { init_boat(); struct match_state *state = calloc(1, sizeof(struct match_state)); state->l1 = leg_init(501, "User"); state->l2 = leg_init(501, "Bot"); EM_ASM({updateUserRem($0)}, state->l1->rem); EM_ASM({updateBoatRem($0)}, state->l2->rem); return state; } EMSCRIPTEN_KEEPALIVE void free_match(struct match_state *state) { leg_free(state->l1); leg_free(state->l2); free(state); } EMSCRIPTEN_KEEPALIVE void change_stdev(float hstdev, float vstdev) { horizontal_stdev = hstdev; vertical_stdev = vstdev; } int main() { EM_ASM(initMatch()); }