#include #include #include #include #include #include #define HORIZONTAL_STDEV 50 #define VERTICAL_STDEV 50 // board spec from WDF rules #define WIRE_WIDTH 1.56 #define INNER_DIAMETER_BULL 12.7 #define INNER_DIAMETER_25 31.8 #define DOUBLE_OUTER_EDGE 170.0 #define TREBLE_OUTER_EDGE 107.4 #define DOUBLE_INSIDE_WIDTH 8.0 #define TREBLE_INSIDE_WIDTH 8.0 #define SEGMENT_MAX_LEN 5 // distance from centre to apex of outer wire // must be ordered outwards from centre #define FOREACH_RING(M) \ M(BULL, INNER_DIAMETER_BULL/2 + WIRE_WIDTH/2) \ M(25, INNER_DIAMETER_25/2 + WIRE_WIDTH/2) \ M(SMALL, TREBLE_OUTER_EDGE - WIRE_WIDTH - TREBLE_INSIDE_WIDTH - \ WIRE_WIDTH/2) \ M(TREBLE, TREBLE_OUTER_EDGE - WIRE_WIDTH/2) \ M(BIG, DOUBLE_OUTER_EDGE - WIRE_WIDTH - DOUBLE_INSIDE_WIDTH - \ WIRE_WIDTH/2) \ M(DOUBLE, DOUBLE_OUTER_EDGE - WIRE_WIDTH/2) #define GEN_RING_ENUM(X, D) R_ ## X, #define GEN_RING_STRING(X, D) #X, #define GEN_RING_OUTER_DIST(X, D) D, int sectors[] = { 20, 1, 18, 4, 13, 6, 10, 15, 2, 17, 3, 19, 7, 16, 8, 11, 14, 9, 12, 5 }; enum ring { FOREACH_RING(GEN_RING_ENUM) R_OUT }; char *RING_NAMES[] = { FOREACH_RING(GEN_RING_STRING) "OUT" }; double OUTER_DISTS[] = { FOREACH_RING(GEN_RING_OUTER_DIST) }; double CENTRE_DISTS[sizeof(OUTER_DISTS)/sizeof(*OUTER_DISTS)]; void init_centre_dists() { CENTRE_DISTS[0] = 0; for (int i = R_25; i < R_OUT; ++i) CENTRE_DISTS[i] = (OUTER_DISTS[i] - ((OUTER_DISTS[i] - OUTER_DISTS[i-1]) / 2)); } struct ccoords { double x, y; }; struct pcoords { double a, r; }; struct segment { enum ring ring; int sector; }; int get_sector(double angle) { //return sectors[(int)(fmod(angle + 279, 360) / 18)]; double shifted = angle + 279; return sectors[(int)((shifted - (360 * floor(shifted / 360))) / 18)]; } enum ring get_ring(double radius) { for (int i = R_BULL; i < R_OUT; ++i) if (radius < OUTER_DISTS[i]) return i; return R_OUT; } double drand() { return (double)rand() / RAND_MAX; } double gauss(double mean, double stdev) { static bool have_next; static double next; double curr; if (have_next) { curr = next; } else { double theta = 2 * M_PI * drand(); double r = sqrt(-2 * log(1 - drand())); curr = r * cos(theta); next = r * sin(theta); } have_next = !have_next; return mean + (curr * stdev); } struct ccoords get_offset() { return (struct ccoords){ .x = gauss(0, HORIZONTAL_STDEV), .y = gauss(0, VERTICAL_STDEV) }; } struct ccoords pol_to_cart(struct pcoords c) { double t = c.a * (M_PI / 180); double x = c.r * cos(t); double y = c.r * sin(t); return (struct ccoords){ .x = x, .y = y }; } struct pcoords cart_to_pol(struct ccoords c) { double a = atan2(c.y, c.x) * (180 / M_PI); double r = sqrt(pow(c.x, 2) + pow(c.y, 2)); return (struct pcoords){ .a = a, .r = r }; } struct pcoords throw_dart(struct pcoords target) { struct ccoords cc = pol_to_cart(target); struct ccoords offset = get_offset(); return cart_to_pol((struct ccoords){ .x = cc.x + offset.x, .y = cc.y + offset.y }); } struct segment get_segment(struct pcoords c) { return (struct segment){ .sector = get_sector(c.a), .ring = get_ring(c.r) }; } char *segment_name(struct segment seg) { char *str = malloc(SEGMENT_MAX_LEN); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wstringop-truncation" if (seg.ring == R_BULL || seg.ring == R_25 || seg.ring == R_OUT) strncpy(str, RING_NAMES[seg.ring], SEGMENT_MAX_LEN); else snprintf(str, SEGMENT_MAX_LEN, (seg.ring == R_TREBLE ? "T%d" : (seg.ring == R_DOUBLE ? "D%d" : "%d")), seg.sector); #pragma GCC diagnostic pop return str; } int main() { /* initscr(); addstr("test"); refresh(); getch(); endwin(); */ srand(time(NULL)); init_centre_dists(); struct pcoords t = { .a = 90, .r = 100 }; struct pcoords res = throw_dart(t); struct segment seg = get_segment(res); for (int i = 0; i < 20; ++i) { res = throw_dart(t); seg = get_segment(res); char *name = segment_name(seg); printf("%d %f %f %d %s %s\n", seg.sector, res.a, res.r, seg.ring, RING_NAMES[seg.ring], name); free(name); } /* printf("\n"); for (int i = 0; i < 6; i++) { printf("%.2f\n%.2f\n\n", CENTRE_DISTS[i], OUTER_DISTS[i]); } */ return 0; }