I have written a program that simulates volleyball using rally scoring. In rally scoring, the team that wins the rally wins the point, regardless of which team is serving (for this reason my program ignores the issue of who’s serving). Games are played to a score of 30 and must be won by at least 2 points.

I actually have my program working. My problem is that I don’t understand why when I use a different version of the simOneGame function within my program, the program’s final output is so drastically different (and wrong).

The simOneGame function that generates good output is not commented out. The simOneGame function that generates bad output is commented out and has “#Why does this not work?” printed after the function definition.

An explanation of why the bad one doesn’t work would be greatly appreciated. Thanks.

# College volleyball simulation.  The team that wins the rally is awarded
# the point, even if they were not the serving team.  games are played to a
# score of 30.

from random import random

def printIntro():
    print "This program simulates a game of volleyball between two"
    print 'teams called "A" and "B".  The abilities of each team is'
    print "indicated by a probability (a number between 0 and 1) that"
    print "the team wins the point."

def getInputs():
    # Returns three simulation parameters probA, probB and n
    a = input("What is the prob. team A wins a rally? ")
    b = input("What is the prob. team B wins a rally? ")
    n = input("How many games to simulate? ")
    return a, b, n

def simNGames(n, probA, probB):
    # Simulate n games and return winsA and winsB
    winsA = 0
    winsB = 0
    for i in range(n):
        scoreA, scoreB = simOneGame(probA, probB)
        if scoreA > scoreB:
            winsA = winsA + 1
        else:
            winsB = winsB + 1
    return winsA, winsB

def simOneGame(probA, probB):
    # Simulates a single game of volleyball between two teams whose
    # abilities are represented by the probabiltiy or winning a rally.
    # Returns final scores for A and B.
    scoreA = 0
    scoreB = 0
    while not gameOver(scoreA, scoreB):
            if random()*probA > random()*probB:
                scoreA = scoreA + 1
            else:
                scoreB = scoreB + 1
    return scoreA, scoreB

##def simOneGame(probA, probB): #Why does this not work?
##    # Simulates a single game of volleyball between two teams whose
##    # abilities are represented by the probabiltiy or winning a rally.
##    # Returns final scores for A and B.
##    scoreA = 0
##    scoreB = 0
##    while not gameOver(scoreA, scoreB):
##            if random()*probA > random()*probB:
##                scoreA = scoreA + 1
##            elif random()*probA < random()*probB:
##                scoreB = scoreB + 1
##    return scoreA, scoreB

def gameOver(a, b):
    # a and b represent scores for a volleyball game.
    # Returns True if the game is over, False otherwise
    return (a >=30 and a - b >= 2) or (b >=30 and b - a >= 2)

def printSummary(winsA, winsB):
    # prints a summary of wins for each team.
    n = winsA + winsB
    print "\nGames simulated:", n
    print "Wins for A: %d (%0.1f%%)" % (winsA, float(winsA)/n*100)
    print "Wins for B: %d (%0.1f%%)" % (winsB, float(winsB)/n*100)

def main():
    printIntro()
    probA, probB, n = getInputs()
    winsA, winsB = simNGames(n, probA, probB)
    printSummary(winsA, winsB)
main()

Edited 3 Years Ago by Dani: Formatting fixed

You do not allow for an equal condition in the commented code. Since you did not say what "wrong" is, we can only guess.

sorry. By "wrong" I mean that if you give each team probabilities of .5, for example, team A will win something like 97% of the time. When equal probabilities are given to both teams, they should each win approximately 50% of the time.

The problem is not so much equal condition (which is infinitesimal), but the fact that you recalculate random(). In the failing case,

##            if random()*probA > random()*probB:
##                scoreA = scoreA + 1
##            elif random()*probA < random()*probB:
##                scoreB = scoreB + 1

the fact that team A loses (line 2 skipped) doesn't necessarily result in incrementing teamB's score.

That said, even the "working" case doesn't seem to be correct. You need to calculate random() once, normalize it to (0, 1) and compare to probA.

Comments
indeed

If you choose

if random()*probA > random()*probB:
                scoreA = scoreA + 1
            else:
                scoreB = scoreB + 1

you can compute the probability that each team wins the point like this: take 2 random variables X, Y uniformly distributed in [0, 1], the probability p that team A wins the point is p = P(probA * X > probB * Y). You can visualize (X, Y) as a random point in the square and the probability is the area of the blue triangle in the attached image. The slope of the upper side of the triangle is probA/probB, so you see that

p = probA/(2 * probB) if probA < probB

p = 1 - probB/(2 * probA) if probA >= probB (in this case the blue area is the complementary of a triangle).

From this you could compute numerically the probability that each team wins the game.

As nezachem remarked, your other law leads to different probabilities.

Edited 5 Years Ago by Gribouillis: n/a

Attachments probability.png 1.23 KB

The idea of strengths of teams is nice, but the method is little intriguing. Considering the case is for two teams competing each other the probability should be ok, just ask probA (as probB would be 1 - probA) and check for if random() < probA: Input could be in percent and you can divide it by 100 before use.

Here is how you can compute the probability that team A wins the game, given the probability that it wins a single point

import sys

version_info = (0, 1)
version = ".".join(map(str, version_info))

def win_probability(p):
    p = float(p)
    assert 0.0 <= p <= 1.0
    N = 30
    q = 1 - p
    L = list(q**i for i in range(30))
    for i in range(1, 30):
        L[0] *= p
        for j in range(1, 30):
            L[j] = p * L[j] + q * L[j-1]
    s = sum(L[:-1])
    return s * p + L[-1] * p**2/(p**2+q**2)

def main(opts, args):
    print "Probability that A wins: ", win_probability(0.55)

#--------------------------------------
#   argv parsing section

def parse_args():
    from optparse import OptionParser
    parser = OptionParser(version='%prog version ' + version)
    (opts, args) = parser.parse_args()
    return (opts, args)

if __name__ == '__main__':
    main(*parse_args())

""" my output -->
Probability that A wins:  0.784152774242
"""

Edited 5 Years Ago by Gribouillis: n/a

Actually, there is a simpler formula to compute who wins

from scipy.misc import comb # binomial coefficient function
from scipy.special import betainc # regularized incomplete beta function

def win_match(p):
    """Return the probability that a team wins the match, given the
    probability that it wins a point.
    
    The formula involves the regularized incomplete beta function
    (see http://en.wikipedia.org/wiki/Beta_function) which is called betainc()
    in scipy.
    """
    p = float(p)
    q = 1.0 - p
    n = 29
    return 1.0 - betainc(n+1, n+1, q) + comb(2*n, n) * (p*q)**n *(
                                                    -p + p**2/(p**2+q**2))

It took me some time to find it :)

Edited 5 Years Ago by Gribouillis: n/a

@Grib: Maybe your solution is reflecting the fact that you are mathematician. Thanks sharing the analysis, regardless of it's relevance to OP. For me, even though I did basic statistics, it is allready good reminder that one point winning probability does not equal match win.

Here would be actually one more step to go as volley ball games are not likely to include only one set. Finally it would be interesting to see probability of team winning championship with constant probability of winning a point (N x N matrix for N teams).

Edited 5 Years Ago by pyTony: n/a

:)

If you define clear rules for the championship, we can try to write a function.

Edited 5 Years Ago by Gribouillis: n/a

Interesting in any case how deceivingly simple problem can give rise to interesting maths even to sophisticated mathematician. The "shape" of problem is nice, but realistically it lives in mathematic space not real world. Winning probability is function of time, even if the team is the home team or not, I think.

Interesting in any case how deceivingly simple problem can give rise to interesting maths even to sophisticated mathematician. The "shape" of problem is nice, but realistically it lives in mathematic space not real world. Winning probability is function of time, even if the team is the home team or not, I think.

That's where computers enrich mathematics by letting us simulate systems with many parameters, when theoretical formulas are out of reach. The simulations may lead to new points of view on the system and tell us which properties to study.

Edited 5 Years Ago by Gribouillis: n/a

Did you realize how deep math the solution exactly would take? Have you sometimes used Python in your work this way leading to new venues of maths? (Sorry OP, start new thread maths and Python?)

Did you realize how deep math the solution exactly would take? Have you sometimes used Python in your work this way leading to new venues of maths? (Sorry OP, start new thread maths and Python?)

I think many people use python this way. You can use the calculating power of computers to explore properties of mathematical objects. Many things can be visualized, like cahotic dynamical systems, solutions of partial differential equations, spectra of operators, etc. You obtain representations that were impossible in the past.

This article has been dead for over six months. Start a new discussion instead.