| 33 | |
| 34 | # Modeling limitation, draw probability probably usually depends on score difference |
| 35 | class Game: |
| 36 | def __init__(self, name: str, draw_probability: float = 0.0, repetitions: int = 1): |
| 37 | """ |
| 38 | Args: |
| 39 | name: The name of the game. |
| 40 | draw_probability: The probability of a tie in the game. |
| 41 | repetitions: The number of times to play the game. |
| 42 | """ |
| 43 | self.name = name |
| 44 | assert 0 <= draw_probability <= 1 |
| 45 | self.draw_probability = draw_probability |
| 46 | self.repetitions = repetitions |
| 47 | |
| 48 | def play_game(self, players: list[Player]) -> dict[str, int]: |
| 49 | """ |
| 50 | Returns: |
| 51 | dictionary of number of times each player won or tied |
| 52 | """ |
| 53 | assert len(players) == 2 |
| 54 | p1_elo = players[0].true_elo |
| 55 | p2_elo = players[1].true_elo |
| 56 | p_tie = self.draw_probability |
| 57 | win_prob_a_no_tie = expected_score(p1_elo, p2_elo) |
| 58 | win_prob_b_no_tie = 1 - win_prob_a_no_tie |
| 59 | win_prob_a = win_prob_a_no_tie * (1 - p_tie) |
| 60 | win_prob_b = win_prob_b_no_tie * (1 - p_tie) |
| 61 | results = [] |
| 62 | for _ in range(self.repetitions): |
| 63 | single_result = random.choices( |
| 64 | [players[0].name, players[1].name, TIE], weights=[win_prob_a, win_prob_b, p_tie] |
| 65 | )[0] |
| 66 | results.append(single_result) |
| 67 | return dict(Counter(results)) |
| 68 | |
| 69 | |
| 70 | class Tournament: |
nothing calls this directly
no outgoing calls
no test coverage detected