Skip to content

Commit

Permalink
Update prob_match function to fix bug with serving change over
Browse files Browse the repository at this point in the history
  • Loading branch information
mjam03 committed Jan 12, 2022
1 parent de5118b commit 1fce30a
Showing 1 changed file with 193 additions and 3 deletions.
196 changes: 193 additions & 3 deletions src/tennisim/match.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def prob_match(
g_b (int, optional): games in curr set won by 'b'. Defaults to 0.
pt_a (int, optional): points in curr game won by 'a'. Defaults to 0.
pt_b (int, optional): points in curr game won by 'b'. Defaults to 0.
sets (int, optional): how many sets match si 'best of'. Defaults to 3.
sets (int, optional): how many sets match is 'best of'. Defaults to 3.
Returns:
float: probability that player 'a' wins the match
Expand Down Expand Up @@ -110,8 +110,13 @@ def prob_match(
# by adding prob we win set if we win this game
# with prob we win this set if we lose this game
p_this_game = prob_game(p_a, pt_a, pt_b)
p_this_set_if_w = p_this_game * prob_set(p_a, p_b, g_a + 1, g_b)
p_this_set_if_l = (1 - p_this_game) * prob_set(p_a, p_b, g_a, g_b + 1)
# we want prob we win the set here if we win the game
# but if we serve this game then they serve the next
# so we need to view it from ther perspective
p_this_set_if_w = p_this_game * (1 - prob_set(p_b, p_a, g_b, g_a + 1))
p_this_set_if_l = (1 - p_this_game) * (
1 - prob_set(p_b, p_a, g_b + 1, g_a)
)
p_this_set = p_this_set_if_w + p_this_set_if_l

# so now we have the probability of winning the set we are in
Expand All @@ -126,3 +131,188 @@ def prob_match(
)[0]
p_match = p_match_w_set + p_match_l_set
return p_match


def reformat_match(match_data: list, p_a: float, p_b: float) -> list:
"""Reformats data generated by match simulation for ease of analysis
Args:
match_data (list): output of match simulation function sim_match
p_a (float): prob that player 'a' wins a given point on serve
p_b (float): prob that player 'b' wins a given point on serve
Returns:
list: list of points in chronological order of the sim'ed tennis match
"""

points = []
game_count = 0
point_count = 0
set_prog = match_data[1]
game_progs = match_data[2]
point_progs = match_data[3]

for i, set_score in enumerate(set_prog):
if i == 0:
# then we haven't played a set yet
# so set score is 0,0
st_a = 0
st_b = 0
else:
# grab previous set score
st_a = set_prog[i - 1][0]
st_b = set_prog[i - 1][1]

# grab the games in the set
games = game_progs[i]
# for each game in that set
for j, g in enumerate(games):
if j == 0:
# then we haven't played any games yet
g_a = 0
g_b = 0
else:
g_a = games[j - 1][0]
g_b = games[j - 1][1]

# now grab the point score in the game
pts = point_progs[i][j]
pts = [(0, 0)] + pts[:-1]
for k, p in enumerate(pts):
if k == 0:
# we haven't played any points yet
pt_a = 0
pt_b = 0
else:
# if we have an even game count
# then 'a' is serving so keep as is
if game_count % 2 == 0:
pt_a = p[0]
pt_b = p[1]
else:
# else reverse them
pt_a = p[1]
pt_b = p[0]

# now compute win probab for player 'a'
# first check special situation of being in tiebreak
if g_a == 6 and g_b == 6:
# then in tiebreak
if game_count % 2 == 0:
# then 'a' should serve first point of tiebreak
# e.g. if we've played 1,2 points in tb then 'b' serve
if (pt_a + pt_b) % 4 == 1 or (pt_a + pt_b) % 4 == 1:
p = 1 - prob_match(
p_b, p_a, st_b, st_a, g_b, g_a, pt_b, pt_a
)
p_w = 1 - prob_match(
p_b, p_a, st_b, st_a, g_b, g_a, pt_b, pt_a + 1
)
p_l = 1 - prob_match(
p_b, p_a, st_b, st_a, g_b, g_a, pt_b + 1, pt_a
)
else:
# then 'a' is serving
p = prob_match(
p_a, p_b, st_a, st_b, g_a, g_b, pt_a, pt_b
)
p_w = prob_match(
p_a, p_b, st_a, st_b, g_a, g_b, pt_a + 1, pt_b
)
p_l = prob_match(
p_a, p_b, st_a, st_b, g_a, g_b, pt_a, pt_b + 1
)
else:
# we have the reverse where b serves first point of tb
if (pt_a + pt_b) % 4 == 1 or (pt_a + pt_b) % 4 == 1:
# then 'a' is serving
p = prob_match(
p_a, p_b, st_a, st_b, g_a, g_b, pt_a, pt_b
)
p_w = prob_match(
p_a, p_b, st_a, st_b, g_a, g_b, pt_a + 1, pt_b
)
p_l = prob_match(
p_a, p_b, st_a, st_b, g_a, g_b, pt_a, pt_b + 1
)
else:
p = 1 - prob_match(
p_b, p_a, st_b, st_a, g_b, g_a, pt_b, pt_a
)
p_w = 1 - prob_match(
p_b, p_a, st_b, st_a, g_b, g_a, pt_b, pt_a + 1
)
p_l = 1 - prob_match(
p_b, p_a, st_b, st_a, g_b, g_a, pt_b + 1, pt_a
)
else:
# we're not in the tiebreak so much easier
if game_count % 2 == 0:
# then 'a' serving
p = prob_match(
p_a, p_b, st_a, st_b, g_a, g_b, pt_a, pt_b
)
p_w = prob_match(
p_a, p_b, st_a, st_b, g_a, g_b, pt_a + 1, pt_b
)
p_l = prob_match(
p_a, p_b, st_a, st_b, g_a, g_b, pt_a, pt_b + 1
)
else:
p = 1 - prob_match(
p_b, p_a, st_b, st_a, g_b, g_a, pt_b, pt_a
)
p_w = 1 - prob_match(
p_b, p_a, st_b, st_a, g_b, g_a, pt_b, pt_a + 1
)
p_l = 1 - prob_match(
p_b, p_a, st_b, st_a, g_b, g_a, pt_b + 1, pt_a
)

# now add this data to a map
p_map = {
"st_a": st_a,
"st_b": st_b,
"g_a": g_a,
"g_b": g_b,
"pt_a": pt_a,
"pt_b": pt_b,
"p_a": p_a,
"p_b": p_b,
"pc": point_count,
"gc": game_count,
"sc": st_a + st_b,
"prob": p,
"prob_w": p_w,
"prob_l": p_l,
}

point_count += 1
points.append(p_map)

# bump game count up
game_count += 1

# add on final score
st_a = set_prog[-1][0]
st_b = set_prog[-1][1]
p = prob_match(p_a, p_b, st_a, st_b)
p_map = {
"st_a": set_prog[-1][0],
"st_b": set_prog[-1][1],
"g_a": 0,
"g_b": 0,
"pt_a": 0,
"pt_b": 0,
"p_a": p_a,
"p_b": p_b,
"pc": point_count,
"gc": game_count,
"sc": st_a + st_b,
"prob": p,
"prob_w": p,
"prob_l": p,
}
points.append(p_map)

return points

0 comments on commit 1fce30a

Please sign in to comment.