File size: 10,198 Bytes
4e5bc49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Apr 20 02:58:47 2019

@author: ManishChalana
"""

import numpy as np
import collections
import pandas as pd



class Team:
    def __init__(self, players, teams):
        self.players = players
        self.team1 = teams[0]
        self.team2 = teams[1]
        numPlayers = collections.Counter([player['team'] for player in self.players])
        assert list(numPlayers.values())==[11,11],  "Invalid combination! Number of players in " + self.team1 + ": " + str(numPlayers[self.team1]) + "," + self.team2 + ": " + str(numPlayers[self.team2])
        
        
class Dream11(Team):
    
    def __init__(self, players, teams):
        super().__init__(players, teams)
        self.teamParams = {'min':4, 'max':7}
        self.maxPoints = 100
        self.combinations = [[1,3,2,5], [1,3,3,4], [1,4,1,5], [1,4,2,4], [1,4,3,3], [1,5,1,4], [1,5,2,3]]
#        self.combinationsProb = [0.14]*6 + [0.16] 
#        self.combinationsProb = [0.1,0.2,0.05,0.2,0.3,0.05,0.1]
        self.playerNames = [p['name'] for p in players]
        self.playerPointMap = {p['name']:p['points'] for p in self.players}
        self.playerTeamMap = {p['name']:p['team'] for p in self.players}
        self.playerTypeMap = {p['name']:p['type'] for p in self.players}
        self.playerTypeCount = collections.Counter(self.playerTypeMap.values())
                
    @staticmethod
    def getSoftmaxProbabilities(points, toneDownMultiplier=1):
        if len(points) == 0:
            return []
        points = [toneDownMultiplier*point for point in points]
        denom = np.sum([np.exp(point) for point in points])
        softMax = [np.exp(point)/denom for point in points]
        return softMax
    
    
    def sample(self, players, req): 
        numStars = np.sum([p['star'] for p in players])
        
        availableStars = [p['name'] for p in players if p['star']==1]
        availableStarsPoints = [p['points'] for p in players if p['star']==1]
        availableStarsSoftMax = Dream11.getSoftmaxProbabilities(availableStarsPoints)
        
        availableNonStars = [p['name'] for p in players if not(p['star']==1)]
        availableNonStarsPoints = [p['points'] for p in players if not(p['star']==1)]
        availableNonStarsSoftMax = Dream11.getSoftmaxProbabilities(availableNonStarsPoints)
    
        if numStars >= req:
            return ([] if len(availableStars)==0 else list(np.random.choice(availableStars, size = req, p=availableStarsSoftMax, replace=False)))
        else:
            return availableStars + list(np.random.choice(availableNonStars, size = req - numStars, p=availableNonStarsSoftMax, replace=False))      
    
    def calculateTeamVector(self, team):
        teamVector = [player['points'] if (player['name'] in team) else 0 for player in self.players]
        return teamVector

    def checkUniqueTeamCriteria(self, sampledTeam, selectedTeams):
        return (np.sum([set(team)==set(sampledTeam) for team in selectedTeams]) == 0)
    
    def checkMinPlayersTeamCriteria(self, teamDemography):
        return (teamDemography[self.team1]>=self.teamParams['min']) and (teamDemography[self.team2]>=self.teamParams['min']) 
    
    def checkMaxPlayersTeamCriteria(self, teamDemography):
        return (teamDemography[self.team1]<=self.teamParams['max']) and (teamDemography[self.team2]<=self.teamParams['max'])
    
    def checkMaxTeamPointsCriteria(self, sampledTeam):
        totalPoints = np.sum([self.playerPointMap[player] for player in sampledTeam])
        return (totalPoints <= self.maxPoints)
        
    def checkSimilarityIndexCriteria(self, sampledTeam, selectedTeams, selected, thresh=24):
        
        similarityIndexCriteria = False
        similarityIndices = []
        
        if selected>0:
            similarityIndices = [np.sqrt(np.sum(np.square(np.array(self.calculateTeamVector(sampledTeam)) - np.array(self.calculateTeamVector(team))))) for team in selectedTeams]
            if np.min(similarityIndices) > thresh:
                similarityIndexCriteria = True
        else:
            similarityIndexCriteria = True
        return similarityIndices, similarityIndexCriteria
    
    def chooseCaptain(self, sampledTeam, captain):
        [c, vc] = ['', '']
        if captain:
            sampledTeamSoftmax = [self.playerPointMap[name] for name in sampledTeam]
            [c, vc] = np.random.choice(sampledTeam, size=2, replace=False, p=Dream11.getSoftmaxProbabilities(sampledTeamSoftmax, toneDownMultiplier=0.75))   
            
        return [c, vc]

    def updateSelectedTeams(self, sampledTeam, selectedTeams, selected, captain):
        #Finding the numbers of wks, bats, ar and bowls in the sampled team
        teamDemography = collections.Counter([self.playerTeamMap[player] for player in sampledTeam])
        
        # Finding the total number of points spent in selecting the sampled team and ensuring that it is less than maximum available points
        pointsCriteria = self.checkMaxTeamPointsCriteria(sampledTeam)
        
        # Ensuring that sampled team is not same as one of the previously selected teams
        uniqueTeamCriteria = self.checkUniqueTeamCriteria(sampledTeam, selectedTeams)
        
        # Making sure that minimum required players are selected in sampled team from each of the two parent teams
        minPlayersCriteria = self.checkMinPlayersTeamCriteria(teamDemography)
        
        # Making sure that maximum required players are selected in sampled team from each of the two parent teams
        maxPlayersCriteria = self.checkMaxPlayersTeamCriteria(teamDemography)
        
        # Calculating the similarity index of the sampled team with the already selected teams to ensure dissimilarity
        similarityIndices, similarityIndexCriteria = self.checkSimilarityIndexCriteria(sampledTeam, selectedTeams, selected)
        
        # Choosing a captain and vice captain
        [c, vc] = self.chooseCaptain(sampledTeam, captain)
        
        if  pointsCriteria and uniqueTeamCriteria and minPlayersCriteria and maxPlayersCriteria and similarityIndexCriteria:                
            
            # When all criterias are fulfilled by the team, append the sampled team to list of already selected teams
            selectedTeams.append(sampledTeam)                                
            selected = selected + 1
            
            self.printTeamDetails(sampledTeam, selected, c, vc, similarityIndices)
            
            # Finding the attributes of the selected team
            
        return selectedTeams, selected
    
    
    def printTeamDetails(self, sampledTeam, index, c, vc, similarityIndices):
        
        selectedPlayersNames = [name.upper() for name in sampledTeam]
        selectedPlayersPoints = [[p for p in self.players if p['name']==name][0]['points'] for name in sampledTeam]
        selectedPlayersTeams = [[p for p in self.players if p['name']==name][0]['team'].upper() for name in sampledTeam]
        selectedPlayersTypes = [[p for p in self.players if p['name']==name][0]['type'] for name in sampledTeam]
        selectedPlayersCVC = ['c' if name==c else 'vc' if name==vc else ' ' for name in sampledTeam ]
        selectedPlayersTypesCounter = collections.Counter(selectedPlayersTypes)
        selectedPlayersTeamsCounter = collections.Counter(selectedPlayersTeams)
            
        # Defining a dataframe containing the details of sampled team
        teamDf = pd.DataFrame({'Player': selectedPlayersNames, 'C/VC': selectedPlayersCVC, 'Points':selectedPlayersPoints, 'Team':selectedPlayersTeams, 'Type':selectedPlayersTypes}, index=range(1,12))[['Player', 'C/VC', 'Team', 'Type', 'Points']]
        teamDf = pd.concat([teamDf[teamDf['Type']==playType].sort_values(['Points'], ascending=False) for playType in ['wk', 'bat', 'ar', 'bowl']])
        teamDf.index = range(1,12)
            
        # Printing the team on console
        print("------------ Team", index, "------------\n")
        print(teamDf)
        print("\nTotal points invested:", np.sum(teamDf['Points']))
        print("Wicket-keepers:", selectedPlayersTypesCounter['wk'], ", Batsman:", selectedPlayersTypesCounter['bat'], ", All-rounders:", selectedPlayersTypesCounter['ar'], " Bowlers:", selectedPlayersTypesCounter['bowl'])
        print(self.team1.upper(), ":", selectedPlayersTeamsCounter[self.team1.upper()], self.team2.upper(), ":", selectedPlayersTeamsCounter[self.team2.upper()])
        print("Similarity indices:", similarityIndices)
        print('\n')
        
    
    
    
    def generateTeams(self, numTeams, captain=False):
        selectedTeams = []
        selected = 0
        
        while selected < numTeams:
            # Choose a random combination of number of wicket-keepers, batsman, all-rounders and bowlers
            while True:
                [numWks, numBats, numArs, numBowls] = self.combinations[np.random.choice(len(self.combinations), size=1)[0]]
                if (numWks <= self.playerTypeCount['wk']) and (numBats <=self.playerTypeCount['bat']) and (numArs <=self.playerTypeCount['ar']) and (numBowls<=self.playerTypeCount['bowl']):
                    break
            
            # Choose Keepers
            wks = self.sample([p for p in self.players if p['type']=='wk'], numWks)
            
            # Choose batsman
            bats = self.sample([p for p in self.players if p['type']=='bat'], numBats)
            
            # Choose all-rounders
            ars = self.sample([p for p in self.players if p['type']=='ar'], numArs)
            
            # Choose bowlers
            bowls = self.sample([p for p in self.players if p['type']=='bowl'], numBowls)
            
            # Chosen team
            sampledTeam = wks + bats + ars + bowls
            
            # Update selected teams list based on whether the sampled team fulfills all eligibility criteria
            selectedTeams, selected = self.updateSelectedTeams(sampledTeam, selectedTeams, selected, captain)