Skip to content

Instantly share code, notes, and snippets.

@voronaam
Last active March 5, 2024 05:17
Show Gist options
  • Save voronaam/b137a9168bf190e67503c88a11a6a558 to your computer and use it in GitHub Desktop.
Save voronaam/b137a9168bf190e67503c88a11a6a558 to your computer and use it in GitHub Desktop.
Model for an unbalanced game
#!/usr/bin/env python3
import argparse
import random
LADDER_PLAYERS = 1000
LADDER_GAMES = 1000000
TOURNAMENTS = 20
def win_probability(race1, race2, imbalance, rematch):
# If the players have the same race probability is 0.5, otherwise it is 0.5 + imbalance for Terg
if race1 == race2:
prob = 0.5
elif race1 == 'Terg':
prob = 0.5 + imbalance + rematch
else:
prob = 0.5 - imbalance - rematch
# print("Probability of {} winning against {} is {}".format(race1, race2, prob))
return prob
def ladder_game(player1, player2, imbalance, rematch):
prob = win_probability(player1["race"], player2["race"], imbalance, rematch)
# Return tupple (winner, loser)
if random.random() < prob:
return (player1, player2)
else:
return (player2, player1)
def simulate_ladder(imbalance):
# Create array of 500 Protoss and 500 Terg players
players = [{'race' : 'Protoss', 'mmr': 0} for i in range(int(LADDER_PLAYERS/2))] + [{'race' : 'Terg', 'mmr': 0} for i in range(int(LADDER_PLAYERS/2))]
# loop for a lot of games
for i in range(LADDER_GAMES):
# Select two random players
player1 = random.choice(players)
player2 = random.choice(players)
# If the players have the same skip the game
if player1 == player2:
continue
# Note the rematch premium is always 0.0 for ladder
(winner, looser) = ladder_game(player1, player2, imbalance, 0.0)
# Increase MMR of the winner by 1 and decrease looser's MMR by 1
winner["mmr"] += 1
looser["mmr"] -= 1
# Find the top 100 players by MMR
top100 = sorted(players, key=lambda x: x['mmr'], reverse=True)[:100]
# Count the number of Protoss and Terg players in the top 100
protoss_percent = sum([1 for p in top100 if p["race"] == "Protoss"])
# format protoss percentage as float with 2 decimal places
print("Protoss percentage in the ladder Grand Master: {}%".format(protoss_percent))
def tournament_round(players, imbalance, rematch, bo):
# Run the round
winners = []
for i in range(0, len(players), 2):
player1 = players[i]
player2 = players[i+1]
# run `bo` games and find out the winner
player1wins = [random.random() < win_probability(player1, player2, imbalance, i*rematch) for i in range(bo)]
if max(set(player1wins), key=player1wins.count):
winners += [player1]
else:
winners += [player2]
return winners
def tournament(imbalance, rematch):
# Create array of 16 Protoss and 16 Terg players
players = ['Protoss' for i in range(16)] + ['Terg' for i in range(16)]
# Shuffle the players
random.shuffle(players)
# Round of 32 is bo3
ro32winners = tournament_round(players, imbalance, rematch, 3)
# Round of 16 is bo3
ro16winners = tournament_round(ro32winners, imbalance, rematch, 3)
# Round of 8 is bo5
ro8winners = tournament_round(ro16winners, imbalance, rematch, 5)
# Round of 4 is bo5
ro4winners = tournament_round(ro8winners, imbalance, rematch, 5)
# The final is bo7
winner = tournament_round(ro4winners, imbalance, rematch, 7)
return winner
def simulate_tournaments(imbalance, rematch):
protoss_wins = 0
for i in range(TOURNAMENTS):
winner = tournament(imbalance, rematch)
if winner[0] == 'Protoss':
protoss_wins += 1
print("Protoss won {} tournaments out of {}.".format(protoss_wins, TOURNAMENTS))
parser = argparse.ArgumentParser(description='Run the balance model')
parser.add_argument('imbalance', type=float, help='The game imbalance (Positive to favor Terg, negative Protoss. 0.1 means 60% winrate for Terg and 40% for Protoss)')
parser.add_argument('rematch', type=float, help='Rematch premium. Applied for any rematch between the same players. Positive numbers favour Terg')
args = parser.parse_args()
# Run the model
print("""Running the model with the following parameters
Chance of Protoss winning a game on ladder {:.0f}%
Chance of Protoss winning a game 1 in a tournament series {:.0f}%
Chance of Protoss winning a game 2 in a tournament series {:.0f}%
Chance of Protoss winning a game 3 in a tournament series {:.0f}%
and so on...
""".format( (0.5 - args.imbalance)*100,
(0.5 - args.imbalance)*100,
(0.5 - args.imbalance - args.rematch )*100,
(0.5 - args.imbalance - args.rematch*2 )*100))
simulate_ladder(args.imbalance)
simulate_tournaments(args.imbalance, args.rematch)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment