def test_oneSubgraph(self): playedGames = [ Game(MatchUp(Team("a", "", 0), Team("b", "", 1))), Game(MatchUp(Team("c", "", 2), Team("d", "", 3))), Game(MatchUp(Team("e", "", 4), Team("f", "", 5))), Game(MatchUp(Team("a", "", 0), Team("c", "", 2))), Game(MatchUp(Team("d", "", 3), Team("f", "", 5))), Game(MatchUp(Team("e", "", 4), Team("b", "", 1))) ] futureGames = [ Game(MatchUp(Team("a", "", 0), Team("f", "", 5))), Game(MatchUp(Team("b", "", 1), Team("c", "", 2))), Game(MatchUp(Team("d", "", 3), Team("e", "", 4))) ] teams = [ Team("a", "", 0), Team("b", "", 1), Team("c", "", 2), Team("d", "", 3), Team("e", "", 4), Team("f", "", 5) ] self.assertEqual( GraphRating.rateFutureGames(playedGames, futureGames, teams), 0) for i in range(0, 10): shuffle(playedGames) shuffle(futureGames) shuffle(teams) self.assertEqual( GraphRating.rateFutureGames(playedGames, futureGames, teams), 0)
def test_calculateTotalError(self): currentRanking = [Team("a", "", 0), Team("b", "", 0), Team("c", "", 0), Team("d", "", 0)] results = [Game(MatchUp(Team("a", "", 0), Team("b", "", 0)), Result(0, 1, 2), None), Game(MatchUp(Team("c", "", 0), Team("d", "", 0)), Result(0, 1, 2), None)] mirroredResults = [Game(MatchUp(Team("b", "", 0), Team("a", "", 0)), Result(0, 2, 1), None), Game(MatchUp(Team("d", "", 0), Team("c", "", 0)), Result(0, 2, 1), None)] self.assertEqual(RankingGenerator._calculateTotalError(currentRanking, results), RankingGenerator._calculateTotalError(currentRanking, mirroredResults))
def generateMatchUps(self, debug=False) -> List[Game]: """ Generate new matchups for given ranking and played games There will be no repetition of already played matchups. Under this condition, the matchup w/ minimal distance in the ranking table is sought. """ # start recursive generation of matchups: all teams to distribute, no matchups, no loss yet self._genMatchUpRecursive(list(range(0, len(self.teams))), [], 0) # convert back to [MatchUp] (w/ str description) # select best matchup considering the connection ratings too bestFullyConnectedMatchUp = [] bestWeightedLoss = sys.float_info.max for pair in self._bestMatchUpManager.bestMatchUps(): loss = pair[0] goodMatchUpList = pair[1] convertedMatchUp = [] for matchUpInt in goodMatchUpList: matchUp = Game( MatchUp(self.ranking[matchUpInt.first], self.ranking[matchUpInt.second]), None, None) convertedMatchUp.append(matchUp) rating = rateFutureGames(self.playedGames, convertedMatchUp, self.teams) * loss if rating < bestWeightedLoss: bestWeightedLoss = rating bestFullyConnectedMatchUp = convertedMatchUp # debug messages if debug: for matchUp in bestFullyConnectedMatchUp: print(matchUp.matchup.first.name, ":", matchUp.matchup.second.name) print("Distance in ranking table: loss=", self.bestLoss) assert len(bestFullyConnectedMatchUp) > 0 return bestFullyConnectedMatchUp
def genResult(game: Game) -> Game: # make results a bit more realistic by adding a random offset baseOffset = abs(np.random.normal(0, 4)) baseOffset = min(max(baseOffset, 4), 0) paramsA = teamParams[game.matchup.first] paramsB = teamParams[game.matchup.second] resultA = genOneResult(baseOffset + paramsA[muPos], paramsA[sigmaUpPos], paramsA[sigmaDownPos]) resultB = genOneResult(baseOffset + paramsB[muPos], paramsB[sigmaUpPos], paramsB[sigmaDownPos]) game.result = Result(0, round(resultA), round(resultB)) return game
def test_twoSubgraphsAndLongNames(self): playedGames = [ Game(MatchUp(Team("awww", "", 0), Team("bxxx", "", 0))), Game(MatchUp(Team("cyyy", "", 0), Team("dzzz", "", 0))) ] futureGames = [ Game(MatchUp(Team("bxxx", "", 0), Team("cyyy", "", 0))), Game(MatchUp(Team("awww", "", 0), Team("dzzz", "", 0))) ] teams = [ Team("awww", "", 0), Team("bxxx", "", 0), Team("cyyy", "", 0), Team("dzzz", "", 0) ] self.assertEqual( GraphRating.rateFutureGames(playedGames, futureGames, teams), 0) for i in range(0, 5): shuffle(playedGames) shuffle(futureGames) shuffle(teams) self.assertEqual( GraphRating.rateFutureGames(playedGames, futureGames, teams), 0)
def test_insertGame(self): print("########## testing inserting next game ############") teams = self.instance.getListOfAllTeams( divisionId_Swissdraw) # get a list of teams result = Result(-1, 0, 0, 0, 0) # set a result slots = self.instance.getListOfSlotsOfUpcomingRound( divisionId_Swissdraw) # get upcompiung slots if len(slots) != 0: matchup = MatchUp( teams[0], teams[1] ) # set up matchups with 2 (random, the first 2) teams from all teams game: Game = Game( matchup, result, slots[0] ) # set up game with matchup, result, and the first slot self.instance.insertNextGame( game, GameState.COMPLETED, 1 ) # insert nextgames in debug mode (no real insertion in db). don' use second parameter for productive system else: print("no available Slots found")
def update(forceDBToBeUsed: str = "", finalRoundState: RoundState = RoundState.FINAL_PREDICTION): api = DataAPI(forceDBToBeUsed=forceDBToBeUsed) # check if optimizations need to be done stillRoundsToBeOptimized = False for division in api.getSwissDrawDivisions(): if api.getRoundNumberToBeOptimized(division.divisionId) is not None: stillRoundsToBeOptimized = True break # TODO remove this, only a hack for MC19 for division in api.getSwissDrawDivisions(): divisionId = division.divisionId if api.getRoundNumberToBeOptimized(divisionId) is None: teams = api.getListOfAllTeams(divisionId) gamesRelevantForRanking = api.getListOfGames( gameStates=[GameState.COMPLETED, GameState.RUNNING], divisionId=divisionId) ranking = generateNewRanking(teams, gamesRelevantForRanking) roundNumber = 4 api.insertRanking(ranking, roundNumber, divisionId) #if not stillRoundsToBeOptimized: # return False #TODO remove this, only a hack for MC19 if not stillRoundsToBeOptimized: return True for division in api.getSwissDrawDivisions(): divisionId = division.divisionId # create ranking teams = api.getListOfAllTeams(divisionId) gamesRelevantForRanking = api.getListOfGames( gameStates=[GameState.COMPLETED, GameState.RUNNING], divisionId=divisionId) ranking = generateNewRanking(teams, gamesRelevantForRanking) roundNumber = api.getRoundNumberToBeOptimized(divisionId) if roundNumber is None: continue api.insertRanking(ranking, roundNumber, divisionId) # create matchups allGames = api.getListOfGames(gameStates=[ GameState.COMPLETED, GameState.RUNNING, GameState.NOT_YET_STARTED ], divisionId=divisionId) matchUpGenerator = MatchUpGenerator(ranking, allGames) futureMatchUps = matchUpGenerator.generateMatchUps(True) # schedule games futureSlots = [] for slot in api.getListOfSlotsOfUpcomingRound(divisionId=divisionId): futureSlots.append(Game(None, None, slot)) if len(futureSlots) == 0: _setRoundState(roundNumber, divisionId, api, finalRoundState) continue #TODO do something sensible if there are no games to be scheduled scheduler = SwissGameScheduler() nextGames = scheduler.maximizeGain(allGames, futureSlots, futureMatchUps) # update games in DB gameState = GameState.NOT_YET_STARTED api.insertNextGames(nextGames, gameState) _setRoundState(roundNumber, divisionId, api, finalRoundState) return True
Team("Caracals", "", 0), Team("Drehst'n Deckel", "", 0), Team("Airpussies", "", 0), Team("Cakes", "", 0), Team("RotPot", "", 0), Team("Paradisco", "", 0), ] dataDir = "./testData/fourth_round" # read results from CSV into list[Result] results = [] resultsFile = open(join(dataDir, "results.csv")) resultsCsv = csv.reader(resultsFile, delimiter=';') for row in resultsCsv: results.append( Game(MatchUp(Team(row[0], "", 0), Team(row[1], "", 0)), Result(0, int(row[2]), int(row[3])), None)) resultsFile.close() # read previous matches from CSV into list[Match] previousMatches = [] previousMatchesFile = open(join(dataDir, "previousMatches.csv")) previousMatchesCsv = csv.reader(previousMatchesFile, delimiter=';') for row in previousMatchesCsv: previousMatches.append( Game(MatchUp(Team(row[0], "", 0), Team(row[1], "", 0)), None, Slot(hhmmTom(row[2]), hhmmTom(row[3]), int(row[4]), 0, 0))) previousMatchesFile.close() # generate current ranking (debug=True) # XXX currently expensive t0 = time()
def test_emptyLists3(self): playedGames = [Game()] futureGames = [Game()] teams = [] self.assertRaises(Exception, GraphRating.rateFutureGames, playedGames, futureGames, teams)
def test_threeSubgraphsLarge(self): playedGames = [ # subgraph0 Game(MatchUp(Team("a", "", 0), Team("b", "", 0))), Game(MatchUp(Team("a", "", 0), Team("f", "", 0))), Game(MatchUp(Team("b", "", 0), Team("c", "", 0))), Game(MatchUp(Team("c", "", 0), Team("d", "", 0))), Game(MatchUp(Team("d", "", 0), Team("e", "", 0))), Game(MatchUp(Team("e", "", 0), Team("f", "", 0))), # subgraph1 Game(MatchUp(Team("m", "", 0), Team("n", "", 0))), Game(MatchUp(Team("m", "", 0), Team("k", "", 0))), Game(MatchUp(Team("n", "", 0), Team("l", "", 0))), Game(MatchUp(Team("l", "", 0), Team("k", "", 0))), # subgraph2 Game(MatchUp(Team("j", "", 0), Team("g", "", 0))), Game(MatchUp(Team("j", "", 0), Team("i", "", 0))), Game(MatchUp(Team("g", "", 0), Team("h", "", 0))), Game(MatchUp(Team("h", "", 0), Team("i", "", 0))) ] futureGames = [ Game(MatchUp(Team("f", "", 0), Team("g", "", 0))), Game(MatchUp(Team("m", "", 0), Team("a", "", 0))) ] teams = [ "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n" ] teams = [ Team("a", "", 0), Team("b", "", 0), Team("c", "", 0), Team("d", "", 0), Team("e", "", 0), Team("f", "", 0), Team("g", "", 0), Team("h", "", 0), Team("i", "", 0), Team("j", "", 0), Team("k", "", 0), Team("l", "", 0), Team("m", "", 0), Team("n", "", 0) ] self.assertAlmostEqual( GraphRating.rateFutureGames(playedGames, futureGames, teams), 0.666666, 5) for i in range(0, 10): shuffle(playedGames) shuffle(futureGames) shuffle(teams) self.assertAlmostEqual( GraphRating.rateFutureGames(playedGames, futureGames, teams), 0.666666, 5)
def evalFunction(numRounds): ranking = [ Team("a", "", 0), Team("b", "", 1), Team("c", "", 2), Team("d", "", 3), Team("e", "", 4), Team("f", "", 5), Team("g", "", 6), Team("h", "", 7), Team("i", "", 8), Team("j", "", 9), Team("k", "", 10), Team("l", "", 11), Team("m", "", 12), Team("n", "", 13), Team("o", "", 14), Team("p", "", 15), ] futureSlots = [ [ Game(None, None, Slot(0, 35, hall1, 0, 0)), Game(None, None, Slot(0, 35, hall2, 1, 0)), Game(None, None, Slot(0, 35, hall3, 2, 0)), Game(None, None, Slot(40, 75, hall1, 3, 0)), Game(None, None, Slot(40, 75, hall2, 4, 0)), Game(None, None, Slot(40, 75, hall3, 5, 0)), Game(None, None, Slot(80, 115, hall1, 6, 0)), Game(None, None, Slot(80, 115, hall2, 7, 0)), ], [ Game(None, None, Slot(120, 155, hall1, 8, 1)), Game(None, None, Slot(120, 155, hall2, 9, 1)), Game(None, None, Slot(120, 155, hall3, 10, 1)), Game(None, None, Slot(160, 195, hall1, 11, 1)), Game(None, None, Slot(160, 195, hall2, 12, 1)), Game(None, None, Slot(160, 195, hall3, 13, 1)), Game(None, None, Slot(200, 235, hall1, 14, 1)), Game(None, None, Slot(200, 235, hall3, 15, 1)), ], [ Game(None, None, Slot(240, 275, hall1, 16, 2)), Game(None, None, Slot(240, 275, hall2, 17, 2)), Game(None, None, Slot(240, 275, hall3, 18, 2)), Game(None, None, Slot(280, 315, hall1, 19, 2)), Game(None, None, Slot(280, 315, hall2, 20, 2)), Game(None, None, Slot(280, 315, hall3, 21, 2)), Game(None, None, Slot(320, 355, hall2, 22, 2)), Game(None, None, Slot(320, 355, hall3, 23, 2)), ], [ Game(None, None, Slot(360, 395, hall1, 24, 3)), Game(None, None, Slot(360, 395, hall2, 25, 3)), Game(None, None, Slot(360, 395, hall3, 26, 3)), Game(None, None, Slot(400, 435, hall1, 27, 3)), Game(None, None, Slot(400, 435, hall2, 28, 3)), Game(None, None, Slot(400, 435, hall3, 29, 3)), Game(None, None, Slot(440, 475, hall1, 30, 3)), Game(None, None, Slot(440, 475, hall2, 31, 3)), ], [ Game(None, None, Slot(480, 515, hall1, 32, 4)), Game(None, None, Slot(480, 515, hall2, 33, 4)), Game(None, None, Slot(480, 515, hall3, 34, 4)), Game(None, None, Slot(520, 555, hall1, 35, 4)), Game(None, None, Slot(520, 555, hall2, 36, 4)), Game(None, None, Slot(520, 555, hall3, 37, 4)), Game(None, None, Slot(560, 595, hall1, 38, 4)), Game(None, None, Slot(560, 595, hall3, 39, 4)), ], ] results = [ Game(MatchUp(Team("a", "", 0), Team("b", "", 1)), Result(0, 10, 11), Slot(-40, -5, hall1, 0, -1)), Game(MatchUp(Team("c", "", 2), Team("d", "", 3)), Result(0, 10, 11), Slot(-40, -5, hall2, 0, -1)), Game(MatchUp(Team("e", "", 4), Team("f", "", 5)), Result(0, 10, 11), Slot(-40, -5, hall3, 0, -1)), Game(MatchUp(Team("g", "", 6), Team("h", "", 7)), Result(0, 10, 11), Slot(-40, -5, hall1, 0, -1)), Game(MatchUp(Team("i", "", 8), Team("j", "", 9)), Result(0, 10, 11), Slot(-40, -5, hall2, 0, -1)), Game(MatchUp(Team("k", "", 10), Team("l", "", 11)), Result(0, 10, 11), Slot(-40, -5, hall3, 0, -1)), Game(MatchUp(Team("m", "", 12), Team("n", "", 13)), Result(0, 10, 11), Slot(-40, -5, hall1, 0, -1)), Game(MatchUp(Team("o", "", 14), Team("p", "", 15)), Result(0, 10, 11), Slot(-40, -5, hall2, 0, -1)), ] rankingLosses = [] for i in range(0, numRounds): # generate matchups matchUpGenerator = MatchUpGenerator(ranking, results) futureMatchUps = matchUpGenerator.generateMatchUps(False) # schedule matchups scheduler = SwissGameScheduler() returnedGames = scheduler.maximizeGain(results, futureSlots[i], futureMatchUps) # generate results for game in returnedGames: results.append(genResult(game)) # generate ranking ranking = generateNewRanking(ranking, results, False) rankingLosses.append(calculateRankingLoss(expectedRanking, ranking)) timesPlayedHall3 = [0] * len(expectedRanking) for game in results: if (game.slot.locationId == hall3): timesPlayedHall3[expectedRanking.index(game.matchup.first)] += 1 timesPlayedHall3[expectedRanking.index(game.matchup.second)] += 1 return np.array(rankingLosses), np.array(timesPlayedHall3)
def getListOfGames(self, divisionId: int, gameStates: List[GameState], locationId: int = None) -> List[Game]: if divisionId == None or divisionId < 0: raise ValueError("divisionId must not be None nor negative") if locationId == None: locationId = -1 if len(gameStates) <= 0: gameStates = [ GameState.NOT_YET_STARTED, GameState.COMPLETED, GameState.RUNNING ] games = [] if self.conn.is_connected(): gameStateStringList = "" for x in range(len(gameStates)): if x == 0: gameStateStringList += "%s" else: gameStateStringList += ",%s" gameStateArgs = () for gameState in gameStates: gameStateArgs += (gameState, ) format_strings = ','.join(['\'%s\''] * len(gameStates)) query = "SELECT team1.team_name AS team1_name, team1.team_acronym AS team1_acronym, team1.team_id AS team1_id, team1.team_seed AS team1_seed, "\ "team2.team_name AS team2_name, team2.team_acronym AS team2_acronym, team2.team_id AS team2_id, team2.team_seed AS team2_seed, "\ "matchup.matchup_id AS matchup_id, matchup.matchup_team1_timeouts AS team1_timeouts, "\ "matchup.matchup_team1_score AS team1_score, matchup.matchup_team2_timeouts AS team2_timeouts, "\ "matchup.matchup_team2_score AS team2_score, slot.slot_id AS slot_id, "\ "slot.slot_start AS slot_start, slot.slot_end AS slot_end, slot.location_id AS location_id, "\ "round.round_number AS round_number, game.game_id AS game_id "\ "FROM game "\ "INNER JOIN matchup ON game.matchup_id = matchup.matchup_id "\ "INNER JOIN team AS team1 ON matchup.matchup_team1_id = team1.team_id "\ "INNER JOIN team AS team2 ON matchup.matchup_team2_id = team2.team_id "\ "INNER JOIN slot ON game.slot_id = slot.slot_id "\ "INNER JOIN round ON slot.round_id = round.round_id "\ "WHERE game.game_state IN ("+gameStateStringList+") "\ "AND round.division_id = %s" args = gameStateArgs + (divisionId, ) #print(query) if locationId >= 0: query += " AND slot.location_id = %s" args += (locationId, ) try: cursor = self.conn.cursor(dictionary=True) cursor.execute(query, args) row = cursor.fetchone() while row is not None: #print(row) team1 = Team(row["team1_name"], row["team1_acronym"], row["team1_id"], row["team1_seed"]) team2 = Team(row["team2_name"], row["team2_acronym"], row["team2_id"], row["team2_seed"]) matchup = MatchUp(team1, team2, row["matchup_id"]) slot = Slot(row["slot_start"], row["slot_end"], row["location_id"], row["slot_id"], row["round_number"]) result = Result(row["matchup_id"], row["team1_score"], row["team2_score"], row["team1_timeouts"], row["team2_timeouts"]) game = Game(matchup, result, slot, row["game_id"]) games.append(game) row = cursor.fetchone() except Error as e: print(e) finally: cursor.close() else: raise NoDatabaseConnection() return games