我一直在寻找好几天,但我找不到正确的解决方案。 我在数学方面比在Python方面更好。
我有一个名为" tennisTotal.py"的脚本。这是网球比赛的概率计算器。 在这个计算器中,我有11个可变字段。
s_point=0
v_game_point=0
w_game_point=0
v_tiebreak=0
w_tiebreak=0
returnpoint_server=0.30
v_games_in_set=0
w_games_in_set=0
v_sets_won=0
w_sets_won=0
best_of=5
我希望这些字段可以通过GUI填充输入。 (GUI仍处于开发阶段,需要添加更多字段)
我想去的地方是我在GUI中放置一个值,例如"服务点赢了"这个值出现在" s_point"领域。 同样适用于GUI中的值"返回点赢了",我希望这个值出现在" returnpoint_server"
我的问题是,如何将我的GUI中的这些值转换为我的"概率"计算器吗
GUI脚本
from Tkinter import *
fields = 'Service Points Won', 'Return Points Won'
def fetch(variables):
for variable in variables:
print "%s" % variable.get()
def makeform(root, fields):
lab1= Label(text="Stats", font="Verdana 10 bold")
form = Frame(root)
left = Frame(form)
rite = Frame(form)
lab1.pack(side=TOP)
form.pack(fill=X)
left.pack(side=LEFT)
rite.pack(side=RIGHT)
variables = []
for field in fields:
lab1= Label()
lab = Label(left, text=field)
ent = Entry(rite)
lab.pack(anchor='w')
ent.pack(fill=X)
var = StringVar()
ent.config(textvariable=var)
var.set('0.5')
variables.append(var)
return variables
if __name__ == '__main__':
root = Tk()
vars = makeform(root, fields)
Button(root, text='Fetch',
command=(lambda v=vars: fetch(v))).pack()
root.bind('<Return>', (lambda event, v=vars: fetch(v)))
root.mainloop()
概率脚本
s_point=0
v_game_point=0
w_game_point=0
v_tiebreak=0
w_tiebreak=0
returnpoint_server=0.30
v_games_in_set=0
w_games_in_set=0
v_sets_won=0
w_sets_won=0
best_of=5
def fact(x):
if x in[0, 1]:
return 1
r = 1
for a in range(1, (x+1)):
r = r*a
return r
def ch(a, b):
return fact(a)/(fact(b)*fact(a-b))
def gameOutcome(s, a, b):
return ch((a+b), a)*(s**a)*((1-s)**b)*s
# Game Probability
def gameProb(s=s_point, v=v_game_point, w=w_game_point):
# function calculates the probability of server winning
# a single game, given p(winning any given point) [s],
# and the current point score.
# v, w = current game score, where love = 0, 15 = 1, etc.
# - e.g. 30-15 is v=2, w=1
# check if game is already over:
if v >= 4 and (v-w) >= 2:
return 1
elif w >= 4 and (w-v) >= 2:
return 0
else:
pass
# if deuce or ad score e.g. 5-4, reduce to e.g. 3-2
while True:
if (v+w) > 6:
v -= 1
w -= 1
else:
break
# specific probabilities:
if w == 0:
w0 = gameOutcome(s, 3-v, 0)
else:
w0 = 0
if w <= 1:
w15 = gameOutcome(s, 3-v, 1-w)
else:
w15 = 0
if w <= 2:
w30 = gameOutcome(s, 3-v, 2-w)
else:
w30 = 0
if v == 4:
wAd, lAd = s, 0
d = 1-s
elif w == 4:
wAd, lAd = 0, 1-s
d = s
else:
wAd, lAd = 0, 0
a = 3 - v
b = 3 - w
d = ch((a+b), a)*(s**a)*((1-s)**b)
if v <= 2:
l30 = gameOutcome((1-s), 3-w, 2-v)
else:
l30 = 0
if v <= 1:
l15 = gameOutcome((1-s), 3-w, 1-v)
else:
l15 = 0
if v == 0:
l0 = gameOutcome((1-s), 3-w, 0)
else:
l0 = 0
# given d = prob of getting to deuce,
# math to divide up further outcomes
denom = s**2 + (1-s)**2
wd = (d*(s**2))/denom
ld = (d*((1-s)**2))/denom
win = w0 + w15 + w30 + wd + wAd
lose = l0 + l15 + l30 + ld + lAd
return win
# Tiebreak Probability
def tiebreakProb(s=s_point, t=returnpoint_server, v=v_tiebreak, w=w_tiebreak, p=7):
# calculate the probability that the current server wins a best-of-p
# tiebreak.
# s = p(server wins service point)
# t = p(current server wins return point)
# v, w = current score
# check if tiebreak is already over:
if v >= p and (v-w) >= 2:
return 1
elif w >= p and (w-v) >= 2:
return 0
else:
pass
# re-adjust so that point score is not higher than p;
# e.g., if p=7 and score is 8-8, adjust to 6-6, which
# is logically equivalent
while True:
if (v+w) > 2*(p-1):
v -= 1
w -= 1
else:
break
outcomes = {}
# track probability of each possible score
# this is messy and probably not optimal, figuring out
# how many points remain, and how many are on each
# player's serve:
for i in range((p-1)):
remain = p + i - v - w
if remain < 1:
continue
else:
pass
if remain % 2 == 1:
if (v+w) % 2 == 0:
if (remain-1) % 4 == 0:
svc = (remain+1)/2
ret = (remain-1)/2
else:
svc = (remain-1)/2
ret = (remain+1)/2
else:
if (remain-1) % 4 == 0:
svc = (remain+1)/2
ret = (remain-1)/2
else:
svc = (remain+1)/2
ret = (remain-1)/2
else:
if (v+w) % 2 == 0:
svc, ret = remain/2, remain/2
else:
svc, ret = (remain-2)/2, (remain-2)/2
if remain % 4 == 0:
svc += 1
ret += 1
else:
svc += 2
# who serves the last point?
if (v+w) % 2 == 0:
if (remain % 4) in [0, 1]:
final = s
svc -= 1
else:
final = t
ret -= 1
else:
if (remain % 4) in [3, 0]:
final = t
ret -= 1
else:
final = s
svc -= 1
pOutcome = 0
for j in range(svc+1):
for k in range(ret+1):
if (j+k) == (p - 1 - v):
m = svc - j
n = ret - k
pr = (s**j)*(t**k)*((1-s)**m)*((1-t)**n)*ch(svc, j)*ch(ret, k)*final
pOutcome += pr
else:
continue
key = str(p) + str(i)
outcomes[key] = pOutcome
if remain % 2 == 1:
if (v+w) % 2 == 0:
if (remain-1) % 4 == 0:
svc = (remain+1)/2
ret = (remain-1)/2
else:
svc = (remain-1)/2
ret = (remain+1)/2
else:
if (remain-1) % 4 == 0:
svc = (remain+1)/2
ret = (remain-1)/2
else:
svc = (remain+1)/2
ret = (remain-1)/2
else:
if (v+w) % 2 == 0:
svc, ret = remain/2, remain/2
else:
svc, ret = (remain-2)/2, (remain-2)/2
if remain % 4 == 0:
svc += 1
ret += 1
else:
svc += 2
# probability of getting to (p-1)-(p-1) (e.g. 6-6)
final = 1
x = 0
for j in range(svc+1):
for k in range(ret+1):
if (j+k) == (p - 1 - v):
m = svc - j
n = ret - k
pr = (s**j)*(t**k)*((1-s)**m)*((1-t)**n)*ch(svc, j)*ch(ret, k)*final
x += pr
else:
continue
outcomes['+'] = (x*s*t)/((s*t) + (1-s)*(1-t))
# add up all positive outcomes
wtb = 0
for z in outcomes:
wtb += outcomes[z]
return wtb
# Set Probability
def setOutcome(final, sGames, rGames, vw, g, h):
pOutcome = 0
for j in range((sGames+1)):
for k in range((rGames+1)):
if (j + k) == (6 - 1 - vw):
m = sGames - j
n = rGames - k
p = (g**j)*(h**k)*((1-g)**m)*((1-h)**n)*ch(sGames, j)*ch(rGames, k)*final
pOutcome += p
else:
continue
return pOutcome
def setGeneral(s=s_point, u=returnpoint_server, v=v_games_in_set, w=w_games_in_set, tb=1):
# calculate the probability of the current server winning
# a 6-game, tiebreak set, given prob. of server winning any
# given service point (s) or return point (u), and the current
# game score (v, w)
# get prob of current server winning a service game:
g = gameProb(s)
# and current server winning a return game:
h = gameProb(u)
# is set over?
if tb:
if v == 7:
return 1
elif w == 7:
return 0
elif v == 6 and (v-w) > 1:
return 1
elif w == 6 and (w-v) > 1:
return 0
else:
pass
else:
if v >= 6 and (v-w) > 1:
return 1
elif w >= 6 and (w-v) > 1:
return 0
else:
pass
# if not over, re-adjust down to no higher than 6-6
while True:
if (v+w) > 12:
v -= 1
w -= 1
else:
break
# if no tiebreak, chance that server wins set is ratio
# of server's prob of winning
# two games in a row to returner's prob of winning two games in a row
if not tb:
deuceprob = (g*h)/((g*h) + (1-g)*(1-h))
outcomes = {}
# special cases, 11 games or more already
if (v+w) == 12:
if tb:
tp = tiebreakProb(s, u)
outcomes['76'] = tp
outcomes['67'] = 1 - tp
else:
outcomes['75'] = deuceprob
outcomes['57'] = 1-deuceprob
elif (v+w) == 11:
if tb:
tp = tiebreakProb((1-u), (1-s))
if v == 6:
outcomes['75'] = g
x = (1-g)
outcomes['76'] = x*(1 - tp)
outcomes['67'] = x*tp
else:
outcomes['57'] = 1-g
x = g
outcomes['76'] = x*(1 - tp)
outcomes['67'] = x*tp
else:
if v == 6:
outcomes['75'] = g
outcomes['57'] = 0
f = 1 - g
else:
outcomes['57'] = 1-g
outcomes['75'] = 0
f = g
outcomes['75'] += f*deuceprob
outcomes['57'] += f*(1-deuceprob)
else:
for i in range(5):
t = 6 + i - v - w
if t < 1:
continue
if t % 2 == 0:
final = h
sGames = t/2
rGames = sGames - 1
else:
final = g
sGames = (t-1)/2
rGames = (t-1)/2
pOutcome = setOutcome(final, sGames, rGames, v, g, h)
key = '6' + str(i)
outcomes[key] = pOutcome
# loss probabilities
# this section isn't necessary, but I wrote it for informal
# testing purposes
for i in range(5):
t = 6 + i - v - w
if t < 1:
continue
if t % 2 == 0:
final = 1-h
sGames = t/2
rGames = sGames - 1
else:
final = 1-g
sGames = (t-1)/2
rGames = (t-1)/2
pOutcome = setOutcome(final, sGames, rGames, w, (1-g), (1-h))
key = str(i) + '6'
outcomes[key] = pOutcome
t = 10 - v - w
if t % 2 == 0:
sGames = t/2
rGames = t/2
else:
sGames = (t-1)/2 + 1
rGames = (t-1)/2
f = setOutcome(1, sGames, rGames, v, g, h)
if tb == 1:
outcomes['75'] = f*g*h
outcomes['57'] = f*(1-g)*(1-h)
x = f*g*(1-h) + f*(1-g)*h
if (v+w) % 2 == 0:
tp = tiebreakProb(s, u)
else:
tp = tiebreakProb(u, s)
outcomes['76'] = x*tp
outcomes['67'] = x - x*tp
else:
outcomes['75'] = f*deuceprob
outcomes['57'] = f*(1-deuceprob)
win = 0
for o in outcomes:
if o in ['60', '61', '62', '63', '64', '75', '76']:
win += outcomes[o]
else:
pass
return win
#Match Probability
def matchGeneral(e, v=0, w=0, s=3):
# calculates probability of winning the match
# from the beginning of a set
# e is p(winning a set)
# v and w is current set score
# s is total number of sets ("best of")
towin = (s+1)/2
left = towin - v
if left == 0:
return 1
remain = s - v - w
if left > remain:
return 0
win = 0
for i in range(left, (remain+1)):
add = ch((i-1), (left-1))*(e**(left-1))*((1-e)**(i-left))*e
win += add
return win
def matchProb(s=s_point, t=returnpoint_server, gv=v_game_point, gw=w_game_point, sv=v_games_in_set, sw=w_games_in_set, mv=v_sets_won, mw=w_sets_won, sets=best_of):
# calculates probability of winning a match from any given score,
# given:
# s, t: p(server wins a service point), p(server wins return point)
# gv, gw: current score within the game. e.g. 30-15 is 2, 1
# sv, sw: current score within the set. e.g. 5, 4
# mv, mw: current score within the match (number of sets for each player)
# v's are serving player; w's are returning player
# sets: "best of", so default is best of 3
a = gameProb(s)
b = gameProb(t)
c = setGeneral(s, t)
if gv == 0 and gw == 0:
if sv == 0 and sw == 0:
return matchGeneral(c, v=mv, w=mw, s=sets)
else:
sWin = setGeneral(a, b, s, t, v=sv, w=sw)
sLoss = 1 - sWin
elif sv == 6 and sw == 6:
sWin = tiebreakProb(s, t, v=gv, w=gw)
sLoss = 1 - sWin
else:
gWin = gameProb(s, v=gv, w=gw)
gLoss = 1 - gWin
sWin = gWin*(1 - setGeneral((1-b), (1-a), (1-t), (1-s), v=sw, w=(sv+1)))
sWin += gLoss*(1 - setGeneral((1-b), (1-a), (1-t), (1-s), v=(sw+1), w=sv))
sLoss = 1 - sWin
mWin = sWin*matchGeneral(c, v=(mv+1), w=mw, s=sets)
mWin += sLoss*matchGeneral(c, v=mv, w=(mw+1), s=sets)
return mWin, sLoss
print "Server Game = ""{0:.2%}".format(gameProb())
print "Receiver Game = ""{0:.2%}".format(1-gameProb())
print "Server Tiebreak = ""{0:.2%}".format(tiebreakProb())
print "Receiver Tiebreak = ""{0:.2%}".format(1-tiebreakProb())
print "Server Set = ""{0:.2%}".format(setGeneral())
print "Receiver Set = ""{0:.2%}".format(1-setGeneral())
print "Server Match = ""{0:.2%}".format(matchProb())
print "Receiver Match= ""{0:.2%}".format(1-matchProb())
答案 0 :(得分:1)
您可以将概率脚本转换为class
,然后在每次要运行时创建class
对象。为此,我还将您的GUI转换为class
,以便将变量传递给运行第二个脚本的按钮函数更简单。
将概率脚本转换为class
:
class probScript():
def __init__(self, s_point, v_game_point, w_game_point, v_tiebreak, ...):
self.s_point=s_point
self.v_game_point=v_game_point
self.w_game_point=w_game_point
...
run_method()
我不太熟悉Tkinter
但是添加一个按钮来运行当前GUI输入的脚本应该可行。如果您在__init__()
class
run_method()
中调用概率脚本方法,那么您只需在按钮函数中创建对象即可运行。< / p>
button = Tkinter.Button(text="Check Probability", command=self.run_prob_script)
button.pack()
root.mainloop()
def run_prob_script(self):
prob_script = probScript(self.input_1, self.input_2, ...)