21点游戏python简单实现
文章目录
21点游戏python简单实现规则简述游戏流程图设计功能设计代码实现总结OOA(分析)和OOD(设计)代码部分可改进部分
规则简述
玩家共两个角色:电脑和人类,电脑是庄家
游戏开始时,先给人类和电脑每个玩家分别发两张牌作为底牌,庄家底牌只漏一张
判断双方底牌是否直接为21点,如果其中一方为21点则直接判胜利,并在总分上加一分。如果双方都是21点,那就是平局,不得分。
当初始牌面上,没有直接出现21点,人类玩家根据自己的牌面大小决定是否继续要牌。如果要牌,那就在牌堆中抽一张,然后再次判断胜负。如果人类牌面的总点数超过了21点,那就直接判输
如果人类玩家停止要牌了,并且没有因为超过21点而被判输的情况下,则电脑要牌。电脑要牌这里,可以自己设计一个规则: 5.1 比如电脑一直要牌,直到比人类玩家大才停止要牌。 5.2 根据牌堆中剩余牌的数量,计算赢的概率,然后设置一个阈值,超过阈值就要,低于就不要。 5.3 …
循环4和5的步骤
完成一轮游戏的时候,可由人类玩家决定,是否继续玩下一轮
牌堆中剩余的牌数不够玩一轮游戏的时候,游戏自动结束。
计算规则: 2. 3. 4. 5. 6. 7. 8. 9. 10分别是正常的点数,J. Q. K都是10点
A比较特殊,首先把A当做1来计算,牌面总分数如果小于21,那么再把A当做11再计算一次,如果这个时候仍然小于21,那么A就当11算,如果这个时候牌面总分数大于了21,那么A就当1算。
游戏流程图设计
功能设计
class poke
class dealer
field:
cards: 每一个荷官对应多副牌 function:
give_one_card(): 发牌
class Player
field:
name: 昵称score: 总比分points:计数器cards_in_hand->list: 手牌 function:
who_win(player): 判断未提前结束下与其他玩家的胜负now_count(): 计算当前牌数字get(*cards): 将荷官发的牌加入手牌
代码实现
import random
from sys
import exit
class Poke:
'''
Poke类用来初始化一个牌堆
'''
def __init__(self
):
self
.cards
= [[face
, suite
] for face
in "♠♥♦♣" for suite
in [1,2,3,4,5,6,7,8,9,10,'J','Q','K']]
random
.shuffle
(self
.cards
)
class Dealer:
'''
Dealer类初始化一个荷官
主要用来实现取牌和发牌的作用
'''
def __init__(self
):
self
.cards
= Poke
().cards
def give_one_card(self
):
'''
给玩家发牌
return: list
'''
if not self
.cards
:
self
.cards
.extend
(Poke
().cards
)
return self
.cards
.pop
()
class Player:
def __init__(self
, name
):
'''
初始化实例属性
'''
self
.name
= name
self
.score
= 0
self
.points
= 0
self
.cards_in_hand
= []
def init(self
):
'''
重置计数器和牌列表
'''
self
.cards_in_hand
= []
self
.points
= 0
def now_count(self
):
'''
更新计数器
'''
point
= 0
for face
, suite
in self
.cards_in_hand
:
if suite
in ['J', 'Q', 'K']:
suite
= 10
point
+= suite
for card
in self
.cards_in_hand
:
if card
[1] == 1 and point
+ 10 < 21:
self
.points
= point
+ 10
else:
self
.points
= point
def is_win(self
, player
):
'''
未提前结束回合时,判断玩家输赢
param: player 进行比较的玩家
'''
s1
= self
.points
s2
= player
.points
if s1
> s2
:
print(f
"玩家{self.name}点数为{s1}, 电脑{player.name}点数为{s2}, 玩家{self.name}赢了!")
self
.score
+= 1
elif s1
== s2
:
print(f
"玩家{self.name}点数为{s1}, 电脑{player.name}点数为{s2}, 平局!")
else:
print(f
"玩家{self.name}点数为{s1}, 电脑{player.name}点数为{s2}, 电脑{player.name}赢了!")
player
.score
+= 1
def get(self
, *cards
):
'''
玩家取荷官发的牌,并更新计数器
param: *cards 一个或多个list类型表示的牌
'''
for card
in cards
:
self
.cards_in_hand
.append
(card
)
self
.now_count
()
def main(dealer
: Dealer
, computer
: Player
, human
: Player
):
'''
游戏控制主函数
'''
count
= 0
try:
while True:
count
+= 1
print(f
"第{count}轮比赛开始:")
flag
= False
human
.init
()
computer
.init
()
human
.get
(dealer
.give_one_card
(), dealer
.give_one_card
())
computer
.get
(dealer
.give_one_card
(), dealer
.give_one_card
())
print(f
"玩家{human.name}手中的牌是{human.cards_in_hand[-2]}, {human.cards_in_hand[-1]}")
print(f
"电脑{computer.name}手中的牌是{computer.cards_in_hand[-2]}, ?")
if human
.points
== 21 == computer
.points
:
print("玩家{human.name}和电脑{computer.name}都为21点,平局!")
elif human
.points
== 21:
print("玩家{human.name}的点数为21点,恭喜玩家{human.name}赢了!")
human
.score
+= 1
else:
while True:
if_next_card
= input("是否继续要牌:(Y/N)")
if if_next_card
in ['N', 'n']:
break
elif if_next_card
in ['Y', 'y']:
human
.get
(dealer
.give_one_card
())
print(f
"玩家{human.name}得到一张{human.cards_in_hand[-1]}, 玩家{human.name}手中的牌是{human.cards_in_hand}")
if human
.points
> 21:
print(f
"玩家{human.name}的点数{human.points}超过了21点,玩家{human.name}输了!")
computer
.score
+= 1
flag
= True
break
if not flag
:
while computer
.points
< human
.points
:
computer
.get
(dealer
.give_one_card
())
print(f
"电脑{computer.name}得到一张{computer.cards_in_hand[-1]}, 电脑{computer.name}手中的牌是{computer.cards_in_hand}")
if computer
.points
> 21:
print(f
"电脑{computer.name}的点数为{computer.points}超过21点,恭喜玩家{human.name}赢了!")
human
.score
+= 1
else:
human
.is_win
(computer
)
print("-" * 30)
if_play_again
= input("是否进行下一局:(Y/N)")
if if_play_again
in ['Y', 'y']:
print(f
"玩家{human.name},电脑{computer.name}总比分为{human.score}:{computer.score}")
elif if_play_again
in ['N', 'n']:
print(f
"玩家{human.name},电脑{computer.name}总比分为{human.score}:{computer.score}")
if human
.score
> computer
.score
:
print(f
"{human.name}胜出!")
elif human
.score
< computer
.score
:
print(f
"{computer.name}胜出!")
else:
print("战况激烈,你们打平了!")
print("游戏结束")
exit
(0)
else:
print("输入有误,请重新输入:")
except Exception
:
print("有bug,游戏结束!")
if __name__
== '__main__':
computer
= Player
('Robot')
human
= Player
('Lihaoer')
dealer
= Dealer
()
main
(dealer
, computer
, human
)
总结
OOA(分析)和OOD(设计)
制作流程图时,主流程尽量保持在一个方向上,每遇到选择分支,就在垂直方向上继续分析,尽量保证各个分支的同一层次和主流程保持平行,这样的话如果有提前结束的分支,也非常清楚。流程图不要过于复杂,过于复杂的话很容易混乱也不利于再次阅读,并且不要着急去考虑方法。本例中需要抽象的类、属性和方法都不多。对于多类多方法的情况,考虑增加类图;多对象的交互行为考虑增加顺序图;而对于像本例这样的游戏属于单对象跨用例行为,可以考虑状态机图。
代码部分
python的类属性和实例属性。与Java有static静态来表示属性的归属不同,python的实例属性定义在__init()__中,类属性仍然直接表示在类中。如果实例属性需要定期重置,可能需要重新定义一个init函数。类之间的关系有至少三种,包括关联,泛化和依赖,如果类之间互相有对象的参数调用,需要先搞清楚类之间的关系,否则类方法可能有重复等不合理的地方。提前结束的代码逻辑一般是由多层并列循环的跳出来实现的,但具体实现提出设计到goto的思想,一般代码中是通过设置提前结束标志来实现。本例中至少两处需用到,一是是否重复获取输入标志,一是是否提前结束本局标志。random类和sys.exit()方法python支持多重判断a==b==c两种输出格式化字符串方法。 print(f"%format", args) print("%format".format(args))
可改进部分
改进系统输入的代码部分,抛出异常或抓获checked exception,或是直接改进bug。游戏逻辑可改进,包括电脑要牌逻辑,以及游戏规则等。类属性和方法的访问安全问题。