找回密码
 立即注册
搜索
查看: 41|回复: 0

乒乓球比赛结果-2025世界杯乒乓球比赛结果-乒乓球比赛结果通报

[复制链接]

2万

主题

0

回帖

6万

积分

管理员

积分
63850
发表于 2025-4-22 19:53:35 | 显示全部楼层 |阅读模式
9.1.3 编程案例:乒乓球比赛模拟

大家都知道,中国乒乓球项目的技术水平在世界上处于领先地位,所以几乎所有比赛的冠军都被中国球员包揽了。为了让乒乓球运动更有吸引力,提升其他国家的人对这项运动的兴趣,国际乒联想出了诸多办法来降低中国球员的绝对优势,比如把乒乓球的直径增大、禁止使用某些种类的球拍、更改赛制等等。在本节里,我们要编写程序去模拟乒乓球比赛。这样做是为了研究一项针对中国球员的规则改革是否真的有效。这项改革具体是:从 2001 年 9 月 1 日开始,乒乓球比赛的每一局比分由 21 分变成 11 分。

乒乓球是两个球员之间的比赛。比赛开始后,先是一个球员发球,接着另一个球员把球接回来。之后两人就交替击球,一直到一方无法将球回到对方台上,此时另一方就能得一分。一个球员有若干次发球机会,当用完这些发球机会后,就会换发球。

比赛的胜负取决于球员的技术水平。我们通过两个球员对阵时各自的得分概率来体现他们的技术水平。若球员 A 与 B 水平相近,那么 A 拿下 1 分的概率为 50%,B 拿下 1 分的概率也是 50%。倘若 A 水平较高,其拿下 1 分的概率是 55%,此时 B 拿下 1 分的概率就仅有 45%了。顺便要指出的是,对于球员技术水平的表示方式并没有固定的规则,这是由编程者根据自己的主观意愿来确定的。关键在于表示方法要尽量与实际情况相符。我们在此处采用的是得分概率这种表示方法,它很简单,但是没有将球员作为发球方和接发球方的区别考虑进去。读者可以考虑其他的表示方式,例如:把球员的世界排名转化为获胜概率;用球员作为发球方时的得分概率来表示;通过综合考虑发球得分概率和接发球得分概率的某个概率计算公式来体现,等等。

模拟一回合比赛与得分

在 A、B 两球员比赛时,A 球员得分的概率是 prob,B 球员得分的概率是 1 - prob。通过蒙特卡洛方法,以下代码模拟了获得 1 分的一回合比赛,这是整个模拟程序的核心功能。

<p><pre>    <code>if random() < prob:
    pointA = pointA + 1
else:
    pointB = pointB + 1
</code></pre></p>
我们能够即刻开始对这个核心功能进行测试。假定 A 的得分概率为 0.55,让 A 与 B 展开 10000 分的比拼,来查看它们各自的得分状况。测试代码如下:

<p><pre>    <code>>>> from random import random
>>> pointA = pointB = 0
对于 i 在 10000 的范围内进行遍历:如果随机数小于 0.55 时:
pointA = pointA + 1 else:
pointB = pointB + 1
打印 pointA 和 pointB ,其值分别为 5430 和 4570 。
</code></pre></p>
最后得分大约是 55%比 45%。由此可见,模拟比赛的结果能够反映出 A、B 双方的实力。

模拟一局比赛

乒乓球比赛并非依据比赛回合来判定胜负,而是把若干回合组合成一局,以局为单位来判定胜负。老规则是每局 21 分制,新规则是每局 11 分制。我们把上述模拟一回合比赛及得分的代码进行修改,使其以局为单位进行比赛(假设采用 21 分制)。

<p><pre>    <code>>>> def oneGame():
pointA = pointB = 0
当 pointA 不等于 21 并且 pointB 不等于 21 时:如果 random() 小于 0.55 :
pointA = pointA + 1 else:
pointB 增加了 1,然后返回 pointA 和 pointB
</code></pre></p>
函数对 21 分制的一局比赛进行了模拟:只要尚未有人达到 21 分,就会持续进行回合的较量;

否则就退出循环,并且返回本句中 A 的得分以及 B 的得分。调用的人能够比较这两个返回值的大小,以此来判断是谁赢了这一局。

我们接下来要对函数进行测试,让两名球员展开 1000 局的较量,然后看看最终的胜负情况是怎样的。

<p><pre>    <code>>>> gameA = gameB = 0
>>> for i in range(1000):
        pointA, pointB = oneGame()
        if pointA > pointB:
            gameA = gameA + 1
        else:
            gameB = gameB + 1
>>> print gameA,gameB
751 249
</code></pre></p>


出人意料的是,A、B 在每一回合的获胜概率相差不大,是 55%比 45%。然而,若按每局 21 分制进行比赛,A 的胜局数遥遥领先于 B,达到 75%比 25%。这里面的道理很明显,每回合的胜负偶然性对 21 分一局的胜负影响变小了,得分能力稍强的人更有可能赢得一局。可以想象,若将一局的得分减少,就如同国际乒联把每局改成 11 分那样,那么每回合的胜负偶然性对一局的胜负会产生较大影响。稍后我们会在程序中对这一点进行验证。

模拟一场比赛

一场乒乓球比赛并非要无限制地打很多局才能决出胜负,通常会采取 3 局 2 胜、5 局 3 胜或 7 局 4 胜的方式来进行比赛。接下来我们选用 21 分制且 3 局 2 胜的赛制,编写模拟一场比赛的程序,并且通过模拟 100 场比赛来进行测试。

<p><pre>    <code>>>> def oneMatch():
gameOver 包含了这些情况:有(3,0)的情况;有(0,3)的情况;有(3,1)的情况;有(1,3)的情况;有(3,2)的情况;有(2,3)的情况。
        gameA = gameB = 0
在 gameOver 中,不存在 (gameA, gameB) 这种情况。
            pointA, pointB = oneGame()
            if pointA > pointB:
                gameA = gameA + 1
            else:
                gameB = gameB + 1
        return gameA, gameB
>>> matchA = matchB = 0
>>> for i in range(100):
        gameA, gameB = oneMatch()
        if gameA > gameB:
            matchA = matchA + 1
        else:
            matchB = matchB + 1
>>> print matchA,matchB
89 11
</code></pre></p>
按 3 局 2 胜来计算胜负,这样 A 和 B 的胜负差距更加悬殊,达到 89%比 11%。这是由于 3 局 2 胜的规则使得每一局胜负的偶然性影响被削弱了。

完整程序

经过以上设计过程,我们的模拟乒乓球比赛程序逐渐完善。接下来我们能够进一步提升程序功能,像把球员技术水平改为由用户输入而非固定的 0.55,允许使用不同的比赛规则(21 分或 11 分),增添对比赛结果的分析等。这些新增特性就不做详细说明了,读者可自行阅读下面的完整程序代码。

【程序 9.2】.py

<p><pre>    <code>from random import random
def getInputs():
输入内容为:“Player A 的获胜概率:”,将其赋值给变量 p 。
输入“要模拟多少场比赛?”,并将结果赋值给变量 n 。
    return p, n
定义 simNMatches 函数,其中 n、prob 和 rule 为参数。将 matchA 和 matchB 初始化为 0。
    for i in range(n):
gameA 与 gameB 由 oneMatch(prob,rule) 得出。
    if gameA &gt; gameB:
        matchA = matchA + 1
    else:
        matchB = matchB + 1
    return matchA, matchB
def oneMatch(prob,rule):


gameOver 包含了这些组合:(3,0)、(0,3)、(3,1)、(1,3)、(3,2)、(2,3)
    gameA = gameB = 0
在 gameOver 中不存在 (gameA, gameB) 时:
oneGame 函数根据 prob 和 rule 分别返回了 pointA 和 pointB 。
        if pointA > pointB:
            gameA = gameA + 1
        else:
            gameB = gameB + 1
        return gameA, gameB
def oneGame(prob,rule):
    pointA = pointB = 0
如果游戏没有结束(根据 pointA、pointB 和 rule 判断),那么就继续执行后续操作。
        if random() < prob:
            pointA = pointA + 1
        else:
            pointB = pointB + 1
    return pointA, pointB
def gameOver(a,b,rule):
    return (a&gt;=rule or b&gt;=rule) and abs(a-b)&gt;=2
def printSummary(a,b): n = float(a + b)
    print "Wins for A: %d (%0.1f%%)" % (a, a/n*100)
    print "Wins for B: %d (%0.1f%%)" % (b, b/n*100)
def main():
    p, n = getInputs()
    matchA, matchB = simNMatches(n,p,21)
    print "\nRule: 21 points, best of 3 games." printSummary(matchA,matchB)
    matchA, matchB = simNMatches(n,p,11)
    print "\nRule: 11 points, best of 3 games." printSummary(matchA,matchB)
main()
</code></pre></p>
本程序的核心代码前面已经介绍过了。其他方面,像 和 的功能是很明显的。只有在判断一局比赛结束的 中,有一个条件 abs(a - b) >= 2 需要加以说明。乒乓球比赛规则规定,在 20:20(或 10:10)之后,赢得一局比赛的球员至少要比对手多得 2 分,必须连得 2 分才能赢得此局。

下面是本程序的一次运行结果:

<p><pre>    <code>Player A 的获胜概率为 0.52 。
要模拟多少场比赛?100 场。
规则是 21 分,三局两胜。A 获胜的次数为 74 次(占 74.0%)。
Wins for B: 26 (26.0%)
Wins for B: 32 (32.0%)
</code></pre></p>
结果表明,球员 A 对球员 B 的得分概率为 52%。采用每局 21 分、3 局 2 胜的规则时,A 有 74%的机会赢得比赛。采用每局 11 分、3 局 2 胜的规则时,A 的获胜概率降到了 68%。这说明国际乒联对规则的修改能削弱强手的优势程度。不过即便处于这样的情况,强手获胜的概率依然是比较高的。并且中国球员的得分概率恐怕远远超过 52%。或许需要把每局的分数再降低一些,亦或是采用其他的办法,才能够增加外国选手获胜的机会吧。

读者可以尝试对程序 9.2 进行修改,例如以发球方得分概率来表示技术水平,同时把发球、换发球等因素添加到模拟程序里。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|【远见汇智】 ( 京ICP备20013102号-17 )

GMT+8, 2025-5-5 20:33 , Processed in 0.310215 second(s), 20 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表