先看看一个项目一般怎么完成的吧。要学会如何作为一个程序员来思考解决问题。
    其中一个很重要的能力是问题拆解
    问题拆解就是在面对一个问题的时候,将一个大问题,拆解成多个步骤或者多个方面,逐步解决,最后完成整个问题,达到所要的结果。
    这种思维在我们日常生活中也非常常见,比如:你需要洗衣服,怎么去完成洗衣服呢?
    1. 把衣服放进洗衣机;2. 倒入洗衣液;3. 点击开始按钮;4. 洗衣机开始洗衣服;5. 将洗好的衣服取出晾起来。
    但在编程中,我们拆解问题就需要按照代码的思维方式进行拆解。
    比如:在上一关的作业练习中,葫芦娃和老爷爷猜数字的问题,我们就可以进行拆解。
    1.png
    当然这种拆解问题的思维并不少见。基于长期编写代码的习惯,程序员会将问题拆得更细致一些,即拆到无法再拆为止。 像这样,我会将完成一个项目的流程总结为以下三步:
    2.png
    明确项目目的,指的就是我们希望这个程序做什么,达到什么样的效果,之后才能更好的进行流程分析,拆解项目,最后逐步解决所有问题,逐渐完善整个项目功能。
    需要注意的是,一个完美的拆解方案,应当是按照从上往下的逻辑自然拆解,难度逐渐增加。

    明确项目目的
    在编程界,一般是由产品经理提出项目要求,由程序员来实现。所谓的项目需求,大家可以简单的理解为项目实现效果。

    我们现在需要重现一下仙剑奇侠传中的经典一战【李逍遥大战拜月教主】!
    最终我们需要实现的效果如下:
    3.gif
    用文字描述一下:在这个游戏中,李逍遥(freeLi)大战拜月教主(Boss),游戏开始后,会随机生成李逍遥与拜月教主的属性,相互攻击,直到一方的血量为 0 ,战斗采取三局两胜制,最后显示战斗结果,公布获胜者。
    4.png
    明确了项目目的,接下来就可以对项目进行拆解了。

    逐步解决,逐渐完善
    编写代码的时候,谁都不能一步到位,尤其是对一初入门的学员来说,逐步解决,逐渐完善才是做好的过程。
    现按照 “难度递增,功能叠加” 的思路,将这个游戏拆解成三个版本。
    5.png
    版本 1.0 主要是帮助我们理清战斗逻辑,而版本 2.0 和 3.0 会涉及新的知识点。

    分析流程,拆解项目
    接下来,我们正式进入李逍遥大战拜月教主的主战场。
    首先来看一下 1.0 版本如何实现
    理清战斗逻辑
    首先,根据我们上面的分析,来看一下整个项目中都有哪些基础元素。
    6.png
    根据这些元素,我们要做的主要有三步:
    1. 规定【李逍遥】和【拜月教主】的属性;
    2. 双方攻击时,失血量根据对方的攻击来进行计算;
    3. 如果有一方的血量减少到 0 或 0 以下,GAME OVER。
    为了保持思路的清晰,画出流程图如下:
    7.png
    从第一步开始,设定【李逍遥】和【拜月教主】的属性,及【血量】 和 【攻击力】。

    1. # 自定义李逍遥的血量和攻击力
    2. print('【李逍遥】\n 血量:100 \n 攻击力:25')
    3. # 自定义拜月教主的血量和攻击力
    4. print('【拜月教主】\n 血量:100 \n 攻击力: 20')

    第二步,双方攻击人工计算各自的剩余血量。

    1. # 人工计算拜月教主剩余血量 100 - 25 = 75
    2. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量 75')
    3. # 人工计算李逍遥剩余血量 100 - 20 = 80
    4. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量 80')

    第三步,继续攻击,人工计算各自的剩余血量。

    1. # 人工计算拜月教主剩余血量 75 - 25 = 50
    2. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量 50')
    3. # 人工计算李逍遥剩余血量 80- 20 = 60
    4. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量 60')

    第四步和第五步,继续攻击,人工计算各自剩余血量。

    1. # 第四步
    2. # 人工计算拜月教主剩余血量 50- 25 = 25
    3. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量 25')
    4. # 人工计算李逍遥剩余血量 60 - 20 = 40
    5. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量 40')
    6. # 第五步
    7. # 人工计算拜月教主剩余血量 25 - 25 = 0,此时拜月教主血量为 0,拜月教主死亡,游戏结束。
    8. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量 0')
    9. # 人工计算李逍遥剩余血量 40 - 20 = 20
    10. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量 20')
    11. print('【拜月教主】死了,【李逍遥】赢了')

    是不是很简单,我们接下来要做的就是将几段代码拼接起来,形成一个完成的代码,然后加上一些分割线,让输出结果看起来更美观一些。

    1. # 自定义李逍遥的血量和攻击力
    2. print('【李逍遥】 \n 血量:100 \n 攻击力:25')
    3. # 自定义拜月教主的血量和攻击力
    4. print('【拜月教主】 \n 血量:100 \n 攻击力: 20')
    5. print('-----------------------')
    6. # 人工计算拜月教主剩余血量 100 - 25 = 75
    7. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量 75')
    8. # 人工计算李逍遥剩余血量 100- 20 = 80
    9. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量 80')
    10. print('-----------------------')
    11. # 人工计算拜月教主剩余血量 75 - 25 = 50
    12. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量 50')
    13. # 人工计算李逍遥剩余血量 80 - 20 = 60
    14. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量 60')
    15. print('-----------------------')
    16. # 人工计算拜月教主剩余血量 50 - 25 = 25
    17. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量 25')
    18. # 人工计算李逍遥剩余血量 60 - 20 = 40
    19. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量 40')
    20. print('-----------------------')
    21. # 人工计算拜月教主剩余血量 25 - 25 = 0,此时拜月教主血量为 0,拜月教主死亡,游戏结束。
    22. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量 0')
    23. # 人工计算李逍遥剩余血量 40 - 20 = 20
    24. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量 20')
    25. print('-----------------------')
    26. print('【拜月教主】死了,【李逍遥】赢了')

    现在我们初步实现了项目的目的,但是我们这一下子就将全部的结果都打印出来了,速度太快了,没有丝毫的游戏快感。
    为了让我们看着结果有一定的进展性,可以让打印的结果间隔出现,我需要用到一个类似 “延迟时间” 的东西。在
    Python 江湖中,我们要用到两行代码。
    8.png
    time.sleep() 就是制作延迟效果的,让输出结果可以延迟出现,我们可以先让结果延迟 2s 出现。代码改写如下:

    1. # 调用 time 模块
    2. import time
    3. # 自定义李逍遥的血量和攻击力
    4. print('【李逍遥】 \n 血量:100 \n 攻击力:25')
    5. # 自定义拜月教主的血量和攻击力
    6. print('【拜月教主】 \n 血量:100 \n 攻击力: 20')
    7. print('-----------------------')
    8. time.sleep(2)
    9. # 人工计算拜月教主剩余血量 100 - 25 = 75
    10. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量 75')
    11. # 人工计算李逍遥剩余血量 100 - 20 = 80
    12. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量 80')
    13. print('-----------------------')
    14. # 人工计算拜月教主剩余血量 75 -25 = 50
    15. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量 50')
    16. # 人工计算李逍遥剩余血量 80 -20 = 60
    17. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量 60')
    18. print('-----------------------')
    19. time.sleep(2)
    20. # 人工计算拜月教主剩余血量 50 - 25 = 25
    21. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量 25')
    22. # 人工计算李逍遥剩余血量 60 - 20 = 40
    23. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量 40')
    24. print('-----------------------')
    25. time.sleep(2)
    26. # 人工计算拜月教主剩余血量 25 -25 = 0,此时拜月教主血量为 0,拜月教主死亡,游戏结束。
    27. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量 0')
    28. # 人工计算李逍遥剩余血量 40 - 20 = 20
    29. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量 20')
    30. print('-----------------------')
    31. time.sleep(2)
    32. print('【拜月教主】死了,【李逍遥】赢了')

    Yes! 看起来不错,总算完成了项目 1.0 。
    但是你有没有发现,现在的代码有一点 low 。都是 print() 函数,并且还要自己手动计算剩余血量,结局也可以自己来确定,一点也不智能。
    那我们就要来进行项目升级了。
    接下来要改造两个方面:
    1. 【李逍遥】和【拜月教主】的属性(血量和攻击力)让计算机进行随机指定;
    2. 战斗过程中血量变化让计算机来计算。

    随机属性,自动 PK
    这个阶段,我们主要增加【随机属性】和【自动战斗】两个功能,画出流程图:
    9.png

    现在问题来了,要生成随机属性,也就是随机数字,怎么实现呢?
    这里有一个可以解决大部分问题的方法 — 问度娘!
    可以看到度娘有很多的答案,我们可以点击第一个进去看一下。
    10.png
    看到度娘告诉我们的答案,想生成随机数,要使用 random 随机数模块中的 randint(a,b) 函数,括号内为 a , b 两个数字为生成随机数的范围,a 是小数字,b 是大数字。

    1. # 多运行几次,看看结果是不是随机生成的~
    2. # 调用 random 模块
    3. import random
    4. # 随机生成 1-100 范围内(含 1 和 100 )的一个整数,并赋值给变量 num
    5. num = random.randint(1, 100)
    6. print(num) #结果为1-100的随机一个数字

    好的,既然随机数已经搞定,那么接下来我们就需要把随机数引入到项目中了。
    要求:
    1. 定义两个变量,用来储存【李逍遥】的血量和攻击力;
    2. 血量是 100-150 之间的随机数,攻击力是 20-30 之间的随机数;
    3. 打印两个变量。

    1. # 提示:调用模块需在开头写上 import 模块名,这里需要用到 random 模块
    2. import random
    3. #freeLi_life为李逍遥血量,freeLi_attack为李逍遥攻击。
    4. freeLi_life = random.randint(100,150)
    5. freeLi_attack = random.randint(20,30)
    6. print(xue)
    7. print(gong) #显示结果分别为100-150,20-30之间的任意一个数字

    标准的变量名最好是用英文来表达含义,如果是多个单词组成,需要用英文下划线 “ _ ” 来隔开。
    江湖秘籍:对于取英文变量名,很多英语水平还停留在高考时期的同学会感到头疼,这里我推荐大家一个网站:
    CODELF,输入中文就可以看到别人是怎么命名的。(CODELF网址:https://unbug.github.io/codelf/
    已经能够随机生成【李逍遥】的血量和攻击力了,下面我们要生成【拜月教主】的血量和攻击力,完成随机生成两者属性的任务。

    1. # 导入 time 库和 random 库,也可合并写成一行:import time, random
    2. import time
    3. import random
    4. # 生成随机属性
    5. # “freeLi_life” 代表李逍遥血量
    6. freeLi_life = random.randint(100, 150)
    7. # “freeLi_attack” 代表李逍遥攻击
    8. freeLi_attack = random.randint(20, 30)
    9. # “BOSS_life” 代表拜月教主血量
    10. BOSS_life = random.randint(100, 150)
    11. # “BOSS_attack” 代表拜月教主攻击
    12. BOSS_attack = random.randint(20, 30)
    13. # 展示双方角色的属性
    14. # freeLi_life 和 freeLi_attack 的数据类型都是整数,所以拼接时需要先用 str() 转换
    15. print('【李逍遥】\n 血量:%s \n 攻击力:%s' % (freeLi_life, freeLi_attack))
    16. print('------------------------')
    17. # 暂停一秒再执行后续代码
    18. time.sleep(1)
    19. print('【拜月教主】\n 血量:%s \n 攻击力:%s' % (BOSS_life, BOSS_attack))
    20. print('------------------------')

    截止到目前为止,我们已经解决了随机生成属性的问题,接下来,我们就要实现 “自动 PK ”。
    11.png
    要怎么实现自动战斗呢?如果一头雾水的话,可以先尝试从版本 1.0 的人为战斗来寻找规律:
    可以发现从 【李逍遥】 攻击【拜月教主】到【拜月教主】回击的这几行代码是重复出现的结构,除了数字是变化的,其余的一模一样。
    这时,根据我们已学知识,我们应该用循环语句来解决重复劳动。
    现在是【李逍遥】和【拜月教主】双方互相攻击,到底要打斗多少次,不知道,打斗多长时间也不知道,只知道,有一个的血量为 0 时,战斗结束。只知道循环的条件,因此要用的就是 while 循环了。
    进一步思考:while 后面要接什么条件呢,也就是说什么条件下,战斗过程会一直持续呢?
    12.png
    可见 while 后面要同时满足两个条件,即这两个条件要同时为真,所以我们要用 and 来连接,用代码来表示就是:

    1. # and 两边用()括起来,更方便大家阅读。
    2. while (freeLi_life > 0) and (BOSS_life > 0)

    执行循环的条件已经找到了,接下来就是要设置 while 循环内部的执行代码了。
    根据刚才的分析,我们希望循环的内容是双方互相攻击,掉血的过程。

    1. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量 XXX')
    2. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量 XXX')
    3. print('------------------------')

    其中【拜月教主】剩余血量 =【拜月教主】当前血量 -【李逍遥】攻击力,【李逍遥】剩余血量 =【李逍遥】当前血量 -【拜月教主】攻击力。
    我们在前面已经定义好了这四个变量,每一次攻击后, freeLi_life (李逍遥血量)与 BOSS_life(拜月教主血量)都会重新赋值,代码就是:

    1. # 赋值语句的执行顺序是先计算等号右边,再赋值给左边的变量
    2. freeLi_life = freeLi_life - BOSS_attack
    3. BOSS_life = BOSS_life - freeLi_attack

    好的,自动攻击的基础逻辑也已经理清楚了。我们先合并一下这之前写过的代码。

    1. # 导入 time 库和 random 库,也可合并写成一行:import time, random
    2. import time
    3. import random
    4. # 生成随机属性
    5. # “freeLi_life” 代表李逍遥血量
    6. freeLi_life = random.randint(100, 150)
    7. # “freeLi_attack” 代表李逍遥攻击
    8. freeLi_attack = random.randint(20, 30)
    9. # “BOSS_life” 代表拜月教主血量
    10. BOSS_life = random.randint(100, 150)
    11. # “BOSS_attack” 代表拜月教主攻击
    12. BOSS_attack = random.randint(20, 30)
    13. # 展示双方角色的属性
    14. # freeLi_life 和 freeLi_attack 的数据类型都是整数,所以拼接时需要先用 str() 转换
    15. print('【李逍遥】 \n 血量:%s \n 攻击力:%s' % (freeLi_life, freeLi_attack))
    16. print('------------------------')
    17. # 暂停一秒再执行后续代码
    18. time.sleep(1)
    19. print('【拜月教主】\n 血量:%s \n 攻击力:%s' % (BOSS_life, BOSS_attack))
    20. print('------------------------')
    21. # 自动 PK 阶段
    22. while (freeLi_life > 0) and (BOSS_life > 0):
    23. freeLi_life = freeLi_life - BOSS_attack
    24. BOSS_life = BOSS_life - freeLi_attack

    写到这里,就只剩下补完 while 循环中的内容,也就是实时打印【李逍遥】与【拜月教主】的剩余血量。

    1. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量XXX')
    2. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量XXX')
    3. print('------------------------')

    合成后:

    1. # 导入 time 库和 random 库,也可合并写成一行:import time, random
    2. import time
    3. import random
    4. # 生成随机属性
    5. # “freeLi_life” 代表李逍遥血量
    6. freeLi_life = random.randint(100, 150)
    7. # “freeLi_attack” 代表李逍遥攻击
    8. freeLi_attack = random.randint(20, 30)
    9. # “BOSS_life” 代表拜月教主血量
    10. BOSS_life = random.randint(100, 150)
    11. # “BOSS_attack” 代表拜月教主攻击
    12. BOSS_attack = random.randint(20, 30)
    13. # 展示双方角色的属性
    14. # freeLi_life 和 freeLi_attack 的数据类型都是整数,所以拼接时需要先用 str() 转换
    15. print('【李逍遥】 \n 血量:%s \n 攻击力:%s' % (freeLi_life, freeLi_attack))
    16. print('------------------------')
    17. # 暂停一秒再执行后续代码
    18. time.sleep(1)
    19. print('【拜月教主】 \n 血量:%s \n 攻击力:%s' % (BOSS_life, BOSS_attack))
    20. print('------------------------')
    21. # 自动 PK 阶段
    22. while (freeLi_life > 0) and (BOSS_life > 0):
    23. freeLi_life = freeLi_life - BOSS_attack
    24. BOSS_life = BOSS_life - freeLi_attack
    25. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量' + str(BOSS_life))
    26. # freeLi_life 是整数,所以拼接时要先用 str() 转换
    27. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量' + str(freeLi_life))
    28. print('------------------------')
    29. # 为了体现出战斗回合,这里停顿 2 秒
    30. time.sleep(2)

    2.0 版本总算完成的差不多了。
    不过它还没有实现:打印出每局结果,三局两胜,并打印最终战果的功能。这就是我们在版本 3.0 要增加的功能。
    我们一鼓作气,攻克最后一个难关!

    打印战果,三局两胜
    对比 2.0 版本,在 3.0 版本中,我们想要增加的功能是:
    1、打印战果:每局战斗后,根据胜负平的结果打印出不同的提示;
    2、三局两胜:双方战斗三局,胜局多的为最终赢家。
    13.png
    我们首先来完成战果的打印。
    当【李逍遥】与【拜月教主】PK 的时候,血量都会开始递减,经过多次攻击,会出现如下结果:
    14.png
    根据上面图片的提示,我们可以想到的这部分代码如下:

    1. if freeLi_life > 0 and BOSS_life <= 0:
    2. print('【拜月教主】挂了,【李逍遥】赢了')
    3. elif freeLi_life <= 0 and BOSS_life > 0:
    4. print('悲催,【拜月教主】把【李逍遥】干掉了!')
    5. else:
    6. print('哎呀,【李逍遥】和【拜月教主】同归于尽了!')

    合成后:

    1. # 导入 time 库和 random 库,也可合并写成一行:import time, random
    2. import time
    3. import random
    4. # 生成随机属性
    5. # “freeLi_life” 代表李逍遥血量
    6. freeLi_life = random.randint(100, 150)
    7. # “freeLi_attack” 代表李逍遥攻击
    8. freeLi_attack = random.randint(20, 30)
    9. # “BOSS_life” 代表拜月教主血量
    10. BOSS_life = random.randint(100, 150)
    11. # “BOSS_attack” 代表拜月教主攻击
    12. BOSS_attack = random.randint(20, 30)
    13. # 展示双方角色的属性
    14. # freeLi_life 和 freeLi_attack 的数据类型都是整数,所以拼接时需要先用 str() 转换
    15. print('【李逍遥】 \n 血量:%s \n 攻击力:%s' % (freeLi_life, freeLi_attack))
    16. print('------------------------')
    17. # 暂停一秒再执行后续代码
    18. time.sleep(1)
    19. print('【拜月教主】 \n 血量:%s \n 攻击力:%s' % (BOSS_life, BOSS_attack))
    20. print('------------------------')
    21. # 自动 PK 阶段
    22. while (freeLi_life > 0) and (BOSS_life > 0):
    23. freeLi_life = freeLi_life - BOSS_attack
    24. BOSS_life = BOSS_life - freeLi_attack
    25. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量'+str(BOSS_life))
    26. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量'+str(freeLi_life))
    27. print('------------------------')
    28. # 为了体现出战斗回合,这里停顿 2 秒
    29. time.sleep(2)
    30. # 打印战果
    31. if freeLi_life > 0 and BOSS_life <= 0:
    32. print('【拜月教主】挂了,【李逍遥】赢了')
    33. elif freeLi_life <= 0 and BOSS_life > 0:
    34. print('悲催,【拜月教主】把【李逍遥】干掉了!')
    35. else:
    36. print('哎呀,【李逍遥】和【拜月教主】同归于尽了!')

    现在只剩下最后一步,三局两胜。
    15.png
    怎么来实现三局两胜呢?
    16.png
    首先来看,三局战斗也是一个可以循环的结构,且循环次数是固定的,所以要用到 for 循环。
    在这里我们可以使用 for i in range( ): 的结构,我们先来回顾一下之前学过的 range() 函数。
    range(a, b, c) :
    a : 计数从 a 开始。不填时,默认从 0 开始,例如:range(1, 5), 表示从 1 开始生成;
    b : 计数到 b 结束,但不包括 b ,例如:range(11), 表示从 0 开始生成到 11 结束,不包括 11;
    c : 计数的间隔,不填时默认为 1 ,例如:range(0, 30, 5), 表示计数间隔为 5。
    尝试把代码打出来吧,让战斗循环三局。(先不用统计最后的结果)
    给两个提示:
    1. 想清楚哪些代码要嵌套到 for 循环里,即一局战斗里包括什么信息。确定了 for 写在哪里之后,一局战斗包含的所有信息都要缩进;
    2. 细节也需要留意,如局与局之间要怎么区分开来(时间间隔 & 打印局数信息)

    1. # 导入 time 库和 random 库,也可合并写成一行:import time, random
    2. import time
    3. import random
    4. for i in range(1, 4):
    5. time.sleep(1)
    6. # 让局与局之间有较明显的有时间间隔
    7. print(' \n——————现在进行第' + str(i) + '局,3,2,1,go!——————') # 作为局的标记
    8. # 生成随机属性
    9. # “freeLi_life” 代表李逍遥血量
    10. freeLi_life = random.randint(100, 150)
    11. # “freeLi_attack” 代表李逍遥攻击
    12. freeLi_attack = random.randint(20, 30)
    13. # “BOSS_life” 代表拜月教主血量
    14. BOSS_life = random.randint(100, 150)
    15. # “BOSS_attack” 代表拜月教主攻击
    16. BOSS_attack = random.randint(20, 30)
    17. # 展示双方角色的属性
    18. # freeLi_life 和 freeLi_attack 的数据类型都是整数,所以拼接时需要先用 str() 转换
    19. print('【李逍遥】 \n 血量:%s \n 攻击力:%s' % (freeLi_life, freeLi_attack))
    20. print('------------------------')
    21. # 暂停一秒再执行后续代码
    22. time.sleep(1)
    23. print('【拜月教主】 \n 血量:%s \n 攻击力:%s' % (BOSS_life, BOSS_attack))
    24. print('------------------------')
    25. # 自动 PK 阶段
    26. while (freeLi_life > 0) and (BOSS_life > 0):
    27. freeLi_life = freeLi_life - BOSS_attack
    28. BOSS_life = BOSS_life - freeLi_attack
    29. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量' + str(BOSS_life))
    30. # freeLi_life 是整数,所以拼接时要先用 str() 转换
    31. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量' + str(freeLi_life))
    32. print('------------------------')
    33. # 为了体现出战斗回合,这里停顿 2 秒
    34. time.sleep(2)
    35. # 打印战果
    36. if freeLi_life > 0 and BOSS_life <= 0:
    37. print('【拜月教主】挂了,【李逍遥】赢了')
    38. elif freeLi_life <= 0 and BOSS_life > 0:
    39. print('悲催,【拜月教主】把【李逍遥】干掉了!')
    40. else:
    41. print('哎呀,【李逍遥】和【拜月教主】同归于尽了!')

    三局比赛的效果已经完成, 现在只差 “统计三局两胜” 的结果了。
    平时比赛如何记录比赛结果呢?
    17.png
    好比乒乓球比赛,有一方赢了一局就翻一下计分牌,让数字 + 1,最后看哪边的数字大就是哪边获胜。
    既然记录得分,首先要给计算机一个空白的 “计分牌”, 用于存放【李逍遥】和【拜月教主】的每一局得分。

    1. # 存放李逍遥赢的局数。
    2. freeLi_score = 0
    3. # 存放拜月教主赢的局数
    4. BOSS_score = 0

    现在我们有了空白的 “计分牌” ,那么,在什么情况下得分才会 +1 呢?当然每一局比赛完成之后,我们去增加得分。

    1. if freeLi_life > 0 and BOSS_life <= 0:
    2. freeLi_score = freeLi_score + 1
    3. print('【拜月教主】挂了,【李逍遥】赢了')
    4. elif freeLi_life <= 0 and BOSS_life > 0:
    5. BOSS_score = BOSS_score + 1
    6. print('悲催,【拜月教主】把【李逍遥】干掉了!')
    7. else:
    8. print('哎呀,【李逍遥】和【拜月教主】同归于尽了!')

    接下来,我们来将【李逍遥】和【拜月教主】各自赢得局数算出来。

    1. # 导入 time 库和 random 库,也可合并写成一行:import time, random
    2. import time
    3. import random
    4. # 存放李逍遥赢的局数。
    5. freeLi_score = 0
    6. # 存放拜月教主赢的局数
    7. BOSS_score = 0
    8. for i in range(1, 4):
    9. time.sleep(1) # 让局与局之间有较明显的有时间间隔
    10. print(' \n——————现在进行第' + str(i) + '局,3,2,1,go!——————') # 作为局的标记
    11. # 生成随机属性
    12. # “freeLi_life” 代表李逍遥血量
    13. freeLi_life = random.randint(100, 150)
    14. # “freeLi_attack” 代表李逍遥攻击
    15. freeLi_attack = random.randint(20, 30)
    16. # “BOSS_life” 代表拜月教主血量
    17. BOSS_life = random.randint(100, 150)
    18. # “BOSS_attack” 代表拜月教主攻击
    19. BOSS_attack = random.randint(20, 30)
    20. # 展示双方角色的属性
    21. # freeLi_life 和 freeLi_attack 的数据类型都是整数,所以拼接时需要先用 str() 转换
    22. print('【李逍遥】 \n 血量:%s \n 攻击力:%s' % (freeLi_life, freeLi_attack))
    23. print('------------------------')
    24. # 暂停一秒再执行后续代码
    25. time.sleep(1)
    26. print('【拜月教主】 \n 血量:%s \n 攻击力:%s' % (BOSS_life, BOSS_attack))
    27. print('------------------------')
    28. # 自动 PK 阶段
    29. while (freeLi_life > 0) and (BOSS_life > 0):
    30. freeLi_life = freeLi_life - BOSS_attack
    31. BOSS_life = BOSS_life - freeLi_attack
    32. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量' + str(BOSS_life))
    33. # freeLi_life 是整数,所以拼接时要先用 str() 转换
    34. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量' + str(freeLi_life))
    35. print('------------------------')
    36. # 为了体现出战斗回合,这里停顿 2 秒
    37. time.sleep(2)
    38. # 打印结果
    39. if freeLi_life > 0 and BOSS_life <= 0:
    40. freeLi_score = freeLi_score + 1
    41. print('【拜月教主】挂了,【李逍遥】赢了')
    42. elif freeLi_life <= 0 and BOSS_life > 0:
    43. BOSS_score = BOSS_score + 1
    44. print('悲催,【拜月教主】把【李逍遥】干掉了!')
    45. else:
    46. print('哎呀,【李逍遥】和【拜月教主】同归于尽了!')

    这样三局过后,freeLi_score 和 BOSS_score 会被赋上新的值。给你一个小技巧:
    freeLi_score = freeLi_score + 1,总是这样写有点烦人,我们可以写作 freeLi_score += 1,这两个代码是等价的,都代表 “如果 if 后的条件满足,变量就 +1” 。如下:

    1. # 打印结果
    2. if freeLi_life > 0 and BOSS_life <= 0:
    3. freeLi_score += 1
    4. print('【拜月教主】挂了,【李逍遥】赢了')
    5. elif freeLi_life <= 0 and BOSS_life > 0:
    6. BOSS_score += 1
    7. print('悲催,【拜月教主】把【李逍遥】干掉了!')
    8. else:
    9. print('哎呀,【李逍遥】和【拜月教主】同归于尽了!')

    最后,再做一次判断,比较一下【李逍遥】赢得局数和【拜月教主】赢得局数。
    18.png
    看到上面分析情况,需要注意得是,因为你是最后需要判断三局两胜的结果,你就需要把最终结果的判断放在 for 循环的外面,不要缩进。

    1. # 导入 time 库和 random 库,也可合并写成一行:import time, random
    2. import time
    3. import random
    4. # 存放李逍遥赢的局数。
    5. freeLi_score = 0
    6. # 存放拜月教主赢的局数
    7. BOSS_score = 0
    8. for i in range(1, 4):
    9. time.sleep(1) # 让局与局之间有较明显的有时间间隔
    10. print(' \n——————现在进行第' + str(i) + '局,3,2,1,go!——————') # 作为局的标记
    11. # 生成随机属性
    12. # “freeLi_life” 代表李逍遥血量
    13. freeLi_life = random.randint(100, 150)
    14. # “freeLi_attack” 代表李逍遥攻击
    15. freeLi_attack = random.randint(20, 30)
    16. # “BOSS_life” 代表拜月教主血量
    17. BOSS_life = random.randint(100, 150)
    18. # “BOSS_attack” 代表拜月教主攻击
    19. BOSS_attack = random.randint(20, 30)
    20. # 展示双方角色的属性
    21. # freeLi_life 和 freeLi_attack 的数据类型都是整数,所以拼接时需要先用 str() 转换
    22. print('【李逍遥】\n 血量:%s \n 攻击力:%s' % (freeLi_life, freeLi_attack))
    23. print('------------------------')
    24. # 暂停一秒再执行后续代码
    25. time.sleep(1)
    26. print('【拜月教主】 \n 血量:%s \n 攻击力:%s' % (BOSS_life, BOSS_attack))
    27. print('------------------------')
    28. # 自动 PK 阶段
    29. while (freeLi_life > 0) and (BOSS_life > 0):
    30. freeLi_life = freeLi_life - BOSS_attack
    31. BOSS_life = BOSS_life - freeLi_attack
    32. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量' + str(BOSS_life))
    33. # freeLi_life 是整数,所以拼接时要先用 str() 转换
    34. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量' + str(freeLi_life))
    35. print('------------------------')
    36. # 为了体现出战斗回合,这里停顿 2 秒
    37. time.sleep(2)
    38. # 打印结果
    39. if freeLi_life > 0 and BOSS_life <= 0:
    40. freeLi_score = freeLi_score + 1
    41. print('【拜月教主】挂了,【李逍遥】赢了')
    42. elif freeLi_life <= 0 and BOSS_life > 0:
    43. BOSS_score = BOSS_score + 1
    44. print('悲催,【拜月教主】把【李逍遥】干掉了!')
    45. else:
    46. print('哎呀,【李逍遥】和【拜月教主】同归于尽了!')
    47. if freeLi_score > BOSS_score:
    48. time.sleep(1)
    49. print('【 大战3个回合:李逍遥赢了!】')
    50. elif BOSS_score > freeLi_score:
    51. print('【大战3个回合:李逍遥输了!】')
    52. else:
    53. print('【大战3个回合:平局!】')

    好了,项目已经做完了,但还是要追求尽善尽美。有个地方需要【格式化字符串】。
    什么叫格式化字符串?
    下面有这么两行代码,是用来展示双方角色的属性的:

    1. print('【李逍遥】' + '血量:' + str(freeLi_life) + '攻击:' + str(freeLi_attack))
    2. print('【拜月教主】' + '血量:' + str(BOSS_life) + '攻击:' + str(BOSS_attack))

    我们在用 + 拼接字符串和变量的时候,常常需要考虑变量是什么类型的数据,如果不是字符串类型,还先需要
    str() 函数转换,然后再拼接。 这里才有两个变量,就使用 【”】 开始包裹拼接,好麻烦。
    Python 为我们提供了一种不同数据类型的拼接方式,使用【格式符 %】来处理。
    19.png
    如上图,我们看到格式符 % 后面有一个字母,这个字母用来控制数据显示的类型。【%s】就是占住这个位置,将变量转换成字符串。
    那么我们项目中的代码就可以改成:

    1. print('【李逍遥】\n 血量: %s \n 攻击力:%s' % (freeLi_life, freeLi_attack))
    2. print('【拜月教主】\n 血量:%s \n 攻击力:%s' % (BOSS_life, BOSS_attack))

    看一下,是不是代码更好读了。

    1. # 导入 time 库和 random 库,也可合并写成一行:import time, random
    2. import time
    3. import random
    4. # 存放李逍遥赢的局数。
    5. freeLi_score = 0
    6. # 存放拜月教主赢的局数
    7. BOSS_score = 0
    8. for i in range(1, 4):
    9. time.sleep(1) # 让局与局之间有较明显的有时间间隔
    10. print(' \n——————现在进行第' + str(i) + '局,3,2,1,go!——————') # 作为局的标记
    11. # 生成随机属性
    12. # “freeLi_life” 代表李逍遥血量
    13. freeLi_life = random.randint(100, 150)
    14. # “freeLi_attack” 代表李逍遥攻击
    15. freeLi_attack = random.randint(20, 30)
    16. # “BOSS_life” 代表拜月教主血量
    17. BOSS_life = random.randint(100, 150)
    18. # “BOSS_attack” 代表拜月教主攻击
    19. BOSS_attack = random.randint(20, 30)
    20. # 展示双方角色的属性
    21. # freeLi_life 和 freeLi_attack 的数据类型都是整数,所以拼接时需要先用 str() 转换
    22. print('【李逍遥】 \n 血量:%s \n 攻击力:%s' % (freeLi_life, freeLi_attack))
    23. print('------------------------')
    24. # 暂停一秒再执行后续代码
    25. time.sleep(1)
    26. print('【拜月教主】\n 血量:%s \n 攻击力:%s' % (BOSS_life, BOSS_attack))
    27. print('------------------------')
    28. # 自动 PK 阶段
    29. while (freeLi_life > 0) and (BOSS_life > 0):
    30. freeLi_life = freeLi_life - BOSS_attack
    31. BOSS_life = BOSS_life - freeLi_attack
    32. print('【李逍遥】向【拜月教主】发起了攻击,【拜月教主】剩余血量' + str(BOSS_life))
    33. # freeLi_life 是整数,所以拼接时要先用 str() 转换
    34. print('【拜月教主】向【李逍遥】发起了攻击,【李逍遥】剩余血量' + str(freeLi_life))
    35. print('------------------------')
    36. # 为了体现出战斗回合,这里停顿 2 秒
    37. time.sleep(2)
    38. # 打印结果
    39. if freeLi_life > 0 and BOSS_life <= 0:
    40. freeLi_score = freeLi_score + 1
    41. print('【拜月教主】挂了,【李逍遥】赢了')
    42. elif freeLi_life <= 0 and BOSS_life > 0:
    43. BOSS_score = BOSS_score + 1
    44. print('悲催,【拜月教主】把【李逍遥】干掉了!')
    45. else:
    46. print('哎呀,【李逍遥】和【拜月教主】同归于尽了!')
    47. if freeLi_score > BOSS_score:
    48. time.sleep(1)
    49. print('【 大战3个回合:李逍遥赢了!】')
    50. elif BOSS_score > freeLi_score:
    51. print('【大战3个回合:李逍遥输了!】')
    52. else:
    53. print('【大战3个回合:平局!】')

    代码结构是不是清爽了很多~
    江湖秘籍:【%】后面的类型码用什么,取决于你希望这个【%】占住的这个位置的数据以什么类型展示出来,如果你希望它以字符串形式展示,那就写【%s】,如果你希望它以整数形式展示,那就写【%d】。

    最后再来回顾一下做项目流程:
    20.png