예제 #1
0
파일: tests.py 프로젝트: fildred13/hamagic
 def test_can_advance_deck(self):
     t = _create_tourney(10,4)
     self.client.get(reverse('tourney:tourney', args=(t.slug,)))
     d = t.decks.order_by('?')[0]
     place(t,2,False,d)
     response = self.client.get(reverse('tourney:tourney', args=(t.slug,)))
     self.assertEqual(response.status_code, 200)
예제 #2
0
def start(tourney):
    print('*****STARTING: '+tourney.name+'*****')
    
    deck_count = len(tourney.decks.all())
    print('Number of decks in tourney: '+str(deck_count))
    
    if deck_count < 4:
        tourney_status = 'Error: too few decks'
        return tourney_status
    elif deck_count > 128:
        tourney_status = 'Error: too many decks'
        return tourney_status
    elif tourney.qr_bracket == "SINGLE" and tourney.bracket == "DOUBLE" and not deck_count >= 8:
        tourney_status = 'Error: require at least 8 decks for a Single-Double Tournament'
        return tourney_status
    elif tourney.qr_bracket == "ROUND_ROBIN" and tourney.bracket == "DOUBLE" and not deck_count >= 8:
        tourney_status = 'Error: require at least 8 decks for a Round Robin-Double Tournament'
        return tourney_status
    elif tourney.qr_bracket == "ROUND_ROBIN" and tourney.bracket == "ROUND_ROBIN" and deck_count < 6:
        tourney_status = 'Error: require at least 6 decks for a Round Robin-Round Robin Tournament'
        return tourney_status
    
#DETERMINE QR BRACKET
    if tourney.qr_bracket == "SINGLE" or tourney.qr_bracket == "DOUBLE":
        if deck_count == 4:
            qr_matches = 2
            qr_loser_matches = 1
            deck_count_after_qr = 2
        elif 8 >= deck_count > 4:
            qr_matches = 4
            qr_loser_matches = 2
            deck_count_after_qr = 4
        elif 16 >= deck_count > 8:
            qr_matches = 8
            qr_loser_matches = 4
            deck_count_after_qr = 8
        elif 32 >= deck_count > 16:
            qr_matches = 16
            qr_loser_matches = 8
            deck_count_after_qr = 16
        elif 64 >= deck_count > 32:
            qr_matches = 32
            qr_loser_matches = 16
            deck_count_after_qr = 32
        elif 128 >= deck_count > 64:
            qr_matches = 64
            qr_loser_matches = 32
            deck_count_after_qr = 64
            
    if tourney.qr_bracket == "ROUND_ROBIN":
        qr_groups = int(ceil(float(deck_count) / tourney.qr_rr_group_size))   
        qr_matches_per_group = (tourney.qr_rr_group_size * (tourney.qr_rr_group_size-1)) / 2
        deck_count_after_qr = qr_groups*tourney.qr_rr_num_advance
        if tourney.bracket == "SINGLE" and deck_count_after_qr < 2:
            tourney_status = 'Error: too few decks to make bracket after round robin play'
            return tourney_status
        if tourney.bracket == "DOUBLE" and deck_count_after_qr < 4:
            tourney_status = 'Error: too few decks to make bracket after round robin play'
            return tourney_status
        
#DETERMINE BRACKET LAYOUT       
    if tourney.bracket == "SINGLE" or tourney.bracket == "DOUBLE":
        rounds = count_rounds(tourney)
        if deck_count_after_qr == 2:
            matches = 1
        elif 4 >= deck_count_after_qr > 2:
            matches = 3
        elif 8 >= deck_count_after_qr > 4:
            matches = 7
        elif 16 >= deck_count_after_qr > 8:
            matches = 15
        elif 32 >= deck_count_after_qr > 16:
            matches = 31
        elif 64 >= deck_count_after_qr > 16:
            matches = 63
        elif 128 >= deck_count_after_qr > 64:
            matches = 127
             
    if tourney.bracket == "ROUND_ROBIN":
        groups = int(ceil(float(deck_count_after_qr) / tourney.rr_group_size))   
        matches_per_group = (tourney.rr_group_size * (tourney.rr_group_size-1)) / 2
        deck_count_after_rr = groups*tourney.rr_num_advance
        if deck_count_after_rr < 2:
            tourney_status = 'Error: too few decks to make bracket after round robin play'
            return tourney_status
        rounds = count_rounds(tourney)
        if deck_count_after_rr == 2:
            matches = 1
        elif 4 >= deck_count_after_rr > 2:
            matches = 3
        elif 8 >= deck_count_after_rr > 4:
            matches = 7
        elif 16 >= deck_count_after_rr > 8:
            matches = 15
        elif 32 >= deck_count_after_rr > 16:
            matches = 31
        elif 64 >= deck_count_after_rr > 16:
            matches = 63
        elif 128 >= deck_count_after_rr > 64:
            matches = 127
        
    ############################
    ######## QR BRACKET ########
    ############################        
    if tourney.qr_bracket == "SINGLE" or tourney.qr_bracket == "DOUBLE":
        #Create QR Match Slots
        for m in range(qr_matches):
            match = Match(tourney = tourney,
                          round = 1,
                          position = m+1,
                          elimination = tourney.qr_elimination,
                          is_qualifier = True,
                          is_active = True
                          )
            match.save()
            
    if tourney.qr_bracket == "ROUND_ROBIN":
        #Create QR Match Slots
        for g in range(qr_groups):
            g = Group(tourney = tourney,
                      round = 1,
                      size = tourney.qr_rr_group_size,
                      is_active = True
                      )
            g.save()
            for m in range(int(qr_matches_per_group)):
                match = Match(tourney = tourney,
                              round = 1,
                              position = m+1,
                              group = g,
                              elimination = tourney.qr_elimination,
                              is_qualifier = True,
                              is_active = True
                              )
                match.save() 
            
    #Populate QR Match Slots
    print('Populating QR Match Slots')
    deck_list = tourney.decks.all()
    user_list = []
    for d in deck_list:
        user_list.append(d.user)
    counted_user_list = Counter(user_list)
    # The old way of organizing the user list, in case the new one breaks.  Can delete in a few versions
    # organized_user_list = sorted(counted_user_list, key=lambda u: (-counted_user_list[u], u))
    organized_user_list = sorted(counted_user_list, key=lambda u: -counted_user_list[1])
    for u in organized_user_list:
        user_deck_list = tourney.decks.filter(user=u)
        if tourney.qr_bracket == "ROUND_ROBIN":
            for d in user_deck_list:
                #hopefully pick a group where you don't already have a deck
                filtered_groups = Group.objects.filter(tourney=tourney)
                for g in filtered_groups:
                    if g.size == len(g.decks.all()):
                        filtered_groups = filtered_groups.exclude(id=g.id)
                    else:
                        for group_deck in g.decks.all():
                            if d.user == group_deck.user:
                                filtered_groups = filtered_groups.exclude(id=g.id)
                                break
                if not filtered_groups:
                    #if every group has at least one of his deck, there is nothing more we can do.
                    filtered_groups = Group.objects.filter(tourney=tourney)
                #now we know what groups would be good for this deck, so go ahead and place him in one            
                placed = False
                while placed == False:        
                    possible_group = filtered_groups.order_by('?')[:1].get()
                    if possible_group.size > len(possible_group.decks.all()):
                        gs = GroupStats(deck=d, 
                                        group=possible_group,
                                        points = 0,
                                        margin = 0)
                        gs.save()
                        placed = True
                match_count_for_deck = tourney.qr_rr_group_size-1
                empty_matches_allowed = match_count_for_deck-len(possible_group.decks.all())+1
                for i in range(match_count_for_deck):
                    place(tourney,1,False,d,possible_group,empty_matches_allowed)      
        else:
            for d in user_deck_list:
                place(tourney,1,False,d)
            
    if tourney.qr_bracket == "DOUBLE":
        #Create QR Loser Match Slots
        for m in range(qr_loser_matches):
            match = Match(tourney = tourney,
                      round = 1,
                      position = m+1,
                      elimination = tourney.qr_elimination,
                      is_qualifier = True,
                      is_active = False,
                      is_loser = True
                      )
            match.save()               
                
    ##################################
    ############  BRACKET ############
    ##################################            
    if tourney.bracket == "SINGLE" or tourney.bracket == "DOUBLE":         
        #Create Remaining Rounds Match Slots
        print("Bracket is " + str(tourney.bracket) + ". Creating Matches...")
        print("matches = " + str(matches))
        for r in range(rounds-1):
            print("r = " + str(r))
            for m in range(int(ceil(matches/(2.0**(r+1))))):
                print("m = " + str(m))
                match = Match(tourney = tourney,
                          round = r+2,
                          position = m+1,
                          elimination = tourney.elimination
                          )
                if tourney.bracket == "SINGLE":
                    if match.round == rounds:
                        match.is_final = True
                        match.elimination = tourney.final_elimination
                    if match.round == rounds-1:
                        match.is_semi = True
                        match.elimination = tourney.semi_elimination
                if tourney.bracket == "DOUBLE":
                    if match.round == rounds:
                        match.is_semi = True
                        match.elimination = tourney.semi_elimination
                match.save()
                
    if tourney.bracket == "ROUND_ROBIN":
        #Create Round Robin Round
        for g in range(groups):
            g = Group(tourney = tourney,
                      round = 2,
                      size = tourney.rr_group_size,
                      is_active = True
                      )
            g.save()
            for m in range(int(matches_per_group)):
                match = Match(tourney = tourney,
                              round = 2,
                              position = m+1,
                              group = g,
                              elimination = tourney.elimination,
                              is_active = False
                              )
                if match.round == rounds-1:
                    match.is_semi = True
                    match.elimination = tourney.semi_elimination
                match.save() 
                 
        #Create Remaining Rounds Match Slots
        for r in range(rounds-2):
            for m in range(int(ceil(matches/(2.0**(r+1))))):
                match = Match(tourney = tourney,
                          round = r+3,
                          position = m+1,
                          elimination = tourney.elimination
                          )
                if match.round == rounds:
                    match.is_final = True
                    match.elimination = tourney.final_elimination
                if match.round == rounds-1:
                    match.is_semi = True
                    match.elimination = tourney.semi_elimination
                match.save()
       
    if tourney.bracket == "DOUBLE":
        #Create Remaining Rounds Loser Match Slots
        loser_rounds = count_loser_rounds(tourney)
                
        for r in range(loser_rounds):
            this_round = r+2      
            for m in range(loser_matches_in_round(tourney.qr_bracket,
                                                  deck_count_after_qr,
                                                  this_round)
                           ):
                match = Match(tourney = tourney,
                              round = this_round,
                              position = m+1,
                              elimination = tourney.elimination,
                              is_loser = True
                              )
                if match.round == loser_rounds+1:
                    match.is_final = True
                    match.elimination = tourney.final_elimination
                if match.round == loser_rounds:
                    match.is_semi = True
                    match.elimination = tourney.semi_elimination
                match.save()
    
    ##################################
    ########### UNIVERSAL ############
    ##################################
    #after all user decks are placed, assign byes.
    assign_byes(tourney,1)
    tourney.has_started = True
    tourney.save()    
    tourney_status = 'active'                 
    return tourney_status
        
        
        
        
예제 #3
0
파일: views.py 프로젝트: fildred13/hamagic
def submit_results(request,
                   tourney_slug,
                   ):
    tourney = Tourney.objects.get(slug=tourney_slug)
    #make sure they didn't leave anything blank:
    if 'first_deck_wins' in request.POST and 'second_deck_wins' in request.POST:
        try:
            first_deck_wins = int(request.POST['first_deck_wins'])
            second_deck_wins = int(request.POST['second_deck_wins'])
        #if they entered text or something, tell them they are a dingus:
        except ValueError:
            messages.error(request, 'Error: Please enter valid values for submission.') 
            return HttpResponseRedirect(reverse('tourney:tourney', args=(tourney_slug,)))
        #make sure there are no negative numbers
        if first_deck_wins < 0 or second_deck_wins < 0:
            messages.error(request, 'Error: No negative game wins allowed') 
            return HttpResponseRedirect(reverse('tourney:tourney', args=(tourney_slug,)))
        
        #MAKE SURE THE MATCH WASN'T ALREADY SUBMITTED
        match = Match.objects.get(id=request.POST['match_id'])
        if match.is_complete:
            messages.error(request, 'Error: Match results already submitted') 
            return HttpResponseRedirect(reverse('tourney:tourney', args=(tourney_slug,)))
        
        #validate that they entered the right number of wins for the elimination type
        if match.elimination == 'SINGLE':
            elim_type = 'single elimination'
            max_wins = 1
            wins_for_winner = 1
        elif match.elimination == 'BEST_THREE':
            elim_type = 'best of three'
            max_wins = 3
            wins_for_winner = 2
        elif match.elimination == 'BEST_FIVE':
            elim_type = 'best of five'
            max_wins = 5
            wins_for_winner = 3
        elif match.elimination == 'BEST_SEVEN':
            elim_type = 'best of seven'
            max_wins = 7
            wins_for_winner = 4
            
        if first_deck_wins + second_deck_wins > max_wins:
            messages.error(request, 'Error: The submitted match is '+elim_type+', yet the total games added up to more than '+str(max_wins)+'.') 
            return HttpResponseRedirect(reverse('tourney:tourney', args=(tourney_slug,)))
        elif first_deck_wins < wins_for_winner and second_deck_wins < wins_for_winner:
            messages.error(request, 'Error: The submitted match is '+elim_type+', yet neither player had at least '+str(wins_for_winner)+' wins.') 
            return HttpResponseRedirect(reverse('tourney:tourney', args=(tourney_slug,)))
        elif first_deck_wins > wins_for_winner or second_deck_wins > wins_for_winner:
            messages.error(request, 'Error: The submitted match is '+elim_type+', yet the winner had too many wins. The maximum number of game wins the winner should have is: '+str(wins_for_winner)+'.') 
            return HttpResponseRedirect(reverse('tourney:tourney', args=(tourney_slug,)))
        ##### VALIDATION COMPLETE #####
        
        
        #Start assigning all the variables and gathering neccessary data        
        #assume the simplest case
        next_round = match.round + 1
        #add caveats for double bracket semi finals
        if tourney.bracket == "DOUBLE" and match.is_semi == True:
            final_round = Match.objects.get(tourney=tourney, is_final=True).round
        
        #determine if it is a self-match
        is_self_match = False
        if match.first_deck.user == match.second_deck.user:
            is_self_match = True
             
        #determine loser round
        if not match.is_final:
            if not match.is_loser:
                if tourney.bracket == "DOUBLE":
                    loser_round = match.round
        #determine if this is a loser round
        is_loser_round = False
        if match.is_loser:
            is_loser_round = True
        
        #actually submit the match and process
        if first_deck_wins > second_deck_wins:   
            winner = match.first_deck
            loser = match.second_deck
            winners_wins = first_deck_wins
            losers_wins = second_deck_wins
            
            if not is_self_match:
                winner.game_wins += first_deck_wins
                winner.game_losses += second_deck_wins
                loser.game_wins += second_deck_wins
                loser.game_losses += first_deck_wins
        else:
            winner = match.second_deck
            loser = match.first_deck
            winners_wins = second_deck_wins
            losers_wins = first_deck_wins
            
            if not is_self_match:
                winner.game_wins += second_deck_wins
                winner.game_losses += first_deck_wins
                loser.game_wins += first_deck_wins
                loser.game_losses += second_deck_wins
        
        if not is_self_match:    
            winner.match_wins += 1
            loser.match_losses += 1
        
        winner.save()
        loser.save()
         
        #disable current match
        match.first_deck_wins = first_deck_wins
        match.second_deck_wins = second_deck_wins
        match.is_active = False
        match.is_complete = True
        match.date_completed = timezone.now()
        match.save()
        
        if match.is_final:
            winner.tourney_wins += 1
            winner.save()
            if not is_self_match:
                loser.tourney_losses += 1
                loser.save()
            if is_self_match:
                loser.tourney_bow_outs += 1
                loser.save()
            tourney.winner = winner.user
            tourney.is_finished = True
            tourney.finished_date = timezone.now()
            tourney.save()
            tourney.winning_deck.add(winner)
        else:
            #place deck/s wherever they belong
            if match.round == 1:
                bracket_type = tourney.qr_bracket
            elif match.round > 2 and tourney.bracket == "ROUND_ROBIN":
                bracket_type = "SINGLE"
            else:
                bracket_type = tourney.bracket
                    
            if bracket_type == "SINGLE":
                if match.round == 1 and tourney.bracket == "ROUND_ROBIN":
                    #place according to group rules
                    match_count_for_deck = tourney.rr_group_size-1
                    groups = Group.objects.filter(tourney=tourney, round=2)
                    for g in groups:
                        if g.size == len(g.decks.all()):
                            groups = groups.exclude(id=g.id)
                        else:
                            for group_deck in g.decks.all():
                                if winner.user == group_deck.user:
                                    groups = groups.exclude(id=g.id)
                                    break
                    if not groups:
                        #if every group has at least one of his deck, there is nothing more we can do.
                        groups = Group.objects.filter(tourney=tourney, round=2)
                    placed = False
                    while placed == False:
                        possible_group = groups.order_by('?')[:1].get()
                        placeable = False
                        if possible_group.decks:
                            if possible_group.size > len(possible_group.decks.all()):
                                placeable = True
                        elif not possible_group.decks:
                            placeable = True
                        if placeable == True:
                            gs = GroupStats(deck=winner, 
                                            group=possible_group,
                                            points = 0,
                                            margin = 0)
                            gs.save()
                            placed = True
                    for i in range(match_count_for_deck):
                        empty_matches_allowed = match_count_for_deck-len(possible_group.decks.all())+1
                        place(tourney, 2, False, winner, possible_group, empty_matches_allowed)
                else:
                    place(tourney,next_round,False,winner)
                if not is_self_match:
                    loser.tourney_losses += 1
                    loser.save()
                if is_self_match:
                    loser.tourney_bow_outs += 1
                    loser.save()
            elif bracket_type == "DOUBLE":
                if not is_loser_round:
                    if match.is_semi:
                        place(tourney,final_round,True,winner)   
                    else: 
                        place(tourney,next_round,False,winner)
                    place(tourney,loser_round,True,loser)
                if is_loser_round:
                    place(tourney,next_round,True,winner)
                    if not is_self_match:
                        loser.tourney_losses += 1
                        loser.save()
                    if is_self_match:
                        loser.tourney_bow_outs += 1
                        loser.save()
            elif bracket_type == "ROUND_ROBIN":
                #Increment winner's information in the GroupStats
                winners_stats = GroupStats.objects.get(deck=winner, group=match.group)
                winners_stats.points += 1
                winners_stats.margin += (winners_wins - losers_wins)
                winners_stats.save()
                #increment loser's margin in the GroupStats
                losers_stats = GroupStats.objects.get(deck=loser, group=match.group)
                losers_stats.margin -= (winners_wins - losers_wins)
                losers_stats.save()
                
                #Check if the round is complete and, if it is, determine the winners
                if not Match.objects.filter(tourney=tourney,
                                            round=match.round,
                                            group=match.group,
                                            is_complete=False):
                    
                    if match.round == 1:
                        num_winners = tourney.qr_rr_num_advance
                    else:
                        num_winners = tourney.rr_num_advance
                    group_winners = GroupStats.objects.filter(group=match.group).order_by('-points','-margin','?')[:num_winners]
                    match_count_for_deck = tourney.rr_group_size-1
                    for w in group_winners:
                        if match.round == 1 and tourney.bracket == "ROUND_ROBIN":
                            #hopefully pick a group where you don't already have a deck
                            groups = Group.objects.filter(tourney=tourney, round=2)
                            for g in groups:
                                if g.size == len(g.decks.all()):
                                    groups = groups.exclude(id=g.id)
                                else:
                                    for group_deck in g.decks.all():
                                        if w.deck.user == group_deck.user:
                                            groups = groups.exclude(id=g.id)
                                            break
                            if not groups:
                                #if every group has at least one of his deck, there is nothing more we can do.
                                groups = Group.objects.filter(tourney=tourney, round=2)
                            placed = False
                            while placed == False:
                                possible_group = groups.order_by('?')[:1].get()
                                placeable = False
                                if possible_group.decks:
                                    if possible_group.size > len(possible_group.decks.all()):
                                        placeable = True
                                elif not possible_group.decks:
                                    placeable = True
                                if placeable == True:
                                    gs = GroupStats(deck=w.deck, 
                                                    group=possible_group,
                                                    points = 0,
                                                    margin = 0)
                                    gs.save()
                                    placed = True
                            for i in range(match_count_for_deck):
                                empty_matches_allowed = match_count_for_deck-len(possible_group.decks.all())+1
                                place(tourney,next_round,False,w.deck,possible_group,empty_matches_allowed)
                        else:
                            place(tourney,next_round,False,w.deck)
                            
            #lastly, determine and assign byes across the tournament    
            determine_byes(tourney)
            
        
    else:
        messages.error(request, 'Error: Please enter valid values for submission.')
        return HttpResponseRedirect(reverse('tourney:tourney', args=(tourney_slug,)))
    
    return HttpResponseRedirect(reverse('tourney:tourney', 
                                        args=(tourney_slug,)))