From f9117e7c9b5b6602e4eb55ee48815882a7085782 Mon Sep 17 00:00:00 2001 From: David Vazgenovich Shakaryan Date: Sun, 1 May 2022 09:43:27 -0700 Subject: make name consistent; minor file organisation --- .gitignore | 2 +- Makefile | 2 +- curses.c | 2 +- dartboat.c | 168 +++++++++++++++++++++++++++++++++ dartbot.c | 167 -------------------------------- web/dartboat_wasm.c | 8 +- web/static/index.html | 2 +- web/svg.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++ web/svg.h | 7 ++ web/svg_dartboard.c | 256 -------------------------------------------------- 10 files changed, 439 insertions(+), 431 deletions(-) create mode 100644 dartboat.c delete mode 100644 dartbot.c create mode 100644 web/svg.c create mode 100644 web/svg.h delete mode 100644 web/svg_dartboard.c diff --git a/.gitignore b/.gitignore index 09ca33a..dca8006 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -dartbot +dartboat *.d *.o diff --git a/Makefile b/Makefile index 83ec0a8..3ffd796 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CFLAGS += -O2 -Wall -Wextra -Wpedantic CPPFLAGS += -MMD -MP LDFLAGS += -lm -lncurses -TARGET := dartbot +TARGET := dartboat SRC := $(wildcard *.c) OBJ := $(SRC:.c=.o) diff --git a/curses.c b/curses.c index 4169906..12141af 100644 --- a/curses.c +++ b/curses.c @@ -21,7 +21,7 @@ void init_curses() promptw = newwin(1, COLS, LINES-1, 0); wbkgd(titlew, COLOR_PAIR(C_STATUS)); wbkgd(statw, COLOR_PAIR(C_STATUS)); - waddstr(titlew, " dartbot"); + waddstr(titlew, " dartboat"); wrefresh(titlew); } diff --git a/dartboat.c b/dartboat.c new file mode 100644 index 0000000..aa59630 --- /dev/null +++ b/dartboat.c @@ -0,0 +1,168 @@ +#include "board.h" +#include "checkouts.h" +#include "comp.h" +#include "curses.h" +#include "match.h" + +#include +#include +#include +#include + +void test_match(int start_points) +{ + struct leg *l = leg_init(start_points, NULL); + + while (l->rem > 0) + comp_visit(l); + + printf("(%2d) %3d\n", 0, l->start); + for (int i = 0; i < l->n_visits; ++i) { + struct visit *v = l->visits + i; + printf("(%2d) %3d %3d", i+1, v->points, v->rem); + + for (int j = 0; j < v->n_darts; ++j) { + char *n = segment_name(v->darts[j]); + printf(j == 0 ? " %4s" :" %4s", n); + free(n); + } + printf("\n"); + } + + leg_free(l); +} + +void user_visit(struct leg *l) +{ + if (l->n_visits == l->size_visits) + leg_grow_visits(l); + struct visit *v = l->visits + l->n_visits++; + + char status[100]; + int len = sprintf(status, " %s has %d remaining", l->name, l->rem); + if (l->rem <= 170) { + char *target = CHECKOUTS[2][l->rem-1]; + if (target) { + int trem = l->rem - segment_points(segment_from_name(target)); + len += sprintf(status + len, " (%s", target); + if (trem) { + target = CHECKOUTS[1][trem-1]; + len += sprintf(status + len, "-%s", target); + trem = trem - segment_points(segment_from_name(target)); + + if (trem) { + target = CHECKOUTS[0][trem-1]; + len += sprintf(status + len, "-%s", target); + } + } + len += sprintf(status + len, ")"); + } + } + char prompt[] = " enter points> "; + curses_status(status); + curses_prompt(prompt); + + char buf[100] = { 0 }; + int buflen = 0; + + int c; + while((c = wgetch(promptw)) != 10) { + if (c == 127) { + if (buflen > 0) { + buf[--buflen] = 0; + wmove(promptw, 0, sizeof(prompt) - 1 + buflen); + wclrtoeol(promptw); + wrefresh(promptw); + } + } else if (c >= '0' && c <= '9') { + buf[buflen++] = c; + wechochar(promptw, c); + } + } + + curses_prompt(""); + v->points = atoi(buf); + l->rem -= v->points; + v->rem = l->rem; +} + +void curses_match(int start_points, char *n1, void (*f1)(struct leg *), + char *n2, void (*f2)(struct leg *)) +{ + init_curses(); + + struct leg *l1 = leg_init(start_points, n1); + struct leg *l2 = leg_init(start_points, n2); + + curses_draw(l1, l2); + + while (l1->rem > 0 && l2->rem > 0) { + (*f1)(l1); + curses_draw(l1, l2); + + if (l1->rem > 0) + (*f2)(l2); + + curses_draw(l1, l2); + } + + char status[100]; + sprintf(status, " %s wins", l1->rem <= 0 ? l1->name : l2->name); + curses_status(status); + + leg_free(l1); + leg_free(l2); + wgetch(w); + free_curses(); +} + +void cvc_curses_match(int start_points) +{ + curses_match(start_points, "Dartboat 1", comp_visit, "Dartboat 2", + comp_visit); +} + +void pvc_curses_match(int start_points) +{ + curses_match(start_points, "David", user_visit, "Dartboat", comp_visit); +} + +void pvp_curses_match(int start_points) +{ + curses_match(start_points, "David", user_visit, "Davidn't", user_visit); +} + +void test_averages() +{ + int rounds = 100000; + + for (int stdev = 4; stdev < 25; ++stdev) { + horizontal_stdev = vertical_stdev = stdev; + + int darts = 0; + for (int i = 0; i < rounds; ++i) { + struct leg *l = leg_init(501, NULL); + while (l->rem > 0) + comp_visit(l); + leg_free(l); + + darts += (l->n_visits-1)*3 + l->visits[l->n_visits-1].n_darts; + } + + printf("%d %f\n", stdev, (double)(501*rounds)/darts*3); + } +} + +int main() +{ + srand(time(NULL)); + init_board(); + + //cvc_curses_match(501); + pvc_curses_match(501); + //pvp_curses_match(501); + test_match(501); + //test_averages(); + + return 0; +} diff --git a/dartbot.c b/dartbot.c deleted file mode 100644 index 1759846..0000000 --- a/dartbot.c +++ /dev/null @@ -1,167 +0,0 @@ -#include "board.h" -#include "checkouts.h" -#include "comp.h" -#include "curses.h" -#include "match.h" - -#include -#include -#include -#include - -void test_match(int start_points) -{ - struct leg *l = leg_init(start_points, NULL); - - while (l->rem > 0) - comp_visit(l); - - printf("(%2d) %3d\n", 0, l->start); - for (int i = 0; i < l->n_visits; ++i) { - struct visit *v = l->visits + i; - printf("(%2d) %3d %3d", i+1, v->points, v->rem); - - for (int j = 0; j < v->n_darts; ++j) { - char *n = segment_name(v->darts[j]); - printf(j == 0 ? " %4s" :" %4s", n); - free(n); - } - printf("\n"); - } - - leg_free(l); -} - -void user_visit(struct leg *l) -{ - if (l->n_visits == l->size_visits) - leg_grow_visits(l); - struct visit *v = l->visits + l->n_visits++; - - char status[100]; - int len = sprintf(status, " %s has %d remaining", l->name, l->rem); - if (l->rem <= 170) { - char *target = CHECKOUTS[2][l->rem-1]; - if (target) { - int trem = l->rem - segment_points(segment_from_name(target)); - len += sprintf(status + len, " (%s", target); - if (trem) { - target = CHECKOUTS[1][trem-1]; - len += sprintf(status + len, "-%s", target); - trem = trem - segment_points(segment_from_name(target)); - - if (trem) { - target = CHECKOUTS[0][trem-1]; - len += sprintf(status + len, "-%s", target); - } - } - len += sprintf(status + len, ")"); - } - } - char prompt[] = " enter points> "; - curses_status(status); - curses_prompt(prompt); - - char buf[100] = { 0 }; - int buflen = 0; - - int c; - while((c = wgetch(promptw)) != 10) { - if (c == 127) { - if (buflen > 0) { - buf[--buflen] = 0; - wmove(promptw, 0, sizeof(prompt) - 1 + buflen); - wclrtoeol(promptw); - wrefresh(promptw); - } - } else if (c >= '0' && c <= '9') { - buf[buflen++] = c; - wechochar(promptw, c); - } - } - - curses_prompt(""); - v->points = atoi(buf); - l->rem -= v->points; - v->rem = l->rem; -} - -void curses_match(int start_points, char *n1, void (*f1)(struct leg *), - char *n2, void (*f2)(struct leg *)) -{ - init_curses(); - - struct leg *l1 = leg_init(start_points, n1); - struct leg *l2 = leg_init(start_points, n2); - - curses_draw(l1, l2); - - while (l1->rem > 0 && l2->rem > 0) { - (*f1)(l1); - curses_draw(l1, l2); - - if (l1->rem > 0) - (*f2)(l2); - - curses_draw(l1, l2); - } - - char status[100]; - sprintf(status, " %s wins", l1->rem <= 0 ? l1->name : l2->name); - curses_status(status); - - leg_free(l1); - leg_free(l2); - wgetch(w); - free_curses(); -} - -void cvc_curses_match(int start_points) -{ - curses_match(start_points, "Dartbot 1", comp_visit, "Dartbot 2", comp_visit); -} - -void pvc_curses_match(int start_points) -{ - curses_match(start_points, "David", user_visit, "Dartbot", comp_visit); -} - -void pvp_curses_match(int start_points) -{ - curses_match(start_points, "David", user_visit, "Davidn't", user_visit); -} - -void test_averages() -{ - int rounds = 100000; - - for (int stdev = 4; stdev < 25; ++stdev) { - horizontal_stdev = vertical_stdev = stdev; - - int darts = 0; - for (int i = 0; i < rounds; ++i) { - struct leg *l = leg_init(501, NULL); - while (l->rem > 0) - comp_visit(l); - leg_free(l); - - darts += (l->n_visits-1)*3 + l->visits[l->n_visits-1].n_darts; - } - - printf("%d %f\n", stdev, (double)(501*rounds)/darts*3); - } -} - -int main() -{ - srand(time(NULL)); - init_board(); - - //cvc_curses_match(501); - pvc_curses_match(501); - //pvp_curses_match(501); - test_match(501); - //test_averages(); - - return 0; -} diff --git a/web/dartboat_wasm.c b/web/dartboat_wasm.c index 21d13fd..b4d232a 100644 --- a/web/dartboat_wasm.c +++ b/web/dartboat_wasm.c @@ -1,3 +1,5 @@ +#include "svg.h" + #include "checkouts.h" #include "comp.h" @@ -157,7 +159,6 @@ EMSCRIPTEN_KEEPALIVE void update_user_rem_from_pts(int pts) update_player_rem(state->active_player, state->active_leg->rem - pts); } -void draw_point(double, double); EMSCRIPTEN_KEEPALIVE void draw_boat_throwing(int pts, char *str, double x, double y) { char pts_str[10]; @@ -167,7 +168,7 @@ EMSCRIPTEN_KEEPALIVE void draw_boat_throwing(int pts, char *str, double x, doubl state->legs[1]->visits[state->legs[1]->n_visits-2].rem : state->legs[1]->start; - draw_point(x, y); + svg_draw_point(x, y); update_player_rem(2, rem - pts); EM_ASM({setPromptInput($0)}, pts_str); EM_ASM({promptMsgR($0)}, str); @@ -461,12 +462,11 @@ EMSCRIPTEN_KEEPALIVE void set_stdev(float stdev) horizontal_stdev = vertical_stdev = stdev; } -void draw_board(); void init_boat() { srand(time(NULL)); init_board(); - draw_board(); + svg_draw_board(); EM_ASM(readOpts()); EM_ASM({updateDelay($0)}, delay_ms); diff --git a/web/static/index.html b/web/static/index.html index c1a2fdd..f583449 100644 --- a/web/static/index.html +++ b/web/static/index.html @@ -85,7 +85,7 @@

To avoid destructive actions being a misclick away, certain actions require two presses—one to activate the button and another to trigger it.

The controls are designed to be keyboard-friendly. The keys should be fairly intuitive for the most part.

Info

-

dartboat is free and open-source software. It is written in C and compiled to WebAssembly for the web target. JavaScript is used to handle the interactive elements.

+

dartboat is free and open-source software. It is written in C and compiled to WebAssembly for the web target. JavaScript is used to handle the interactive elements.

diff --git a/web/svg.c b/web/svg.c new file mode 100644 index 0000000..6744ac6 --- /dev/null +++ b/web/svg.c @@ -0,0 +1,256 @@ +#include "svg.h" + +#include "board.h" +#include "comp.h" + +#include +#include +#include + +#include + +#define NUM_SECTORS 20 +#define SECTOR_WIDTH 18.0 + +#define C_BLACK "#272b2c" +#define C_WHITE "#fbe3ba" +#define C_RED "#f6302f" +#define C_GREEN "#22912d" +#define C_WIRE "#909ca0" +#define C_WIRE_INNER "#d8e6ec" + +struct elem { + char *name; + int n_attrs, size_attrs; + char **attr_names, **attr_vals; + char *content; +}; + +struct elem *elem_init(char *name, int size_attrs) +{ + struct elem *e = malloc(sizeof(*e)); + + size_t size = strlen(name) + 1; + e->name = malloc(size * sizeof(*(e->name))); + memcpy(e->name, name, size); + + e->n_attrs = 0; + e->size_attrs = size_attrs; + e->attr_names = malloc(size_attrs * sizeof(*(e->attr_names))); + e->attr_vals = malloc(size_attrs * sizeof(*(e->attr_vals))); + e->content = NULL; + + return e; +} + +void elem_free(struct elem *e) +{ + for(int i = 0; i < e->n_attrs; ++i) { + free(e->attr_names[i]); + free(e->attr_vals[i]); + } + + free(e->content); + free(e->attr_names); + free(e->attr_vals); + free(e->name); + free(e); +} + +void elem_add_attr(struct elem *e, char *name, char *val) +{ + if (e->n_attrs == e->size_attrs) { + e->size_attrs *= 2; + e->attr_names = realloc(e->attr_names, + e->size_attrs * sizeof(*(e->attr_names))); + e->attr_vals = realloc(e->attr_vals, + e->size_attrs * sizeof(*(e->attr_vals))); + } + + size_t size = strlen(name) + 1; + e->attr_names[e->n_attrs] = malloc(size); + memcpy(e->attr_names[e->n_attrs], name, size); + + size = strlen(val) + 1; + e->attr_vals[e->n_attrs] = malloc(size); + memcpy(e->attr_vals[e->n_attrs++], val, size); +} + +void elem_add_attr_double(struct elem *e, char *name, double val) +{ + char str[512]; + sprintf(str, "%f", val); + elem_add_attr(e, name, str); +} + +// draws a ring if angles are equal +struct elem *gen_arc(double a1, double a2, double r1, double r2, char *col) +{ + struct ccoords cc1 = pol_to_cart((struct pcoords){ + .a = (a1 == a2 ? 1 : a2), .r = r1 }); + struct ccoords cc2 = pol_to_cart((struct pcoords){ + .a = (a1 == a2 ? 0 : a1), .r = r1 }); + struct ccoords cc3 = pol_to_cart((struct pcoords){ + .a = (a1 == a2 ? 0 : a1), .r = r2 }); + struct ccoords cc4 = pol_to_cart((struct pcoords){ + .a = (a1 == a2 ? 1 : a2), .r = r2 }); + + struct elem *e = elem_init("path", 2); + elem_add_attr(e, "fill", col); + + char buf[512]; + int buflen = 0; + buflen += sprintf(buf + buflen, "M%f %f", cc1.x, cc1.y); + buflen += sprintf(buf + buflen, "A%f %f 0 0 0 %f %f", + r1, r1, cc2.x, cc2.y); + if (a1 == a2) + buflen += sprintf(buf + buflen, "A%f %f 0 1 0 %f %f", + r1, r1, cc1.x, cc1.y); + buflen += sprintf(buf + buflen, "L%f %f", cc3.x, cc3.y); + buflen += sprintf(buf + buflen, "A%f %f 0 0 1 %f %f", + r2, r2, cc4.x, cc4.y); + if (a1 == a2) + buflen += sprintf(buf + buflen, "A%f %f 0 1 1 %f %f", + r2, r2, cc3.x, cc3.y); + buf[buflen++] = 'Z'; + buf[buflen++] = 0; + elem_add_attr(e, "d", buf); + + return e; +} + +struct elem *gen_segment(double a, double r1, double r2, char *col) +{ + return gen_arc(a - SECTOR_WIDTH/2, a + SECTOR_WIDTH/2, r1, r2, col); +} + +struct elem *gen_ring(double r, double w, char *col) +{ + return gen_arc(0, 0, r - w/2, r + w/2, col); +} + +struct elem *gen_circle(double r, char *col) +{ + struct elem *e = elem_init("circle", 2); + elem_add_attr(e, "fill", col); + elem_add_attr_double(e, "r", r); + + return e; +} + +struct elem *gen_line(double a, double r1, double r2, double w, char *col) +{ + struct ccoords cc1 = pol_to_cart((struct pcoords){ .a = a, .r = r1 }); + struct ccoords cc2 = pol_to_cart((struct pcoords){ .a = a, .r = r2 }); + + struct elem *e = elem_init("line", 6); + elem_add_attr(e, "stroke", col); + elem_add_attr_double(e, "x1", cc1.x); + elem_add_attr_double(e, "y1", cc1.y); + elem_add_attr_double(e, "x2", cc2.x); + elem_add_attr_double(e, "y2", cc2.y); + elem_add_attr_double(e, "stroke-width", w); + + return e; +} + +int draw_spider(int elemc, struct elem **elemv) +{ + for (int i = 5; i > 1; --i) { + elemv[elemc++] = gen_ring(OUTER_DISTS[i], WIRE_WIDTH, C_WIRE); + elemv[elemc++] = gen_ring(OUTER_DISTS[i], WIRE_WIDTH/2, C_WIRE_INNER); + } + + for (int i = 0; i < NUM_SECTORS; ++i) { + double a = 90 - i*SECTOR_WIDTH - SECTOR_WIDTH/2; + if (a < 0) a += 360; + + elemv[elemc++] = gen_line(a, OUTER_DISTS[1], OUTER_DISTS[5] + 10, + WIRE_WIDTH, C_WIRE); + elemv[elemc++] = gen_line(a, OUTER_DISTS[1], OUTER_DISTS[5] + 10, + WIRE_WIDTH/2, C_WIRE_INNER); + } + + for (int i = 1; i >= 0; --i) { + elemv[elemc++] = gen_ring(OUTER_DISTS[i], WIRE_WIDTH, C_WIRE); + elemv[elemc++] = gen_ring(OUTER_DISTS[i], WIRE_WIDTH/2, C_WIRE_INNER); + } + + return elemc; +} + +int draw_numbers(int elemc, struct elem **elemv) +{ + elemv[elemc++] = gen_ring(DIAMETER/2 - WIRE_WIDTH*4, WIRE_WIDTH, "#ddd"); + + int r = DIAMETER/2 - 33/2; + for (int i = 0; i < 20; ++i) { + struct elem *e = elemv[elemc++] = elem_init("text", 5); + elem_add_attr(e, "font-size", "33"); + elem_add_attr(e, "fill", "#fff"); + elem_add_attr(e, "text-anchor", "middle"); + elem_add_attr(e, "dominant-baseline", "central"); + + char buf[512]; + double a = 90 - i*SECTOR_WIDTH; + if (a < 0) a += 360; + struct ccoords cc = pol_to_cart((struct pcoords){ .a = a, .r = r }); + sprintf(buf, "scale(1 -1) translate(%f %f) rotate(%f)", + cc.x, -cc.y, a <= 180 ? 90 -a : 270 -a); + elem_add_attr(e, "transform", buf); + + e->content = malloc(3); + sprintf(e->content, "%d", SECTORS[i]); + } + + return elemc; +} + +void draw_elemv(int layer, int elemc, struct elem **elemv) +{ + EM_ASM({svgDrawElemv($0, $1, $2, $3, $4, $5, $6, $7)}, + layer, elemc, elemv, + offsetof(struct elem, name), offsetof(struct elem, n_attrs), + offsetof(struct elem, attr_names), offsetof(struct elem, attr_vals), + offsetof(struct elem, content)); +} + +void svg_draw_board() +{ + struct elem **elemv = malloc(200 * sizeof(*elemv)); + int elemc = 0; + + elemv[elemc++] = gen_circle(DIAMETER/2, C_BLACK); + + for (int i = 5; i > 1; --i) { + for (int j = 0; j < NUM_SECTORS; ++j) { + double a = 90 - j*SECTOR_WIDTH; + if (a < 0) a += 360; + elemv[elemc++] = gen_segment(a, OUTER_DISTS[i-1], OUTER_DISTS[i], + i%2 ? (j%2 ? C_GREEN : C_RED) : (j%2 ? C_WHITE : C_BLACK)); + } + } + + elemv[elemc++] = gen_circle(OUTER_DISTS[1], C_GREEN); + elemv[elemc++] = gen_circle(OUTER_DISTS[0], C_RED); + + elemc = draw_spider(elemc, elemv); + elemc = draw_numbers(elemc, elemv); + + draw_elemv(0, elemc, elemv); + + for (int i = 0; i < elemc; ++i) + free(elemv[i]); + free(elemv); +} + +void svg_draw_point(double x, double y) { + struct elem *e = gen_circle(8, "#33f"); + elem_add_attr(e, "stroke", "#ff0"); + elem_add_attr(e, "stroke-width", "2"); + elem_add_attr_double(e, "cx", x); + elem_add_attr_double(e, "cy", y); + + draw_elemv(1, 1, &e); + elem_free(e); +} diff --git a/web/svg.h b/web/svg.h new file mode 100644 index 0000000..3321846 --- /dev/null +++ b/web/svg.h @@ -0,0 +1,7 @@ +#ifndef SVG_H +#define SVG_H + +void svg_draw_board(); +void svg_draw_point(double x, double y); + +#endif diff --git a/web/svg_dartboard.c b/web/svg_dartboard.c deleted file mode 100644 index 1125ef0..0000000 --- a/web/svg_dartboard.c +++ /dev/null @@ -1,256 +0,0 @@ -#include "board.h" -#include "comp.h" - -#include -#include -#include - -#include - -#define NUM_SECTORS 20 -#define SECTOR_WIDTH 18.0 - -#define C_BLACK "#272b2c" -#define C_WHITE "#fbe3ba" -#define C_RED "#f6302f" -#define C_GREEN "#22912d" -#define C_WIRE "#909ca0" -#define C_WIRE_INNER "#d8e6ec" - -struct elem { - char *name; - int n_attrs; - int size_attrs; - char **attr_names; - char **attr_vals; - char *content; -}; - -struct elem *elem_init(char *name, int size_attrs) -{ - struct elem *e = malloc(sizeof(*e)); - - size_t size = strlen(name) + 1; - e->name = malloc(size * sizeof(*(e->name))); - memcpy(e->name, name, size); - - e->n_attrs = 0; - e->size_attrs = size_attrs; - e->attr_names = malloc(size_attrs * sizeof(*(e->attr_names))); - e->attr_vals = malloc(size_attrs * sizeof(*(e->attr_vals))); - e->content = NULL; - - return e; -} - -void elem_free(struct elem *e) -{ - for(int i = 0; i < e->n_attrs; ++i) { - free(e->attr_names[i]); - free(e->attr_vals[i]); - } - - free(e->content); - free(e->attr_names); - free(e->attr_vals); - free(e->name); - free(e); -} - -void elem_add_attr(struct elem *e, char *name, char *val) -{ - if (e->n_attrs == e->size_attrs) { - e->size_attrs *= 2; - e->attr_names = realloc(e->attr_names, - e->size_attrs * sizeof(*(e->attr_names))); - e->attr_vals = realloc(e->attr_vals, - e->size_attrs * sizeof(*(e->attr_vals))); - } - - size_t size = strlen(name) + 1; - e->attr_names[e->n_attrs] = malloc(size); - memcpy(e->attr_names[e->n_attrs], name, size); - - size = strlen(val) + 1; - e->attr_vals[e->n_attrs] = malloc(size); - memcpy(e->attr_vals[e->n_attrs++], val, size); -} - -void elem_add_attr_double(struct elem *e, char *name, double val) -{ - char str[512]; - sprintf(str, "%f", val); - elem_add_attr(e, name, str); -} - -// draws a ring if angles are equal -struct elem *gen_arc(double a1, double a2, double r1, double r2, char *col) -{ - struct ccoords cc1 = pol_to_cart((struct pcoords){ - .a = (a1 == a2 ? 1 : a2), .r = r1 }); - struct ccoords cc2 = pol_to_cart((struct pcoords){ - .a = (a1 == a2 ? 0 : a1), .r = r1 }); - struct ccoords cc3 = pol_to_cart((struct pcoords){ - .a = (a1 == a2 ? 0 : a1), .r = r2 }); - struct ccoords cc4 = pol_to_cart((struct pcoords){ - .a = (a1 == a2 ? 1 : a2), .r = r2 }); - - struct elem *e = elem_init("path", 2); - elem_add_attr(e, "fill", col); - - char buf[512]; - int buflen = 0; - buflen += sprintf(buf + buflen, "M%f %f", cc1.x, cc1.y); - buflen += sprintf(buf + buflen, "A%f %f 0 0 0 %f %f", - r1, r1, cc2.x, cc2.y); - if (a1 == a2) - buflen += sprintf(buf + buflen, "A%f %f 0 1 0 %f %f", - r1, r1, cc1.x, cc1.y); - buflen += sprintf(buf + buflen, "L%f %f", cc3.x, cc3.y); - buflen += sprintf(buf + buflen, "A%f %f 0 0 1 %f %f", - r2, r2, cc4.x, cc4.y); - if (a1 == a2) - buflen += sprintf(buf + buflen, "A%f %f 0 1 1 %f %f", - r2, r2, cc3.x, cc3.y); - buf[buflen++] = 'Z'; - buf[buflen++] = 0; - elem_add_attr(e, "d", buf); - - return e; -} - -struct elem *gen_segment(double a, double r1, double r2, char *col) -{ - return gen_arc(a - SECTOR_WIDTH/2, a + SECTOR_WIDTH/2, r1, r2, col); -} - -struct elem *gen_ring(double r, double w, char *col) -{ - return gen_arc(0, 0, r - w/2, r + w/2, col); -} - -struct elem *gen_circle(double r, char *col) -{ - struct elem *e = elem_init("circle", 2); - elem_add_attr(e, "fill", col); - elem_add_attr_double(e, "r", r); - - return e; -} - -struct elem *gen_line(double a, double r1, double r2, double w, char *col) -{ - struct ccoords cc1 = pol_to_cart((struct pcoords){ .a = a, .r = r1 }); - struct ccoords cc2 = pol_to_cart((struct pcoords){ .a = a, .r = r2 }); - - struct elem *e = elem_init("line", 6); - elem_add_attr(e, "stroke", col); - elem_add_attr_double(e, "x1", cc1.x); - elem_add_attr_double(e, "y1", cc1.y); - elem_add_attr_double(e, "x2", cc2.x); - elem_add_attr_double(e, "y2", cc2.y); - elem_add_attr_double(e, "stroke-width", w); - - return e; -} - -int draw_spider(int elemc, struct elem **elemv) -{ - for (int i = 5; i > 1; --i) { - elemv[elemc++] = gen_ring(OUTER_DISTS[i], WIRE_WIDTH, C_WIRE); - elemv[elemc++] = gen_ring(OUTER_DISTS[i], WIRE_WIDTH/2, C_WIRE_INNER); - } - - for (int i = 0; i < NUM_SECTORS; ++i) { - double a = 90 - i*SECTOR_WIDTH - SECTOR_WIDTH/2; - if (a < 0) a += 360; - - elemv[elemc++] = gen_line(a, OUTER_DISTS[1], OUTER_DISTS[5] + 10, - WIRE_WIDTH, C_WIRE); - elemv[elemc++] = gen_line(a, OUTER_DISTS[1], OUTER_DISTS[5] + 10, - WIRE_WIDTH/2, C_WIRE_INNER); - } - - for (int i = 1; i >= 0; --i) { - elemv[elemc++] = gen_ring(OUTER_DISTS[i], WIRE_WIDTH, C_WIRE); - elemv[elemc++] = gen_ring(OUTER_DISTS[i], WIRE_WIDTH/2, C_WIRE_INNER); - } - - return elemc; -} - -int draw_numbers(int elemc, struct elem **elemv) -{ - elemv[elemc++] = gen_ring(DIAMETER/2 - WIRE_WIDTH*4, WIRE_WIDTH, "#ddd"); - - int r = DIAMETER/2 - 33/2; - for (int i = 0; i < 20; ++i) { - struct elem *e = elemv[elemc++] = elem_init("text", 5); - elem_add_attr(e, "font-size", "33"); - elem_add_attr(e, "fill", "#fff"); - elem_add_attr(e, "text-anchor", "middle"); - elem_add_attr(e, "dominant-baseline", "central"); - - char buf[512]; - double a = 90 - i*SECTOR_WIDTH; - if (a < 0) a += 360; - struct ccoords cc = pol_to_cart((struct pcoords){ .a = a, .r = r }); - sprintf(buf, "scale(1 -1) translate(%f %f) rotate(%f)", - cc.x, -cc.y, a <= 180 ? 90 -a : 270 -a); - elem_add_attr(e, "transform", buf); - - e->content = malloc(3); - sprintf(e->content, "%d", SECTORS[i]); - } - - return elemc; -} - -void draw_elemv(int layer, int elemc, struct elem **elemv) -{ - EM_ASM({svgDrawElemv($0, $1, $2, $3, $4, $5, $6, $7)}, - layer, elemc, elemv, - offsetof(struct elem, name), offsetof(struct elem, n_attrs), - offsetof(struct elem, attr_names), offsetof(struct elem, attr_vals), - offsetof(struct elem, content)); -} - -void draw_board() -{ - struct elem **elemv = malloc(500 * sizeof(*elemv)); - int elemc = 0; - - elemv[elemc++] = gen_circle(DIAMETER/2, C_BLACK); - - for (int i = 5; i > 1; --i) { - for (int j = 0; j < NUM_SECTORS; ++j) { - double a = 90 - j*SECTOR_WIDTH; - if (a < 0) a += 360; - elemv[elemc++] = gen_segment(a, OUTER_DISTS[i-1], OUTER_DISTS[i], - i%2 ? (j%2 ? C_GREEN : C_RED) : (j%2 ? C_WHITE : C_BLACK)); - } - } - - elemv[elemc++] = gen_circle(OUTER_DISTS[1], C_GREEN); - elemv[elemc++] = gen_circle(OUTER_DISTS[0], C_RED); - - elemc = draw_spider(elemc, elemv); - elemc = draw_numbers(elemc, elemv); - - draw_elemv(0, elemc, elemv); - - for (int i = 0; i < elemc; ++i) - free(elemv[i]); - free(elemv); -} - -void draw_point(double x, double y) { - struct elem *e = gen_circle(8, "#33f"); - elem_add_attr(e, "stroke", "#ff0"); - elem_add_attr(e, "stroke-width", "2"); - elem_add_attr_double(e, "cx", x); - elem_add_attr_double(e, "cy", y); - - draw_elemv(1, 1, &e); - elem_free(e); -} -- cgit v1.2.3-70-g09d2