#include "comp.h" #include "match.h" #include #include #include struct leg *leg_init(int pts) { struct leg *l = calloc(1, sizeof(*l)); l->start = l->rem = pts; l->size_visits = 16; l->visits = calloc(l->size_visits, sizeof(*l->visits)); return l; } void leg_free(struct leg *l) { // readd undone visits before free to avoid memory leak l->n_visits += l->undone_visits; for (int i = 0; i < l->n_visits; ++i) { free(l->visits[i].darts); free(l->visits[i].ccoords); } free(l->visits); free(l); } void leg_grow_visits(struct leg *l) { size_t bytes = l->size_visits * sizeof(*l->visits); l->size_visits *= 2; l->visits = realloc(l->visits, 2 * bytes); memset((char *)l->visits + bytes, 0, bytes); } void leg_undo_visit(struct leg *l) { l->rem += l->visits[--l->n_visits].points; ++l->undone_visits; } struct visit *leg_redo_visit(struct leg *l) { struct visit *v = l->visits + l->n_visits++; l->rem = v->rem; --l->undone_visits; return v; } static void leg_clear_first_undone(struct leg *l) { free(l->visits[l->n_visits].darts); free(l->visits[l->n_visits].ccoords); memset(l->visits + l->n_visits, 0, sizeof(*l->visits)); --l->undone_visits; } struct visit *leg_comp_visit(struct leg *l, bool redo_undone) { if (redo_undone && l->undone_visits) return leg_redo_visit(l); if (l->undone_visits) leg_clear_first_undone(l); comp_visit(l); struct visit *v = l->visits + l->n_visits - 1; return v; } struct visit *leg_pts_visit(struct leg *l, int pts) { if (!is_points_valid(pts, l->rem)) return NULL; if (l->undone_visits) leg_clear_first_undone(l); if (l->n_visits == l->size_visits) leg_grow_visits(l); struct visit *v = l->visits + l->n_visits++; v->points = pts; l->rem -= pts; v->rem = l->rem; return v; } struct match *match_init() { struct match *m = calloc(1, sizeof(*m)); m->size_players = 2; m->players = malloc(m->size_players * sizeof(*m->players)); m->legs = malloc(m->size_players * sizeof(*m->legs)); return m; } void match_free(struct match *m) { for (int i = 0; i < m->n_players; ++i) { free(m->players[i].name); leg_free(m->legs[i]); } free(m->players); free(m->legs); free(m); } static void match_grow_players(struct match *m) { m->size_players *= 2; m->players = realloc(m->players, m->size_players * sizeof(*m->players)); m->legs = realloc(m->legs, m->size_players * sizeof(*m->legs)); } void match_add_player(struct match *m, enum player_type type, char *name, int start_pts) { if (m->n_players == m->size_players) match_grow_players(m); int i = m->n_players++; if (!m->starting_player) m->starting_player = i; struct player *p = m->players + i; p->type = type; p->name = strdup(name); m->legs[i] = leg_init(start_pts); } int match_next_player(struct match *m) { if (m->active_player == m->n_players) return 1; else return m->active_player + 1; } int match_prev_player(struct match *m) { if (m->active_player == 1) return m->n_players; else return m->active_player - 1; } int match_prev_throw_player(struct match *m) { int pn = match_winning_player(m); return pn ? pn : match_prev_player(m); } int match_winning_player(struct match *m) { for (int i = 0; i < m->n_players; ++i) { if (m->legs[i]->rem == 0) return i + 1; } return 0; } bool match_first_user_has_thrown(struct match *m) { for (int i = 0; i < m->n_players; ++i) { int pn = m->starting_player + i; if (pn > m->n_players) pn -= m->n_players; if (m->players[pn - 1].type == PT_USER) return !!m->legs[pn - 1]->n_visits; } return false; } bool is_points_valid(int pts, int rem) { return pts <= rem && rem - pts != 1 && pts >= 0 && pts <= 180 && pts != 179 && pts != 178 && pts != 176 && pts != 175 && pts != 173 && pts != 172 && pts != 169 && pts != 166 && pts != 163 && (rem - pts != 0 || (pts <= 170 && pts != 168 && pts != 165 && pts != 162 && pts != 159)); }