Exemple #1
0
    def get(self, event_id):
        event = Event.get_by_id(event_id)
        if not event:
            self.redirect(uri_for('home'))

        weightclasses = Weightclass.get_by_event(event_id)
        generate_form = GenerateBracketForm()
        weightclass_choices = []
        brackets = {}
        for weightclass in weightclasses:
            bots = Bot.get_by_weightclass_registered(weightclass.code,
                                                     event.id)
            if len(bots) > 1:
                weightclass_choices.append(
                    (weightclass.code,
                     '%s (%d bots)' % (weightclass.name, len(bots))))
            brackets[weightclass.name] = []
            weightclass_brackets = Bracket.get_by_event_and_class(
                event_id, weightclass.code)
            for bracket in weightclass_brackets:
                matches = Match.get_by_bracket(bracket.id)
                completed_matches = [
                    match for match in matches if match.winning_bot_id
                ]
                bots = Bot.get_by_bracket(bracket.id)

                brackets[weightclass.name].append({
                    'total_matches':
                    len(matches) if matches else 0,
                    'completed_matches':
                    len(completed_matches) if completed_matches else 0,
                    'total_bots':
                    len(bots) if bots else 0,
                    'bracket':
                    bracket,
                    'format':
                    FORMATS.get(bracket.format_code)
                })
        generate_form.weightclass.choices = weightclass_choices

        context = {
            'event_brackets': brackets,
            'event': event,
            'generate_form': generate_form,
            'weightclasses': weightclasses
        }
        self.render_response('brackets.html', **context)
Exemple #2
0
    def get(self, event_id, bracket_id):
        event = Event.get_by_id(event_id)
        if not event:
            self.redirect(uri_for('home'))

        bracket = Bracket.get_by_id(bracket_id)
        if not bracket:
            self.redirect(uri_for('brackets', event_id=event_id))

        bots = Bot.get_by_weightclass_registered(bracket.weightclass_code, event.id)

        context = {
            'event': event,
            'bracket': bracket,
            'bots': json.dumps([{'id': bot.id, 'name': bot.name} for bot in bots])
        }
        self.render_response('seed.html', **context)
Exemple #3
0
    def get(self, event_id, bracket_id):
        event = Event.get_by_id(event_id)
        if not event:
            self.redirect(uri_for('home'))

        bracket = Bracket.get_by_id(bracket_id)
        if not bracket:
            self.redirect(uri_for('brackets', event_id=event_id))

        bots = Bot.get_by_weightclass_registered(bracket.weightclass_code,
                                                 event.id)

        context = {
            'event': event,
            'bracket': bracket,
            'bots': json.dumps([{
                'id': bot.id,
                'name': bot.name
            } for bot in bots])
        }
        self.render_response('seed.html', **context)
Exemple #4
0
    def get(self, event_id):
        event = Event.get_by_id(event_id)
        if not event:
            self.redirect(uri_for('home'))

        weightclasses = Weightclass.get_by_event(event_id)
        generate_form = GenerateBracketForm()
        weightclass_choices = []
        brackets = {}
        for weightclass in weightclasses:
            bots = Bot.get_by_weightclass_registered(weightclass.code, event.id)
            if len(bots) > 1:
                weightclass_choices.append((weightclass.code, '%s (%d bots)' % (weightclass.name, len(bots))))
            brackets[weightclass.name] = []
            weightclass_brackets = Bracket.get_by_event_and_class(event_id, weightclass.code)
            for bracket in weightclass_brackets:
                matches = Match.get_by_bracket(bracket.id)
                completed_matches = [match for match in matches if match.winning_bot_id]
                bots = Bot.get_by_bracket(bracket.id)

                brackets[weightclass.name].append({
                    'total_matches': len(matches) if matches else 0,
                    'completed_matches': len(completed_matches) if completed_matches else 0,
                    'total_bots': len(bots) if bots else 0,
                    'bracket': bracket,
                    'format': FORMATS.get(bracket.format_code)
                })
        generate_form.weightclass.choices = weightclass_choices

        context = {
            'event_brackets': brackets,
            'event': event,
            'generate_form': generate_form,
            'weightclasses': weightclasses
        }
        self.render_response('brackets.html', **context)
Exemple #5
0
    def generate(self, seeding=None):
        """
        generate the bracket
        """

        # find all registered bots in the given class
        bots = Bot.get_by_weightclass_registered(self.weightclass_code,
                                                 self.event_id,
                                                 order="id")

        # defines the order for matches to spread out the byes better, probably a formula for this but didn't take time to figure it out
        match_ordering = {
            2: [1, 2],
            4: [1, 3, 2, 4],
            8: [1, 8, 5, 4, 3, 6, 7, 2],
            16: [1, 16, 9, 8, 5, 12, 13, 4, 3, 14, 11, 6, 7, 10, 15, 2]
        }

        # need at least 2 bots to generate a chart
        if (len(bots) < 2):
            return False

        # manual seeding, if passed in (is dumb, assumes # of seeds matches # of bots)
        if seeding:
            for i, bot_id in enumerate(seeding):
                bot = Bot.get_by_id(bot_id)
                bot.seed_number = i
                bot.bracket_id = self.id
                bot.put()
        else:
            # generate a random array for the seeding
            seeds = range(0, len(bots))
            shuffle(seeds)

            # assign the seeds
            for i, bot in enumerate(bots):
                bot.seed_number = seeds[i]
                bot.bracket_id = self.id
                bot.put()

        # generate matches
        if self.format_code.upper() != 'ROUNDROBIN':
            chart_size = 2

            # find the first power of 2 higher than the number of bots in the bracket, this is our chart size
            num_rounds = 1
            while (len(bots) > chart_size):
                chart_size *= 2
                num_rounds += 1

            # create first round matches, do our best to avoid a team fighting itself first round
            # will regenerate up to 5 times until it gives up on avoiding first round team fighting self
            for _ in xrange(0, 5):
                matches = []
                for i in xrange(0, chart_size / 2):
                    bot1_seed = i
                    bot2_seed = chart_size - 1 - i

                    bot1 = Bot.get_by_bracket_seed(self.event_id, self.id,
                                                   bot1_seed)
                    bot2 = Bot.get_by_bracket_seed(self.event_id, self.id,
                                                   bot2_seed)
                    bot1_id = bot1.id
                    bot2_id = bot2.id if bot2 else 0

                    match = Match(number=match_ordering[chart_size / 2][i],
                                  bracket_id=self.id,
                                  bracket_side="A",
                                  round="A",
                                  bot1_id=bot1_id,
                                  bot2_id=bot2_id)
                    matches.append(match)

                conflict = False
                for match in matches:
                    if match.bot1_id > 0 and match.bot2_id > 0:
                        bot1 = Bot.get_by_id(match.bot1_id)
                        bot2 = Bot.get_by_id(match.bot2_id)
                        if bot1.team_name == bot2.team_name:
                            conflict = True
                            break

                if not conflict:
                    break

            [match.put() for match in matches]

            # create the rest of the A side matches, one round at a time
            for i in xrange(2, num_rounds + 1):
                round_letter = chr(63 + (2 * i))  #A,C,E etc
                for j in xrange(1, chart_size / pow(2, i) + 1):
                    bot1_source = 'W%s%d' % (chr(63 + (2 * i) - 2), (j * 2 - 1)
                                             )  # ie WA1 (Winner of A1)
                    bot2_source = 'W%s%d' % (chr(63 + (2 * i) - 2), (j * 2))
                    match = Match(number=j,
                                  bracket_id=self.id,
                                  bracket_side="A",
                                  round=round_letter,
                                  bot1_source_match=bot1_source,
                                  bot2_source_match=bot2_source)
                    match.put()

            # generate B side matches, if necessary
            if self.format_code.upper(
            ) == 'DOUBLEELIM' or self.format_code.upper() == 'DOUBLETRUE':
                num_b_rounds = num_rounds * 2 - 1
                for i in xrange(2, num_b_rounds + 1):
                    round_letter = chr(62 + (2 * i))
                    round_size = int(chart_size / pow(2, math.floor(
                        (i + 2) / 2)))
                    for j in xrange(1, round_size + 1):
                        if i == 2:  # only case where a loser moves into bot1 spot
                            bot1_source = 'LA%d' % (j * 2 - 1)
                            bot2_source = 'LA%d' % (j * 2)
                        else:
                            if i % 2 == 1:  # means this round's bot2 is sourced from A side
                                # losing source bots need to be from opposite side of chart as to prevent rematches
                                bot1_source = 'W%s%d' % (chr(60 + (2 * i)), j)
                                bot2_source = 'L%s' % (chr(64 + i))
                                # match order depends how far into B side we are
                                # 3 possibilities: normal, reverse, half shift
                                if i % 7 == 0:  # normal
                                    bot2_source = '%s%d' % (bot2_source, j)
                                elif i % 5 == 0:  # half shift
                                    if j < round_size / 2:
                                        bot2_source = '%s%d' % (
                                            bot2_source,
                                            math.ceil((round_size / 2) + j))
                                    else:
                                        bot2_source = '%s%d' % (
                                            bot2_source,
                                            math.ceil((0 -
                                                       (round_size / 2)) + j))
                                else:  # reverse
                                    bot2_source = '%s%d' % (bot2_source,
                                                            round_size + 1 - j)
                            else:
                                bot1_source = 'W%s%d' % (chr(60 + (2 * i)),
                                                         (j * 2 - 1))
                                bot2_source = 'W%s%d' % (chr(60 + (2 * 1)),
                                                         (j * 2))

                        match = Match(number=j,
                                      bracket_id=self.id,
                                      bracket_side="B",
                                      round=round_letter,
                                      bot1_source_match=bot1_source,
                                      bot2_source_match=bot2_source)
                        match.put()

                # insert final A-side match
                round_letter = chr(63 + (2 * (num_rounds + 1)))
                bot1_source = 'W%s1' % chr(63 + (2 * num_rounds))
                bot2_source = 'W%s1' % chr(60 + (2 * (num_b_rounds + 1)))
                match = Match(number=1,
                              bracket_id=self.id,
                              bracket_side="A",
                              round=round_letter,
                              bot1_source_match=bot1_source,
                              bot2_source_match=bot2_source)
                match.put()

            matches_to_update = Match.get_by_bracket_round(self.id, 'A')
            for match in matches_to_update:
                match.check()

        else:  #ROUNDROBIN
            bot_index = 1  # start at 1 because bot0 can't fight bot0 etc
            for bot in bots:
                match_index = 1
                for i in xrange(bot_index, len(bots)):
                    match = Match(number=match_index,
                                  round=chr(64 + bot_index),
                                  bracket_id=self.id,
                                  bracket_side="A",
                                  bot1_id=bot.id,
                                  bot2_id=bots[i].id)
                    match.put()
                    match_index += 1
                bot_index += 1

        return True
Exemple #6
0
    def generate(self, seeding=None):
        """
        generate the bracket
        """

        # find all registered bots in the given class
        bots = Bot.get_by_weightclass_registered(self.weightclass_code, self.event_id, order="id")

        # defines the order for matches to spread out the byes better, probably a formula for this but didn't take time to figure it out
        match_ordering = {
            2: [1, 2],
            4: [1, 3, 2, 4],
            8: [1, 8, 5, 4, 3, 6, 7, 2],
            16: [1, 16, 9, 8, 5, 12, 13, 4, 3, 14, 11, 6, 7, 10, 15, 2]
        }

        # need at least 2 bots to generate a chart
        if(len(bots) < 2):
            return False

        # manual seeding, if passed in (is dumb, assumes # of seeds matches # of bots)
        if seeding:
            for i, bot_id in enumerate(seeding):
                bot = Bot.get_by_id(bot_id)
                bot.seed_number = i
                bot.bracket_id = self.id
                bot.put()
        else:
            # generate a random array for the seeding
            seeds = range(0, len(bots))
            shuffle(seeds)

            # assign the seeds
            for i, bot in enumerate(bots):
                bot.seed_number = seeds[i]
                bot.bracket_id = self.id
                bot.put()

        # generate matches
        if self.format_code.upper() != 'ROUNDROBIN':
            chart_size = 2

            # find the first power of 2 higher than the number of bots in the bracket, this is our chart size
            num_rounds = 1
            while(len(bots) > chart_size):
                chart_size *= 2
                num_rounds += 1

            # create first round matches, do our best to avoid a team fighting itself first round
            # will regenerate up to 5 times until it gives up on avoiding first round team fighting self
            for _ in xrange(0,5):
                matches = []
                for i in xrange(0, chart_size/2):
                    bot1_seed = i
                    bot2_seed = chart_size - 1 - i

                    bot1 = Bot.get_by_bracket_seed(self.event_id, self.id, bot1_seed)
                    bot2 = Bot.get_by_bracket_seed(self.event_id, self.id, bot2_seed)
                    bot1_id = bot1.id
                    bot2_id = bot2.id if bot2 else 0

                    match = Match(number=match_ordering[chart_size/2][i],
                                  bracket_id=self.id,
                                  bracket_side="A",
                                  round="A",
                                  bot1_id=bot1_id,
                                  bot2_id=bot2_id)
                    matches.append(match)

                conflict = False
                for match in matches:
                    if match.bot1_id > 0 and match.bot2_id > 0:
                        bot1 = Bot.get_by_id(match.bot1_id)
                        bot2 = Bot.get_by_id(match.bot2_id)
                        if bot1.team_name == bot2.team_name:
                            conflict = True
                            break

                if not conflict:
                    break

            [match.put() for match in matches]

            # create the rest of the A side matches, one round at a time
            for i in xrange(2, num_rounds+1):
                round_letter = chr(63+(2*i))  #A,C,E etc
                for j in xrange(1, chart_size/pow(2, i)+1):
                    bot1_source = 'W%s%d' % (chr(63+(2*i)-2), (j*2-1))  # ie WA1 (Winner of A1)
                    bot2_source = 'W%s%d' % (chr(63+(2*i)-2), (j*2))
                    match = Match(number=j,
                                  bracket_id=self.id,
                                  bracket_side="A",
                                  round=round_letter,
                                  bot1_source_match=bot1_source,
                                  bot2_source_match=bot2_source)
                    match.put()

            # generate B side matches, if necessary
            if self.format_code.upper() == 'DOUBLEELIM' or self.format_code.upper() == 'DOUBLETRUE':
                num_b_rounds = num_rounds * 2 - 1
                for i in xrange(2, num_b_rounds + 1):
                    round_letter = chr(62+(2*i))
                    round_size = int(chart_size/pow(2, math.floor((i+2)/2)))
                    for j in xrange(1, round_size+1):
                        if i==2:  # only case where a loser moves into bot1 spot
                            bot1_source = 'LA%d' % (j*2-1)
                            bot2_source = 'LA%d' % (j*2)
                        else:
                            if i%2 == 1:  # means this round's bot2 is sourced from A side
                                # losing source bots need to be from opposite side of chart as to prevent rematches
                                bot1_source = 'W%s%d' % (chr(60+(2*i)), j)
                                bot2_source = 'L%s' % (chr(64+i))
                                # match order depends how far into B side we are
                                # 3 possibilities: normal, reverse, half shift
                                if i%7 == 0:  # normal
                                    bot2_source = '%s%d' % (bot2_source, j)
                                elif i%5 == 0:  # half shift
                                    if j < round_size/2:
                                        bot2_source = '%s%d' % (bot2_source, math.ceil((round_size/2) + j))
                                    else:
                                        bot2_source = '%s%d' % (bot2_source, math.ceil((0-(round_size/2))+j))
                                else:  # reverse
                                    bot2_source = '%s%d' % (bot2_source, round_size + 1 - j)
                            else:
                                bot1_source = 'W%s%d' % (chr(60+(2*i)), (j*2-1))
                                bot2_source = 'W%s%d' % (chr(60+(2*1)), (j*2))

                        match = Match(number=j,
                                      bracket_id=self.id,
                                      bracket_side="B",
                                      round=round_letter,
                                      bot1_source_match=bot1_source,
                                      bot2_source_match=bot2_source)
                        match.put()


                # insert final A-side match
                round_letter = chr(63+(2*(num_rounds+1)))
                bot1_source = 'W%s1' % chr(63+(2*num_rounds))
                bot2_source = 'W%s1' % chr(60+(2*(num_b_rounds+1)))
                match = Match(number=1,
                              bracket_id=self.id,
                              bracket_side="A",
                              round=round_letter,
                              bot1_source_match=bot1_source,
                              bot2_source_match=bot2_source)
                match.put()

            matches_to_update = Match.get_by_bracket_round(self.id, 'A')
            for match in matches_to_update:
                match.check()

        else:  #ROUNDROBIN
            bot_index = 1  # start at 1 because bot0 can't fight bot0 etc
            for bot in bots:
                match_index = 1
                for i in xrange(bot_index, len(bots)):
                    match = Match(number=match_index,
                                  round=chr(64+bot_index),
                                  bracket_id=self.id,
                                  bracket_side="A",
                                  bot1_id=bot.id,
                                  bot2_id=bots[i].id)
                    match.put()
                    match_index += 1
                bot_index += 1

        return True